diff --git a/DESCRIPTION b/DESCRIPTION index 9ade5701..7c0f9c55 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -54,4 +54,4 @@ VignetteBuilder: Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 6.1.1 +RoxygenNote: 7.0.0 diff --git a/NEWS.md b/NEWS.md index 5adb8dd8..0ded3438 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,7 @@ # bcdata (development version) # bcdata 0.1.1.9999 +* Fixed a bug where `BBOX()` used in a `filter()` statement combined with `bcdc_query_geodata()` did not work (#135, #137) * Add `mutate` method for bcdc_promise that only fails and suggest an alternative approach. (PR#134) * Add back in querying vignette diff --git a/R/cql-geom-predicates.R b/R/cql-geom-predicates.R index 523e7a7e..350f3dcf 100644 --- a/R/cql-geom-predicates.R +++ b/R/cql-geom-predicates.R @@ -24,9 +24,6 @@ #' bcbdc_cql_string accepts the following geometric predicates: EQUALS, #' DISJOINT, INTERSECTS, TOUCHES, CROSSES, WITHIN, CONTAINS, OVERLAPS, RELATE, #' DWITHIN, BEYOND, BBOX. -#' @inheritParams RELATE -#' @inheritParams BBOX -#' @inheritParams DWITHIN #' #' @seealso sql_geom_predicates #' @@ -51,13 +48,8 @@ bcdc_cql_string <- function(x, geometry_predicates, pattern = NULL, call. = FALSE) } - - geom_col <- attr(x, "geom_col") - if(is.null(geom_col)) geom_col <- "GEOMETRY" - match.arg(geometry_predicates, cql_geom_predicate_list()) - # Only convert x to bbox if not using BBOX CQL function # because it doesn't take a geom if (!geometry_predicates == "BBOX") { @@ -97,8 +89,6 @@ sf_text <- function(x) { call. = FALSE) } - - ## If too big here, drawing bounding if(utils::object.size(x) > getOption("bcdata.max_geom_pred_size", 5E5)){ warning("The object is too large to perform exact spatial operations using bcdata. @@ -127,7 +117,7 @@ sf_text <- function(x) { #' #' @param geom an sf/sfc/sfg object #' @name cql_geom_predicates -#' @return a CQL expression using the bounding box of the geom +#' @return a CQL expression to be passed on to the WFS call NULL #' @rdname cql_geom_predicates @@ -194,7 +184,9 @@ RELATE <- function(geom, pattern) { } #' @rdname cql_geom_predicates -#' @param coords the coordinates of the bounding box. +#' @param coords the coordinates of the bounding box as four-element numeric +#' vector `c(xmin, ymin, xmax, ymax)`, or a `bbox` object from the `sf` +#' package (the result of running `sf::st_bbox()` on an `sf` object). #' @param crs (Optional) A string containing an SRS code #' (For example, 'EPSG:1234'. The default is to use the CRS of the queried layer) #' @export @@ -224,7 +216,6 @@ DWITHIN <- function(geom, distance, } #' @rdname cql_geom_predicates -#' @inheritParams DWITHIN #' @export BEYOND <- function(geom, distance, units = c("meters", "feet", "statute miles", "nautical miles", "kilometers")) { diff --git a/R/cql-translator.R b/R/cql-translator.R index 4130513e..421f5369 100644 --- a/R/cql-translator.R +++ b/R/cql-translator.R @@ -57,19 +57,19 @@ cql_scalar <- dbplyr::sql_translator( `[` = `[`, `[[` = `[[`, `$` = `$`, - DWITHIN = function(x) DWITHIN(x), - EQUALS = function(x) EQUALS(x), - DISJOINT = function(x) DISJOINT(x), - INTERSECTS = function(x) INTERSECTS(x), - TOUCHES = function(x) TOUCHES(x), - CROSSES = function(x) CROSSES(x), - WITHIN = function(x) WITHIN(x), - CONTAINS = function(x) CONTAINS(x), - OVERLAPS = function(x) OVERLAPS(x), - RELATE = function(x) RELATE(x), - DWITHIN = function(x) DWITHIN(x), - BEYOND = function(x) BEYOND(x), - CQL = function(x) CQL(x) + EQUALS = function(geom) EQUALS(geom), + DISJOINT = function(geom) DISJOINT(geom), + INTERSECTS = function(geom) INTERSECTS(geom), + TOUCHES = function(geom) TOUCHES(geom), + CROSSES = function(geom) CROSSES(geom), + WITHIN = function(geom) WITHIN(geom), + CONTAINS = function(geom) CONTAINS(geom), + OVERLAPS = function(geom) OVERLAPS(geom), + RELATE = function(geom, pattern) RELATE(geom, pattern), + DWITHIN = function(geom, distance, units) DWITHIN(geom, distance, units), + BEYOND = function(geom, distance, units) BEYOND(geom, distance, units), + BBOX = function(coords, crs) BBOX(coords, crs), + CQL = function(...) CQL(...) ) # No aggregation functions available in CQL diff --git a/man/bcdata-package.Rd b/man/bcdata-package.Rd index fdc6bd84..8aaf84f3 100644 --- a/man/bcdata-package.Rd +++ b/man/bcdata-package.Rd @@ -6,7 +6,7 @@ \alias{bcdata-package} \title{bcdata: Search and Retrieve Data from the BC Data Catalogue} \description{ -\if{html}{\figure{logo.png}{options: align='right'}} +\if{html}{\figure{logo.png}{options: align='right' alt='logo' width='120'}} Search, query, and download tabular and 'geospatial' data from the British Columbia Data Catalogue(). diff --git a/man/bcdc_browse.Rd b/man/bcdc_browse.Rd index 143589d0..5f6cfe6b 100644 --- a/man/bcdc_browse.Rd +++ b/man/bcdc_browse.Rd @@ -4,8 +4,11 @@ \alias{bcdc_browse} \title{Load the B.C. Data Catalogue URL into an HTML browser} \usage{ -bcdc_browse(query = NULL, browser = getOption("browser"), - encodeIfNeeded = FALSE) +bcdc_browse( + query = NULL, + browser = getOption("browser"), + encodeIfNeeded = FALSE +) } \arguments{ \item{query}{Default (NULL) opens a browser to \code{https://catalogue.data.gov.bc.ca}. @@ -23,7 +26,7 @@ bcdc_browse will search the data catalogue for that string.} } \item{encodeIfNeeded}{Should the URL be encoded by - \code{\link{URLencode}} before passing to the browser? This is not + \code{\link[utils]{URLencode}} before passing to the browser? This is not needed (and might be harmful) if the \code{browser} program/function itself does encoding, and can be harmful for \samp{file://} URLs on some systems and for \samp{http://} URLs passed to some CGI applications. diff --git a/man/bcdc_options.Rd b/man/bcdc_options.Rd index e6c5d8e2..e966fea5 100644 --- a/man/bcdc_options.Rd +++ b/man/bcdc_options.Rd @@ -8,7 +8,7 @@ bcdc_options() } \description{ This function retrieves bcdata specific options that can be set. These options can be set -using \code{option({name of the option} = {value of the option})}. The default options are purposefully +using \verb{option(\{name of the option\} = \{value of the option\})}. The default options are purposefully set conservatively to hopefully ensure successful requests. Resetting these options may result in failed calls to the data catalogue. Options in R are reset every time R is re-started. See examples for addition ways to restore your initial state. diff --git a/man/bcdc_query_geodata.Rd b/man/bcdc_query_geodata.Rd index 1f8e3a58..6f91b158 100644 --- a/man/bcdc_query_geodata.Rd +++ b/man/bcdc_query_geodata.Rd @@ -34,7 +34,7 @@ that the request will take quite a while. } \details{ Note that this function doesn't actually return the data, but rather an -object of class \code{bcdc_promise``, which includes all of the information required to retrieve the requested data. In order to get the actual data as an }sf\code{object, you need to run [collect()] on the}bcdc_promise\code{. This allows further refining the call to }bcdc_query_geodata()\code{with [filter()] and/or [select()] statements before pulling down the actual data as an}sf` +object of class \verb{bcdc_promise``, which includes all of the information required to retrieve the requested data. In order to get the actual data as an }sf\verb{object, you need to run [collect()] on the}bcdc_promise\verb{. This allows further refining the call to }bcdc_query_geodata()\verb{with [filter()] and/or [select()] statements before pulling down the actual data as an}sf` object with \code{\link[=collect]{collect()}}. See examples. } \examples{ @@ -44,18 +44,18 @@ object with \code{\link[=collect]{collect()}}. See examples. bcdc_query_geodata("bc-airports", crs = 3857) # To obtain the actual data as an sf object, collect() must be called: -bcdc_query_geodata("bc-airports", crs = 3857) \%>\% - filter(PHYSICAL_ADDRESS == 'Victoria, BC') \%>\% +bcdc_query_geodata("bc-airports", crs = 3857) %>% + filter(PHYSICAL_ADDRESS == 'Victoria, BC') %>% collect() -bcdc_query_geodata("ground-water-wells") \%>\% - filter(OBSERVATION_WELL_NUMBER == 108) \%>\% - select(WELL_TAG_NUMBER, WATERSHED_CODE) \%>\% +bcdc_query_geodata("ground-water-wells") %>% + filter(OBSERVATION_WELL_NUMBER == 108) %>% + select(WELL_TAG_NUMBER, WATERSHED_CODE) %>% collect() ## A moderately large layer bcdc_query_geodata("bc-environmental-monitoring-locations") -bcdc_query_geodata("bc-environmental-monitoring-locations") \%>\% +bcdc_query_geodata("bc-environmental-monitoring-locations") %>% filter(PERMIT_RELATIONSHIP == "DISCHARGE") diff --git a/man/bcdc_search.Rd b/man/bcdc_search.Rd index 258d0f1c..a62f623e 100644 --- a/man/bcdc_search.Rd +++ b/man/bcdc_search.Rd @@ -4,9 +4,16 @@ \alias{bcdc_search} \title{Search the B.C. Data Catalogue} \usage{ -bcdc_search(..., license_id = NULL, download_audience = "Public", - type = NULL, res_format = NULL, sector = NULL, - organization = NULL, n = 100) +bcdc_search( + ..., + license_id = NULL, + download_audience = "Public", + type = NULL, + res_format = NULL, + sector = NULL, + organization = NULL, + n = 100 +) } \arguments{ \item{...}{search terms} diff --git a/man/bcdc_search_facets.Rd b/man/bcdc_search_facets.Rd index c7d3cd2c..d60c2897 100644 --- a/man/bcdc_search_facets.Rd +++ b/man/bcdc_search_facets.Rd @@ -4,13 +4,15 @@ \alias{bcdc_search_facets} \title{Get the valid values for a facet (that you can use in \code{\link[=bcdc_search]{bcdc_search()}})} \usage{ -bcdc_search_facets(facet = c("license_id", "download_audience", "type", - "res_format", "sector", "organization")) +bcdc_search_facets( + facet = c("license_id", "download_audience", "type", "res_format", "sector", + "organization") +) } \arguments{ \item{facet}{the facet(s) for which to retrieve valid values. Can be one or more of: -\code{"license_id", "download_audience", "type", "res_format", "sector", "organization"}} +\verb{"license_id", "download_audience", "type", "res_format", "sector", "organization"}} } \value{ A data frame of values for the selected facet diff --git a/man/collect.Rd b/man/collect.Rd index ab45f0d1..093e1d22 100644 --- a/man/collect.Rd +++ b/man/collect.Rd @@ -23,7 +23,7 @@ See \code{dplyr::\link[dplyr]{collect}} for details. \examples{ \donttest{ -bcdc_query_geodata("bc-airports") \%>\% +bcdc_query_geodata("bc-airports") %>% collect() } diff --git a/man/cql_geom_predicates.Rd b/man/cql_geom_predicates.Rd index 2e84557d..6872e9e5 100644 --- a/man/cql_geom_predicates.Rd +++ b/man/cql_geom_predicates.Rd @@ -36,20 +36,28 @@ RELATE(geom, pattern) BBOX(coords, crs = NULL) -DWITHIN(geom, distance, units = c("meters", "feet", "statute miles", - "nautical miles", "kilometers")) - -BEYOND(geom, distance, units = c("meters", "feet", "statute miles", - "nautical miles", "kilometers")) +DWITHIN( + geom, + distance, + units = c("meters", "feet", "statute miles", "nautical miles", "kilometers") +) + +BEYOND( + geom, + distance, + units = c("meters", "feet", "statute miles", "nautical miles", "kilometers") +) } \arguments{ \item{geom}{an sf/sfc/sfg object} \item{pattern}{spatial relationship specified by a DE-9IM matrix pattern. A DE-9IM pattern is a string of length 9 specified using the characters -\code{*TF012}. Example: \code{'1*T***T**'}} +\verb{*TF012}. Example: \code{'1*T***T**'}} -\item{coords}{the coordinates of the bounding box.} +\item{coords}{the coordinates of the bounding box as four-element numeric +vector \code{c(xmin, ymin, xmax, ymax)}, or a \code{bbox} object from the \code{sf} +package (the result of running \code{sf::st_bbox()} on an \code{sf} object).} \item{crs}{(Optional) A string containing an SRS code (For example, 'EPSG:1234'. The default is to use the CRS of the queried layer)} @@ -60,7 +68,7 @@ A DE-9IM pattern is a string of length 9 specified using the characters \code{"feet"}, \code{"meters"}, \code{"statute miles"}, \code{"nautical miles"}, \code{"kilometers"}} } \value{ -a CQL expression using the bounding box of the geom +a CQL expression to be passed on to the WFS call } \description{ Functions to construct a CQL expression to be used diff --git a/man/filter.bcdc_promise.Rd b/man/filter.bcdc_promise.Rd index 2a227d0c..0a0f33f2 100644 --- a/man/filter.bcdc_promise.Rd +++ b/man/filter.bcdc_promise.Rd @@ -10,7 +10,7 @@ \item{.data}{object of class \code{bcdc_promise} (likely passed from \code{\link[=bcdc_query_geodata]{bcdc_query_geodata()}})} \item{...}{Logical predicates with which to filter the results. Multiple -conditions are combined with \code{&}. Only rows where the condition evaluates to +conditions are combined with \verb{&}. Only rows where the condition evaluates to \code{TRUE} are kept. Accepts normal R expressions as well as any of the special \link[=cql_geom_predicates]{CQL geometry functions} such as \code{WITHIN()} or \code{INTERSECTS()}. If you know \code{CQL} and want to write a \code{CQL} query directly, write it enclosed @@ -22,12 +22,12 @@ full sf object is not read into memory until \code{collect()} has been called. } \examples{ \donttest{ - crd <- bcdc_query_geodata("regional-districts-legally-defined-administrative-areas-of-bc") \%>\% - filter(ADMIN_AREA_NAME == "Cariboo Regional District") \%>\% + crd <- bcdc_query_geodata("regional-districts-legally-defined-administrative-areas-of-bc") %>% + filter(ADMIN_AREA_NAME == "Cariboo Regional District") %>% collect() -ret1 <- bcdc_query_geodata("fire-perimeters-historical") \%>\% - filter(FIRE_YEAR == 2000, FIRE_CAUSE == "Person", INTERSECTS(crd)) \%>\% +ret1 <- bcdc_query_geodata("fire-perimeters-historical") %>% + filter(FIRE_YEAR == 2000, FIRE_CAUSE == "Person", INTERSECTS(crd)) %>% collect() } } diff --git a/man/mutate.bcdc_promise.Rd b/man/mutate.bcdc_promise.Rd index 6f8e9e93..ed2c5ced 100644 --- a/man/mutate.bcdc_promise.Rd +++ b/man/mutate.bcdc_promise.Rd @@ -20,7 +20,7 @@ approach to use mutate with bcdata \dontrun{ ## Mutate columns -bcdc_query_geodata("bc-airports") \%>\% +bcdc_query_geodata("bc-airports") %>% mutate(LATITUDE * 100) } diff --git a/man/select.bcdc_promise.Rd b/man/select.bcdc_promise.Rd index c7a66b21..5a92ce43 100644 --- a/man/select.bcdc_promise.Rd +++ b/man/select.bcdc_promise.Rd @@ -25,11 +25,11 @@ feature_spec <- bcdc_describe_feature("bc-airports") feature_spec[feature_spec$nillable == TRUE,] ## Select columns -bcdc_query_geodata("bc-airports") \%>\% +bcdc_query_geodata("bc-airports") %>% select(DESCRIPTION, PHYSICAL_ADDRESS) ## Select "sticky" columns -bcdc_query_geodata("bc-airports") \%>\% +bcdc_query_geodata("bc-airports") %>% select(LOCALITY) } diff --git a/man/show_query.Rd b/man/show_query.Rd index 5bdab031..7662cbee 100644 --- a/man/show_query.Rd +++ b/man/show_query.Rd @@ -27,13 +27,13 @@ See \code{dplyr::\link[dplyr]{show_query}} for details. \examples{ \donttest{ -bcdc_query_geodata("bc-environmental-monitoring-locations") \%>\% - filter(PERMIT_RELATIONSHIP == "DISCHARGE") \%>\% +bcdc_query_geodata("bc-environmental-monitoring-locations") %>% + filter(PERMIT_RELATIONSHIP == "DISCHARGE") %>% show_query() } \donttest{ -air <- bcdc_query_geodata("bc-airports") \%>\% +air <- bcdc_query_geodata("bc-airports") %>% collect() show_query(air) diff --git a/tests/testthat/test-query-geodata-filter.R b/tests/testthat/test-query-geodata-filter.R index 60af254a..7f4227e6 100644 --- a/tests/testthat/test-query-geodata-filter.R +++ b/tests/testthat/test-query-geodata-filter.R @@ -228,3 +228,12 @@ test_that("a BCGW name works with filter", { collect()) expect_equal(nrow(ret), 367) }) + +test_that("Using BBOX works", { + query <- bcdc_query_geodata("WHSE_FOREST_VEGETATION.BEC_BIOGEOCLIMATIC_POLY", crs = 4326) %>% + filter(BBOX(c(1639473.0,528785.2,1665979.9,541201.0), crs = "EPSG:3005")) %>% + show_query() + expect_equal(query$query_list$CQL_FILTER, + structure("(BBOX(GEOMETRY, 1639473, 528785.2, 1665979.9, 541201, 'EPSG:3005'))", + class = c("sql", "character"))) +})