├── air.toml ├── .github ├── .gitignore ├── ISSUE_TEMPLATE │ └── issue_template.md └── workflows │ ├── pkgdown.yaml │ ├── test-coverage.yaml │ ├── R-CMD-check.yaml │ └── pr-commands.yaml ├── vignettes ├── .gitignore ├── vignette-fig-bbox-1.png ├── vignette-fig-dp_join-1.png ├── vignette-fig-plot-dpg-1.png ├── vignette-fig-air_zones-1.png ├── vignette-fig-districts-1.png ├── vignette-fig-district_parks-1.png ├── vignette-fig-unnamed-chunk-1-1.png ├── vignette-fig-unnamed-chunk-3-1.png ├── vignette-fig-regional_districts-1.png ├── vignette-fig-map-larch-plantations-dpg-1.png ├── precompile.R ├── local-filter.Rmd.orig ├── service_documentation.Rmd └── local-filter.Rmd ├── revdep ├── failures.md ├── problems.md ├── .gitignore ├── email.yml ├── cran.md └── README.md ├── man ├── figures │ └── logo.png ├── pipe.Rd ├── bcdc_list.Rd ├── wfsConnection-class.Rd ├── bcdc_read_functions.Rd ├── bcdc_list_group_records.Rd ├── CQL.Rd ├── bcdc_list_organization_records.Rd ├── bcdc_search_facets.Rd ├── collect-methods.Rd ├── mutate.Rd ├── show_query.Rd ├── bcdc_get_record.Rd ├── bcdc_preview.Rd ├── bcdc_check_geom_size.Rd ├── bcdc_tidy_resources.Rd ├── bcdc_search.Rd ├── bcdata-package.Rd ├── bcdc_get_citation.Rd ├── select.Rd ├── bcdc_describe_feature.Rd ├── bcdc_browse.Rd ├── cql_geom_predicates.Rd ├── filter.Rd ├── bcdc_options.Rd ├── bcdc_query_geodata.Rd └── bcdc_get_data.Rd ├── .gitattributes ├── inst ├── sticker │ ├── bcdata.png │ ├── bcdata_sticker_print.pdf │ └── make_sticker.R └── CITATION ├── pkgdown ├── favicon │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── apple-touch-icon.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ └── apple-touch-icon-180x180.png ├── assets │ └── bc_sans │ │ ├── BCSans-Bold.woff │ │ ├── BCSans-Italic.woff │ │ ├── BCSans-Regular.woff │ │ ├── BCSans-BoldItalic.woff │ │ └── LICENSE_OFL └── extra.css ├── .vscode ├── extensions.json └── settings.json ├── .gitignore ├── codecov.yml ├── COMPLIANCE.yaml ├── tests ├── testthat.R └── testthat │ ├── teardown.R │ ├── test-edge-cases.R │ ├── test-query-geodata-mutate.R │ ├── helper-bcdata.R │ ├── test-bcdc-get-citation.R │ ├── test-browse.R │ ├── setup.R │ ├── test-print-methods.R │ ├── test-query-geodata-base-methods.R │ ├── test-search.R │ ├── test-query-geodata.R │ ├── test-options.R │ ├── test-query-geodata-select.R │ ├── test-utils.R │ ├── test-describe-feature.R │ ├── test-cql-string.R │ ├── test-query-geodata-collect.R │ ├── test-geom-operators.R │ ├── test-get_record.R │ └── test-get-data.R ├── .Rbuildignore ├── bcdata.Rproj ├── cran-comments.md ├── scratch ├── scratch.R ├── scratch_test_iterating.R ├── scratch_dem.R └── multipoint.R ├── R ├── cli.R ├── utils-pipe.R ├── utils-filter.R ├── utils-mutate.R ├── utils-select.R ├── utils-collect.R ├── utils-as_tibble.R ├── utils-show-query.R ├── bcdata-package.R ├── zzz.R ├── utils-is.R ├── bcdc_browse.R ├── bcdc-get-citation.R ├── describe-feature.R ├── cql-translator.R └── bcdc_options.R ├── CONTRIBUTING.md ├── _pkgdown.yml ├── CODE_OF_CONDUCT.md ├── DESCRIPTION ├── NAMESPACE ├── README.Rmd └── README.md /air.toml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /revdep/failures.md: -------------------------------------------------------------------------------- 1 | *Wow, no problems at all. :)* -------------------------------------------------------------------------------- /revdep/problems.md: -------------------------------------------------------------------------------- 1 | *Wow, no problems at all. :)* -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/man/figures/logo.png -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-vendored 2 | *.R linguist-vendored=false 3 | *.R linguist-language=R 4 | -------------------------------------------------------------------------------- /inst/sticker/bcdata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/inst/sticker/bcdata.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "Posit.air-vscode" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | inst/doc 2 | .Rproj.user 3 | .Rhistory 4 | .RData 5 | .Ruserdata 6 | .DS_Store 7 | /docs 8 | /tmp 9 | -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /vignettes/vignette-fig-bbox-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/vignettes/vignette-fig-bbox-1.png -------------------------------------------------------------------------------- /inst/sticker/bcdata_sticker_print.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/inst/sticker/bcdata_sticker_print.pdf -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /vignettes/vignette-fig-dp_join-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/vignettes/vignette-fig-dp_join-1.png -------------------------------------------------------------------------------- /vignettes/vignette-fig-plot-dpg-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/vignettes/vignette-fig-plot-dpg-1.png -------------------------------------------------------------------------------- /pkgdown/assets/bc_sans/BCSans-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/pkgdown/assets/bc_sans/BCSans-Bold.woff -------------------------------------------------------------------------------- /revdep/.gitignore: -------------------------------------------------------------------------------- 1 | checks 2 | library 3 | checks.noindex 4 | library.noindex 5 | cloud.noindex 6 | data.sqlite 7 | *.html 8 | -------------------------------------------------------------------------------- /vignettes/vignette-fig-air_zones-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/vignettes/vignette-fig-air_zones-1.png -------------------------------------------------------------------------------- /vignettes/vignette-fig-districts-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/vignettes/vignette-fig-districts-1.png -------------------------------------------------------------------------------- /pkgdown/assets/bc_sans/BCSans-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/pkgdown/assets/bc_sans/BCSans-Italic.woff -------------------------------------------------------------------------------- /pkgdown/assets/bc_sans/BCSans-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/pkgdown/assets/bc_sans/BCSans-Regular.woff -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/assets/bc_sans/BCSans-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/pkgdown/assets/bc_sans/BCSans-BoldItalic.woff -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/pkgdown/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/pkgdown/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /revdep/email.yml: -------------------------------------------------------------------------------- 1 | release_date: ??? 2 | rel_release_date: ??? 3 | my_news_url: ??? 4 | release_version: ??? 5 | release_details: ??? 6 | -------------------------------------------------------------------------------- /vignettes/vignette-fig-district_parks-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/vignettes/vignette-fig-district_parks-1.png -------------------------------------------------------------------------------- /vignettes/vignette-fig-unnamed-chunk-1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/vignettes/vignette-fig-unnamed-chunk-1-1.png -------------------------------------------------------------------------------- /vignettes/vignette-fig-unnamed-chunk-3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/vignettes/vignette-fig-unnamed-chunk-3-1.png -------------------------------------------------------------------------------- /vignettes/vignette-fig-regional_districts-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/vignettes/vignette-fig-regional_districts-1.png -------------------------------------------------------------------------------- /vignettes/vignette-fig-map-larch-plantations-dpg-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bcdata/HEAD/vignettes/vignette-fig-map-larch-plantations-dpg-1.png -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[r]": { 3 | "editor.formatOnSave": true, 4 | "editor.defaultFormatter": "Posit.air-vscode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /revdep/cran.md: -------------------------------------------------------------------------------- 1 | ## revdepcheck results 2 | 3 | We checked 1 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. 4 | 5 | * We saw 0 new problems 6 | * We failed to check 0 packages 7 | 8 | -------------------------------------------------------------------------------- /man/pipe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-pipe.R 3 | \name{\%>\%} 4 | \alias{\%>\%} 5 | \title{Pipe operator} 6 | \usage{ 7 | lhs \%>\% rhs 8 | } 9 | \description{ 10 | Pipe operator 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | informational: true 10 | patch: 11 | default: 12 | target: auto 13 | threshold: 1% 14 | informational: true 15 | -------------------------------------------------------------------------------- /COMPLIANCE.yaml: -------------------------------------------------------------------------------- 1 | name: compliance 2 | description: | 3 | This document is used to track a projects PIA and STRA 4 | compliance. 5 | spec: 6 | - name: PIA 7 | status: not-required 8 | last-updated: '2020-04-15T00:14:55.870Z' 9 | - name: STRA 10 | status: not-required 11 | last-updated: '2020-04-15T00:14:55.870Z' 12 | -------------------------------------------------------------------------------- /inst/CITATION: -------------------------------------------------------------------------------- 1 | bibentry( 2 | "Article", 3 | doi = "10.21105/joss.02927", 4 | year = 2021, 5 | publisher = "The Open Journal", 6 | volume = 6, 7 | number = 61, 8 | pages = 2927, 9 | author = "Andrew C. Teucher and Sam J. Albers and Stephanie L. Hazlitt", 10 | title = "bcdata: An R package for searching and retrieving data from the B.C. Data Catalogue", 11 | journal = "Journal of Open Source Software" 12 | ) 13 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | # This file is part of the standard setup for testthat. 2 | # It is recommended that you do not modify it. 3 | # 4 | # Where should you do additional test configuration? 5 | # Learn more about the roles of various files in: 6 | # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview 7 | # * https://testthat.r-lib.org/articles/special-files.html 8 | 9 | library(testthat) 10 | library(bcdata) 11 | 12 | test_check("bcdata") 13 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^\.travis\.yml$ 2 | ^scratch$ 3 | ^CODE_OF_CONDUCT\.md$ 4 | ^CONTRIBUTING\.md$ 5 | ^README\.Rmd$ 6 | ^bcdata\.Rproj$ 7 | ^\.Rproj\.user$ 8 | ^inst/sticker$ 9 | 10 | ^_pkgdown\.yml$ 11 | ^docs$ 12 | ^pkgdown$ 13 | ^precompile.R$ 14 | ^codecov\.yml$ 15 | ^cran-comments\.md$ 16 | ^CRAN-RELEASE$ 17 | ^LICENSE.md$ 18 | ^\.github$ 19 | ^COMPLIANCE.yaml$ 20 | ^\.github/workflows/pr-commands\.yaml$ 21 | ^depends\.Rds$ 22 | ^revdep$ 23 | ^CRAN-SUBMISSION$ 24 | ^[\.]?air\.toml$ 25 | ^\.vscode$ 26 | -------------------------------------------------------------------------------- /man/bcdc_list.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bcdc_search.R 3 | \name{bcdc_list} 4 | \alias{bcdc_list} 5 | \title{Return a full list of the names of B.C. Data Catalogue records} 6 | \usage{ 7 | bcdc_list() 8 | } 9 | \value{ 10 | A character vector of the names of B.C. Data Catalogue records 11 | } 12 | \description{ 13 | Return a full list of the names of B.C. Data Catalogue records 14 | } 15 | \examples{ 16 | \donttest{ 17 | try( 18 | bcdc_list() 19 | ) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /bcdata.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | ProjectId: eaf93104-2d1c-45fb-bc62-d9d0a06f4907 3 | 4 | RestoreWorkspace: No 5 | SaveWorkspace: No 6 | AlwaysSaveHistory: Default 7 | 8 | EnableCodeIndexing: Yes 9 | UseSpacesForTab: Yes 10 | NumSpacesForTab: 2 11 | Encoding: UTF-8 12 | 13 | RnwWeave: Sweave 14 | LaTeX: pdfLaTeX 15 | 16 | AutoAppendNewline: Yes 17 | StripTrailingWhitespace: Yes 18 | 19 | BuildType: Package 20 | PackageUseDevtools: Yes 21 | PackageInstallArgs: --no-multiarch --with-keep.source 22 | PackageRoxygenize: rd,collate,namespace 23 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Release summary 2 | 3 | This release is primarily to fix new ERRORs on R-devel 4 | () where we 5 | were inadvertently setting attributes on a primitive function. 6 | 7 | ## R CMD check results 8 | 9 | There were no ERRORs, WARNINGs, or NOTEs. 10 | 11 | ## revdepcheck results 12 | 13 | We checked 1 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. 14 | 15 | * We saw 0 new problems 16 | * We failed to check 0 packages 17 | -------------------------------------------------------------------------------- /man/wfsConnection-class.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cql-translator.R 3 | \docType{class} 4 | \name{wfsConnection-class} 5 | \alias{wfsConnection-class} 6 | \alias{dbQuoteIdentifier,wfsConnection,CQL-method} 7 | \alias{dbQuoteString,wfsConnection,CQL-method} 8 | \title{wfsConnection class} 9 | \usage{ 10 | \S4method{dbQuoteIdentifier}{wfsConnection,CQL}(conn, x) 11 | 12 | \S4method{dbQuoteString}{wfsConnection,CQL}(conn, x) 13 | } 14 | \description{ 15 | wfsConnection class 16 | } 17 | \keyword{internal} 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report or feature request 3 | about: Describe a bug you've seen or make a case for a new feature 4 | --- 5 | 6 | Please briefly describe your problem and what output you expect. Please include a link to the B.C. data catalogue record that you are trying to access if applicable. 7 | 8 | Please include a minimal reproducible example (AKA a reprex). If you've never heard of a [reprex](http://reprex.tidyverse.org/) before, start by reading . 9 | 10 | Brief description of the problem 11 | 12 | ```r 13 | # insert reprex here 14 | ``` 15 | -------------------------------------------------------------------------------- /man/bcdc_read_functions.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/get_data.R 3 | \name{bcdc_read_functions} 4 | \alias{bcdc_read_functions} 5 | \title{Formats supported and loading functions} 6 | \usage{ 7 | bcdc_read_functions() 8 | } 9 | \description{ 10 | Provides a tibble of formats supported by bcdata and the associated function that 11 | reads that data into R. This function is meant as a resource to determine which parameters 12 | can be passed through the \code{bcdc_get_data} function to the reading function. This is 13 | particularly important to know if the data requires using arguments from the read in function. 14 | } 15 | -------------------------------------------------------------------------------- /tests/testthat/teardown.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | options(original_options) 14 | -------------------------------------------------------------------------------- /scratch/scratch.R: -------------------------------------------------------------------------------- 1 | foo <- bcdc_search("forest", res_format = "wms") 2 | 3 | bcdc_search_facets("type") 4 | bcdc_search_facets("license_id") 5 | 6 | bcdc_list() 7 | 8 | bcdc_get_record("freshwater-atlas-named-point-features") 9 | 10 | bar <- bcdc_map("bc-airports") 11 | 12 | bar <- bcdc_map("freshwater-atlas-named-point-features") 13 | rd <- bcdc_map("tantalis-regional-districts") 14 | 15 | hyd <- bcdc_map("hydrology-hydrometric-watershed-boundaries") 16 | 17 | obs_wells <- bcdc_map( 18 | "ground-water-wells", 19 | query = "OBSERVATION_WELL_NUMBER IS NOT NULL" 20 | ) 21 | obs_wells <- bcdc_map( 22 | "ground-water-wells", 23 | query = "OBSERVATION_WELL_NUMBER=108" 24 | ) 25 | -------------------------------------------------------------------------------- /pkgdown/extra.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | src: url('bc_sans/BCSans-Regular.woff') format('woff'); 3 | font-weight: 400; 4 | font-style: normal; 5 | font-family: 'BCSans'; 6 | } 7 | @font-face { 8 | src: url('bc_sans/BCSans-Bold.woff') format('woff'); 9 | font-weight: 700; 10 | font-style: italic; 11 | font-family: 'BCSans'; 12 | } 13 | @font-face { 14 | src: url('bc_sans/BCSans-Italic.woff') format('woff'); 15 | font-weight: 400; 16 | font-style: italic; 17 | font-family: 'BCSans'; 18 | } 19 | @font-face { 20 | src: url('bc_sans/BCSans-Bold.woff') format('woff'); 21 | font-weight: 700; 22 | font-style: normal; 23 | font-family: 'BCSans'; 24 | } 25 | -------------------------------------------------------------------------------- /R/cli.R: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | bold_blue <- function(...) { 14 | cli::col_blue(cli::style_bold(...)) 15 | } 16 | 17 | bold_red <- function(...) { 18 | cli::col_red(cli::style_bold(...)) 19 | } 20 | -------------------------------------------------------------------------------- /tests/testthat/test-edge-cases.R: -------------------------------------------------------------------------------- 1 | test_that("recods with wms but inconsistent layer_name, object_name fields work", { 2 | skip_if_net_down() 3 | skip_on_cran() 4 | # https://github.com/bcgov/bcdata/issues/138 5 | # layer_name = RSLT_PLANTING_ALL_RSLT_CF 6 | # object_name = WHSE_FOREST_VEGETATION.RSLT_PLANTING_SVW 7 | # wms uses object_name 8 | expect_s3_class(bcdc_query_geodata("results-planting"), "bcdc_promise") 9 | 10 | # https://github.com/bcgov/bcdata/issues/129 11 | # layer_name = WHSE_ADMIN_BOUNDARIES.ADM_NR_DISTRICTS_SPG 12 | # wms uses layer_name (generalized) 13 | expect_message( 14 | expect_s3_class( 15 | bcdc_query_geodata("natural-resource-nr-district"), 16 | "bcdc_promise" 17 | ), 18 | "You are accessing a simplified view of the data" 19 | ) 20 | }) 21 | -------------------------------------------------------------------------------- /R/utils-pipe.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | #' Pipe operator 14 | #' 15 | #' 16 | #' @name %>% 17 | #' @rdname pipe 18 | #' @keywords internal 19 | #' @export 20 | #' @importFrom dplyr %>% 21 | #' @usage lhs \%>\% rhs 22 | NULL 23 | -------------------------------------------------------------------------------- /man/bcdc_list_group_records.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bcdc_search.R 3 | \name{bcdc_list_groups} 4 | \alias{bcdc_list_groups} 5 | \alias{bcdc_list_group_records} 6 | \title{Retrieve group information for B.C. Data Catalogue} 7 | \usage{ 8 | bcdc_list_groups() 9 | 10 | bcdc_list_group_records(group) 11 | } 12 | \arguments{ 13 | \item{group}{Name of the group} 14 | } 15 | \description{ 16 | Returns a tibble of groups or records. Groups can be viewed here: 17 | https://catalogue.data.gov.bc.ca/group or accessed directly from R using \code{bcdc_list_groups} 18 | } 19 | \section{Functions}{ 20 | \itemize{ 21 | \item \code{bcdc_list_groups()}: 22 | 23 | }} 24 | \examples{ 25 | \donttest{ 26 | try( 27 | bcdc_list_group_records('environmental-reporting-bc') 28 | ) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /man/CQL.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cql-geom-predicates.R, R/cql-translator.R 3 | \docType{class} 4 | \name{CQL} 5 | \alias{CQL} 6 | \alias{CQL-class} 7 | \title{CQL escaping} 8 | \usage{ 9 | CQL(...) 10 | } 11 | \arguments{ 12 | \item{...}{Character vectors that will be combined into a single CQL statement.} 13 | } 14 | \value{ 15 | An object of class \code{c("CQL", "SQL")} 16 | } 17 | \description{ 18 | Write a CQL expression to escape its inputs, and return a CQL/SQL object. 19 | Used when writing filter expressions in \code{\link[=bcdc_query_geodata]{bcdc_query_geodata()}}. 20 | } 21 | \details{ 22 | See \href{https://docs.geoserver.org/stable/en/user/tutorials/cql/cql_tutorial.html}{the CQL/ECQL for Geoserver website}. 23 | } 24 | \examples{ 25 | CQL("FOO > 12 & NAME LIKE 'A&'") 26 | } 27 | -------------------------------------------------------------------------------- /R/utils-filter.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | #' filter 14 | #' 15 | #' See \code{dplyr::\link[dplyr]{filter}} for details. 16 | #' 17 | #' @name filter 18 | #' @rdname filter 19 | #' @keywords internal 20 | #' @export 21 | #' @importFrom dplyr filter 22 | NULL 23 | -------------------------------------------------------------------------------- /R/utils-mutate.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | #' select 14 | #' 15 | #' See \code{dplyr::\link[dplyr]{mutate}} for details. 16 | #' 17 | #' @name mutate 18 | #' @rdname mutate 19 | #' @keywords internal 20 | #' @export 21 | #' @importFrom dplyr mutate 22 | NULL 23 | -------------------------------------------------------------------------------- /R/utils-select.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | #' select 14 | #' 15 | #' See \code{dplyr::\link[dplyr]{select}} for details. 16 | #' 17 | #' @name select 18 | #' @rdname select 19 | #' @keywords internal 20 | #' @export 21 | #' @importFrom dplyr select 22 | NULL 23 | -------------------------------------------------------------------------------- /scratch/scratch_test_iterating.R: -------------------------------------------------------------------------------- 1 | for (nme in c("mean", "median", "max", "min")) { 2 | fun <- match.fun(nme) 3 | expect_false(is.numeric(fun(runif(10))), label = nme) 4 | } 5 | 6 | 7 | single_arg_functions <- c( 8 | "EQUALS", 9 | "DISJOINT", 10 | "INTERSECTS", 11 | "TOUCHES", 12 | "CROSSES", 13 | "WITHIN", 14 | "CONTAINS", 15 | "OVERLAPS" 16 | ) 17 | 18 | for (nme in single_arg_functions[6]) { 19 | fun <- match.fun(nme) 20 | 21 | local <- bcdc_query_geodata( 22 | "regional-districts-legally-defined-administrative-areas-of-bc" 23 | ) %>% 24 | filter(ADMIN_AREA_NAME == "Cariboo Regional District") %>% 25 | collect() 26 | 27 | remote <- bcdc_query_geodata("bc-airports") %>% 28 | filter(fun(local)) %>% 29 | collect() 30 | 31 | expect_s3_class(remote, "sf") 32 | expect_equal(attr(remote, "sf_column"), "geometry") 33 | } 34 | -------------------------------------------------------------------------------- /R/utils-collect.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | #' Collect 14 | #' 15 | #' See \code{dplyr::\link[dplyr:compute]{collect}} for details. 16 | #' 17 | #' @name collect 18 | #' @rdname collect-methods 19 | #' @keywords internal 20 | #' @export 21 | #' @importFrom dplyr collect 22 | NULL 23 | -------------------------------------------------------------------------------- /R/utils-as_tibble.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | #' as_tibble 14 | #' 15 | #' See \code{tibble::\link[tibble]{as_tibble}} for details. 16 | #' 17 | #' @name as_tibble 18 | #' @rdname collect-methods 19 | #' @keywords internal 20 | #' @export 21 | #' @importFrom tibble as_tibble 22 | NULL 23 | -------------------------------------------------------------------------------- /R/utils-show-query.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | #' filter 14 | #' 15 | #' See \code{dplyr::\link[dplyr:explain]{show_query}} for details. 16 | #' 17 | #' @name show_query 18 | #' @rdname show_query 19 | #' @keywords internal 20 | #' @export 21 | #' @importFrom dplyr show_query 22 | NULL 23 | -------------------------------------------------------------------------------- /tests/testthat/test-query-geodata-mutate.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | test_that("mutate fails on a bcdata promise object", { 14 | skip_on_cran() 15 | skip_if_net_down() 16 | expect_error( 17 | bcdc_query_geodata("bc-airports") %>% 18 | select(LATITUDE) %>% 19 | mutate(LATITUDE * 100) 20 | ) 21 | }) 22 | -------------------------------------------------------------------------------- /man/bcdc_list_organization_records.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bcdc_search.R 3 | \name{bcdc_list_organizations} 4 | \alias{bcdc_list_organizations} 5 | \alias{bcdc_list_organization_records} 6 | \title{Retrieve organization information for B.C. Data Catalogue} 7 | \usage{ 8 | bcdc_list_organizations() 9 | 10 | bcdc_list_organization_records(organization) 11 | } 12 | \arguments{ 13 | \item{organization}{Name of the organization} 14 | } 15 | \description{ 16 | Returns a tibble of organizations or records. Organizations can be viewed here: 17 | https://catalogue.data.gov.bc.ca/organizations or accessed directly from R using \code{bcdc_list_organizations} 18 | } 19 | \section{Functions}{ 20 | \itemize{ 21 | \item \code{bcdc_list_organizations()}: 22 | 23 | }} 24 | \examples{ 25 | \donttest{ 26 | try( 27 | bcdc_list_organization_records('bc-stats') 28 | ) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to contribute 2 | Government employees, public and members of the private sector are encouraged to contribute to the repository by **forking and submitting a pull request**. 3 | 4 | (If you are new to GitHub, you might start with a [basic tutorial](https://help.github.com/articles/set-up-git) and check out a more detailed guide to [pull requests](https://help.github.com/articles/using-pull-requests/).) 5 | 6 | Pull requests will be evaluated by the repository guardians on a schedule and if deemed beneficial will be committed to the master. 7 | 8 | All contributors retain the original copyright to their stuff, but by contributing to this project, you grant a world-wide, royalty-free, perpetual, irrevocable, non-exclusive, transferable license to all users **under the terms of the license under which this project is distributed.** 9 | 10 | --- 11 | *This project was created using the [bcgovr](https://github.com/bcgov/bcgovr) package.* 12 | -------------------------------------------------------------------------------- /R/bcdata-package.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | #' @keywords internal 14 | #' 15 | "_PACKAGE" 16 | 17 | #' @importFrom cli cat_rule cat_line cat_bullet col_blue col_red col_green 18 | #' @importFrom methods setOldClass 19 | NULL 20 | 21 | release_bullets <- function() { 22 | c( 23 | "Run test and check with internet turned off", 24 | "Precompile vignettes" 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /tests/testthat/helper-bcdata.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | skip_if_net_down <- function() { 14 | if (has_internet()) { 15 | return() 16 | } 17 | testthat::skip("no internet") 18 | } 19 | 20 | skip_if_no_capabilities <- function() { 21 | if (!is.null(bcdc_get_capabilities())) { 22 | return() 23 | } 24 | testthat::skip("GetCapabilities request is broken") 25 | } 26 | -------------------------------------------------------------------------------- /man/bcdc_search_facets.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bcdc_search.R 3 | \name{bcdc_search_facets} 4 | \alias{bcdc_search_facets} 5 | \title{Get the valid values for a facet (that you can use in \code{\link[=bcdc_search]{bcdc_search()}})} 6 | \usage{ 7 | bcdc_search_facets( 8 | facet = c("license_id", "download_audience", "res_format", "publish_state", 9 | "organization", "groups") 10 | ) 11 | } 12 | \arguments{ 13 | \item{facet}{the facet(s) for which to retrieve valid values. Can be one or 14 | more of: 15 | \verb{"license_id", "download_audience", "res_format", "publish_state", "organization", "groups"}} 16 | } 17 | \value{ 18 | A data frame of values for the selected facet 19 | } 20 | \description{ 21 | Get the valid values for a facet (that you can use in \code{\link[=bcdc_search]{bcdc_search()}}) 22 | } 23 | \examples{ 24 | \donttest{ 25 | try( 26 | bcdc_search_facets("download_audience") 27 | ) 28 | 29 | try( 30 | bcdc_search_facets("res_format") 31 | ) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | ._bcdataenv_ <- new.env(parent = emptyenv()) 14 | 15 | .onLoad <- function(...) { 16 | ._bcdataenv_$named_get_record_warned <- FALSE # nocov 17 | ._bcdataenv_$get_capabilities_xml <- NULL # nocov 18 | ._bcdataenv_$single_download_limit_warned <- FALSE # nocov 19 | } 20 | 21 | # Define bcdc_sf as a subclass of sf so that it works 22 | # with S4 methods for sf (eg mapview) 23 | methods::setOldClass(c("bcdc_sf", "sf")) 24 | -------------------------------------------------------------------------------- /R/utils-is.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | is_filetype <- function(x, ext) { 14 | tools::file_ext(x) %in% ext 15 | } 16 | 17 | is_emptyish <- function(x) { 18 | length(x) == 0 || !nzchar(x) 19 | } 20 | 21 | 22 | is_whse_object_name <- function(x) { 23 | ## detect object is a record and then just return FALSE 24 | if (inherits(x, "bcdc_record")) { 25 | return(FALSE) 26 | } 27 | 28 | grepl("^[0-9A-Z_]+\\.[0-9A-Z_]+$", x) 29 | } 30 | 31 | is_record <- function(x) { 32 | class(x) == "bcdc_record" 33 | } 34 | -------------------------------------------------------------------------------- /tests/testthat/test-bcdc-get-citation.R: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | test_that("bcdc_get_citation take a character and returns a bibentry", { 14 | skip_if_net_down() 15 | skip_on_cran() 16 | rec <- bcdc_get_record(point_record) 17 | expect_s3_class(bcdc_get_citation(rec), c("citation", "bibentry")) 18 | expect_s3_class(bcdc_get_citation(point_record), c("citation", "bibentry")) 19 | test_url <- glue::glue("{catalogue_base_url()}/dataset/{point_record}") 20 | expect_s3_class(bcdc_get_citation(test_url), c("citation", "bibentry")) 21 | }) 22 | -------------------------------------------------------------------------------- /tests/testthat/test-browse.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | test_that("bcdc_browse returns the correct url", { 14 | skip_if_net_down() 15 | skip_on_cran() 16 | airports_url <- bcdc_browse("bc-airports") 17 | expect_identical( 18 | airports_url, 19 | paste0(catalogue_base_url(), "dataset/bc-airports") 20 | ) 21 | catalogue_url <- bcdc_browse() 22 | expect_identical(catalogue_url, catalogue_base_url()) 23 | expect_error( 24 | bcdc_browse("no-record-here"), 25 | "The specified record does not exist in the catalogue" 26 | ) 27 | }) 28 | -------------------------------------------------------------------------------- /man/collect-methods.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-as_tibble.R, R/utils-classes.R, 3 | % R/utils-collect.R 4 | \name{as_tibble} 5 | \alias{as_tibble} 6 | \alias{collect.bcdc_promise} 7 | \alias{as_tibble.bcdc_promise} 8 | \alias{collect} 9 | \title{as_tibble} 10 | \usage{ 11 | \method{collect}{bcdc_promise}(x, ...) 12 | 13 | \method{as_tibble}{bcdc_promise}(x, ...) 14 | } 15 | \arguments{ 16 | \item{x}{object of class \code{bcdc_promise}} 17 | } 18 | \description{ 19 | See \code{tibble::\link[tibble]{as_tibble}} for details. 20 | 21 | After tuning a query, \code{collect()} is used to actually bring the data into memory. 22 | This will retrieve an sf object into R. The \code{as_tibble()} function can be used 23 | interchangeably with \code{collect} which matches \code{dbplyr} behaviour. 24 | 25 | See \code{dplyr::\link[dplyr:compute]{collect}} for details. 26 | } 27 | \examples{ 28 | \donttest{ 29 | try( 30 | bcdc_query_geodata("bc-airports") \%>\% 31 | collect() 32 | ) 33 | 34 | try( 35 | bcdc_query_geodata("bc-airports") \%>\% 36 | as_tibble() 37 | ) 38 | } 39 | 40 | } 41 | \keyword{internal} 42 | -------------------------------------------------------------------------------- /man/mutate.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-classes.R, R/utils-mutate.R 3 | \name{mutate.bcdc_promise} 4 | \alias{mutate.bcdc_promise} 5 | \alias{mutate} 6 | \title{Throw an informative error when attempting mutate on a \code{bcdc_promise} object} 7 | \usage{ 8 | \method{mutate}{bcdc_promise}(.data, ...) 9 | } 10 | \arguments{ 11 | \item{.data}{object of class \code{bcdc_promise} (likely passed from \code{\link[=bcdc_query_geodata]{bcdc_query_geodata()}})} 12 | 13 | \item{...}{One or more unquoted expressions separated by commas. See details.} 14 | } 15 | \description{ 16 | The CQL syntax to generate WFS calls does not current allow arithmetic operations. Therefore 17 | this function exists solely to generate an informative error that suggests an alternative 18 | approach to use mutate with bcdata 19 | 20 | See \code{dplyr::\link[dplyr]{mutate}} for details. 21 | } 22 | \section{Methods (by class)}{ 23 | \itemize{ 24 | \item \code{mutate(bcdc_promise)}: mutate.bcdc_promise 25 | 26 | }} 27 | \examples{ 28 | \donttest{ 29 | 30 | ## Mutate columns 31 | try( 32 | res <- bcdc_query_geodata("bc-airports") \%>\% 33 | mutate(LATITUDE * 100) 34 | ) 35 | } 36 | 37 | } 38 | \keyword{internal} 39 | -------------------------------------------------------------------------------- /man/show_query.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-classes.R, R/utils-show-query.R 3 | \name{show_query.bcdc_promise} 4 | \alias{show_query.bcdc_promise} 5 | \alias{show_query.bcdc_sf} 6 | \alias{show_query} 7 | \title{Show SQL and URL used for Web Feature Service request from B.C. Data Catalogue} 8 | \usage{ 9 | \method{show_query}{bcdc_promise}(x, ...) 10 | 11 | \method{show_query}{bcdc_sf}(x, ...) 12 | } 13 | \arguments{ 14 | \item{x}{object of class bcdc_promise or bcdc_sf} 15 | } 16 | \description{ 17 | Display Web Feature Service query CQL 18 | 19 | See \code{dplyr::\link[dplyr:explain]{show_query}} for details. 20 | } 21 | \section{Methods (by class)}{ 22 | \itemize{ 23 | \item \code{show_query(bcdc_promise)}: show_query.bcdc_promise 24 | 25 | \item \code{show_query(bcdc_sf)}: show_query.bcdc_promise 26 | 27 | }} 28 | \examples{ 29 | \donttest{ 30 | try( 31 | bcdc_query_geodata("bc-environmental-monitoring-locations") \%>\% 32 | filter(PERMIT_RELATIONSHIP == "DISCHARGE") \%>\% 33 | show_query() 34 | ) 35 | } 36 | 37 | \donttest{ 38 | try( 39 | air <- bcdc_query_geodata("bc-airports") \%>\% 40 | collect() 41 | ) 42 | 43 | try( 44 | show_query(air) 45 | ) 46 | } 47 | } 48 | \keyword{internal} 49 | -------------------------------------------------------------------------------- /man/bcdc_get_record.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bcdc_search.R 3 | \name{bcdc_get_record} 4 | \alias{bcdc_get_record} 5 | \title{Show a single B.C. Data Catalogue record} 6 | \usage{ 7 | bcdc_get_record(id) 8 | } 9 | \arguments{ 10 | \item{id}{the human-readable name, permalink ID, or 11 | URL of the record. 12 | 13 | It is advised to use the permanent ID for a record rather than the 14 | human-readable name to guard against future name changes of the record. 15 | If you use the human-readable name a warning will be issued once per 16 | session. You can silence these warnings altogether by setting an option: 17 | \code{options("silence_named_get_record_warning" = TRUE)} - which you can put 18 | in your .Rprofile file so the option persists across sessions.} 19 | } 20 | \value{ 21 | A list containing the metadata for the record 22 | } 23 | \description{ 24 | Show a single B.C. Data Catalogue record 25 | } 26 | \examples{ 27 | \donttest{ 28 | try( 29 | bcdc_get_record("https://catalogue.data.gov.bc.ca/dataset/bc-airports") 30 | ) 31 | 32 | try( 33 | bcdc_get_record("bc-airports") 34 | ) 35 | 36 | try( 37 | bcdc_get_record("https://catalogue.data.gov.bc.ca/dataset/76b1b7a3-2112-4444-857a-afccf7b20da8") 38 | ) 39 | 40 | try( 41 | bcdc_get_record("76b1b7a3-2112-4444-857a-afccf7b20da8") 42 | ) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | release: 9 | types: [published] 10 | workflow_dispatch: 11 | 12 | name: pkgdown 13 | 14 | jobs: 15 | pkgdown: 16 | runs-on: ubuntu-latest 17 | # Only restrict concurrency for non-PR jobs 18 | concurrency: 19 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 20 | env: 21 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - uses: r-lib/actions/setup-pandoc@v2 26 | 27 | - uses: r-lib/actions/setup-r@v2 28 | with: 29 | use-public-rspm: true 30 | 31 | - uses: r-lib/actions/setup-r-dependencies@v2 32 | with: 33 | extra-packages: any::pkgdown, local::. 34 | needs: website 35 | 36 | - name: Build site 37 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 38 | shell: Rscript {0} 39 | 40 | - name: Deploy to GitHub pages 🚀 41 | if: github.event_name != 'pull_request' 42 | uses: JamesIves/github-pages-deploy-action@v4.4.1 43 | with: 44 | clean: false 45 | branch: gh-pages 46 | folder: docs 47 | -------------------------------------------------------------------------------- /scratch/scratch_dem.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | bcdc_get_dem <- function(bbox) { 14 | if (inherits(bbox, "bbox")) { 15 | bbox <- paste(bbox, collapse = ",") 16 | } 17 | 18 | query_list <- list( 19 | service = "WCS", 20 | version = "1.0.0", 21 | request = "GetCoverage", 22 | coverage = "pub:bc_elevation_25m_bcalb", 23 | bbox = bbox, 24 | CRS = "EPSG:3005", 25 | RESPONSE_CRS = "EPSG:3005", 26 | Format = "GeoTIFF", 27 | resx = 25, 28 | resy = 25 29 | ) 30 | 31 | ## Drop any NULLS from the list 32 | query_list <- compact(query_list) 33 | 34 | ## GET and parse data to sf object 35 | cli <- bcdc_http_client(url = "https://delivery.openmaps.gov.bc.ca/om/wcs") 36 | 37 | tiff_file <- tempfile(fileext = ".tif") 38 | res <- cli$get(query = query_list, disk = tiff_file) 39 | close(file(tiff_file)) 40 | 41 | raster::raster(res$content) 42 | } 43 | -------------------------------------------------------------------------------- /man/bcdc_preview.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bcdc-web-services.R 3 | \name{bcdc_preview} 4 | \alias{bcdc_preview} 5 | \title{Get preview map from the B.C. Web Map Service} 6 | \usage{ 7 | bcdc_preview(record) 8 | } 9 | \arguments{ 10 | \item{record}{either a \code{bcdc_record} object (from the result of \code{bcdc_get_record()}), 11 | a character string denoting the name or ID of a resource (or the URL) or a BC Geographic 12 | Warehouse (BCGW) name. 13 | 14 | It is advised to use the permanent ID for a record or the BCGW name rather than the 15 | human-readable name to guard against future name changes of the record. 16 | If you use the human-readable name a warning will be issued once per 17 | session. You can silence these warnings altogether by setting an option: 18 | \code{options("silence_named_get_data_warning" = TRUE)} - which you can set 19 | in your .Rprofile file so the option persists across sessions.} 20 | } 21 | \description{ 22 | Note this does not return the actual map features, rather 23 | opens an image preview of the layer in a 24 | \href{https://rstudio.github.io/leaflet/}{Leaflet} map window 25 | } 26 | \examples{ 27 | \donttest{ 28 | try( 29 | bcdc_preview("regional-districts-legally-defined-administrative-areas-of-bc") 30 | ) 31 | 32 | try( 33 | bcdc_preview("water-reservations-points") 34 | ) 35 | 36 | # Using BCGW name 37 | try( 38 | bcdc_preview("WHSE_LEGAL_ADMIN_BOUNDARIES.ABMS_REGIONAL_DISTRICTS_SP") 39 | ) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/testthat/setup.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | original_options <- options() 14 | 15 | options("silence_named_get_record_warning" = TRUE) 16 | 17 | ##### To test on delivery/test versions of w[fm]s server change this option 18 | # options("bcdata.web_service_host" = "https://delivery.openmaps.gov.bc.ca") 19 | ## OR 20 | # options("bcdata.web_service_host" = "https://test.openmaps.gov.bc.ca") 21 | 22 | ##### To test on beta catalogue 23 | # options("bcdata.catalogue_api_url" = "https://beta-catalogue.data.gov.bc.ca/api/3/") 24 | # options("bcdata.catalogue_gui_url" = "https://beta-catalogue.data.gov.bc.ca/") 25 | 26 | point_record <- '76b1b7a3-2112-4444-857a-afccf7b20da8' 27 | point_resource <- "4d0377d9-e8a1-429b-824f-0ce8f363512c" 28 | polygon_record <- 'd1aff64e-dbfe-45a6-af97-582b7f6418b9' 29 | lines_record <- '92344413-8035-4c08-b996-65a9b3f62fca' 30 | bcgw_point_record <- 'WHSE_IMAGERY_AND_BASE_MAPS.GSR_AIRPORTS_SVW' 31 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: test-coverage 10 | 11 | jobs: 12 | test-coverage: 13 | runs-on: ubuntu-latest 14 | env: 15 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | 20 | - uses: r-lib/actions/setup-r@v2 21 | with: 22 | use-public-rspm: true 23 | 24 | - uses: r-lib/actions/setup-r-dependencies@v2 25 | with: 26 | extra-packages: any::covr 27 | needs: coverage 28 | 29 | - name: Test coverage 30 | run: | 31 | covr::codecov( 32 | quiet = FALSE, 33 | clean = FALSE, 34 | install_path = file.path(Sys.getenv("RUNNER_TEMP"), "package") 35 | ) 36 | shell: Rscript {0} 37 | 38 | - name: Show testthat output 39 | if: always() 40 | run: | 41 | ## -------------------------------------------------------------------- 42 | find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true 43 | shell: bash 44 | 45 | - name: Upload test results 46 | if: failure() 47 | uses: actions/upload-artifact@v4 48 | with: 49 | name: coverage-test-failures 50 | path: ${{ runner.temp }}/package 51 | -------------------------------------------------------------------------------- /man/bcdc_check_geom_size.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cql-geom-predicates.R 3 | \name{bcdc_check_geom_size} 4 | \alias{bcdc_check_geom_size} 5 | \title{Check spatial objects for WFS spatial operations} 6 | \usage{ 7 | bcdc_check_geom_size(x) 8 | } 9 | \arguments{ 10 | \item{x}{object of class sf, sfc or sfg} 11 | } 12 | \value{ 13 | invisibly return logical indicating whether the check pass. If the return 14 | value is TRUE, the object will not need a bounding box drawn. If the return value is 15 | FALSE, the check will fails and a bounding box will be drawn. 16 | } 17 | \description{ 18 | Check a spatial object to see if it exceeds the current set value of 19 | 'bcdata.max_geom_pred_size' option, which controls how the object is treated when used inside a spatial predicate function in \code{\link[=filter.bcdc_promise]{filter.bcdc_promise()}}. If the object does exceed the size 20 | threshold a bounding box is drawn around it and all features 21 | within the box will be returned. Further options include: 22 | \itemize{ 23 | \item Try adjusting the value of the 'bcdata.max_geom_pred_size' option 24 | \item Simplify the spatial object to reduce its size 25 | \item Further processing on the returned object 26 | } 27 | } 28 | \details{ 29 | See the \href{https://bcgov.github.io/bcdata/articles/efficiently-query-spatial-data-in-the-bc-data-catalogue.html}{Querying Spatial Data with bcdata} 30 | for more details. 31 | } 32 | \examples{ 33 | \donttest{ 34 | try({ 35 | airports <- bcdc_query_geodata("bc-airports") \%>\% collect() 36 | bcdc_check_geom_size(airports) 37 | }) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /man/bcdc_tidy_resources.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bcdc_search.R 3 | \name{bcdc_tidy_resources} 4 | \alias{bcdc_tidy_resources} 5 | \title{Provide a data frame containing the metadata for all resources from a single B.C. Data Catalogue record} 6 | \usage{ 7 | bcdc_tidy_resources(record) 8 | } 9 | \arguments{ 10 | \item{record}{either a \code{bcdc_record} object (from the result of \code{bcdc_get_record()}), 11 | a character string denoting the name or ID of a resource (or the URL) or a BC Geographic 12 | Warehouse (BCGW) name. 13 | 14 | It is advised to use the permanent ID for a record or the BCGW name rather than the 15 | human-readable name to guard against future name changes of the record. 16 | If you use the human-readable name a warning will be issued once per 17 | session. You can silence these warnings altogether by setting an option: 18 | \code{options("silence_named_get_data_warning" = TRUE)} - which you can set 19 | in your .Rprofile file so the option persists across sessions.} 20 | } 21 | \value{ 22 | A data frame containing the metadata for all the resources for a record 23 | } 24 | \description{ 25 | Returns a rectangular data frame of all resources contained within a record. This is particularly useful 26 | if you are trying to construct a vector of multiple resources in a record. The data frame also provides 27 | useful information on the formats, availability and types of data available. 28 | } 29 | \examples{ 30 | \donttest{ 31 | try( 32 | airports <- bcdc_get_record("bc-airports") 33 | ) 34 | 35 | try( 36 | bcdc_tidy_resources(airports) 37 | ) 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /man/bcdc_search.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bcdc_search.R 3 | \name{bcdc_search} 4 | \alias{bcdc_search} 5 | \title{Search the B.C. Data Catalogue} 6 | \usage{ 7 | bcdc_search( 8 | ..., 9 | license_id = NULL, 10 | download_audience = NULL, 11 | res_format = NULL, 12 | sector = NULL, 13 | organization = NULL, 14 | groups = NULL, 15 | n = 100 16 | ) 17 | } 18 | \arguments{ 19 | \item{...}{search terms} 20 | 21 | \item{license_id}{the type of license (see \code{bcdc_search_facets("license_id")}).} 22 | 23 | \item{download_audience}{download audience 24 | (see \code{bcdc_search_facets("download_audience")}). Default \code{NULL} (all audiences).} 25 | 26 | \item{res_format}{format of resource (see \code{bcdc_search_facets("res_format")})} 27 | 28 | \item{sector}{sector of government from which the data comes 29 | (see \code{bcdc_search_facets("sector")})} 30 | 31 | \item{organization}{government organization that manages the data 32 | (see \code{bcdc_search_facets("organization")})} 33 | 34 | \item{groups}{collections of datasets for a particular project or on a particular theme 35 | (see \code{bcdc_search_facets("groups")})} 36 | 37 | \item{n}{number of results to return. Default \code{100}} 38 | } 39 | \value{ 40 | A list containing the records that match the search 41 | } 42 | \description{ 43 | Search the B.C. Data Catalogue 44 | } 45 | \examples{ 46 | \donttest{ 47 | try( 48 | bcdc_search("forest") 49 | ) 50 | 51 | try( 52 | bcdc_search("regional district", res_format = "fgdb") 53 | ) 54 | 55 | try( 56 | bcdc_search("angling", groups = "bc-tourism") 57 | ) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /man/bcdata-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bcdata-package.R 3 | \docType{package} 4 | \name{bcdata-package} 5 | \alias{bcdata} 6 | \alias{bcdata-package} 7 | \title{bcdata: Search and Retrieve Data from the BC Data Catalogue} 8 | \description{ 9 | \if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} 10 | 11 | Search, query, and download tabular and 'geospatial' data from the British Columbia Data Catalogue (\url{https://catalogue.data.gov.bc.ca/}). Search catalogue data records based on keywords, data licence, sector, data format, and B.C. government organization. View metadata directly in R, download many data formats, and query 'geospatial' data available via the B.C. government Web Feature Service ('WFS') using 'dplyr' syntax. 12 | } 13 | \seealso{ 14 | Useful links: 15 | \itemize{ 16 | \item \url{https://bcgov.github.io/bcdata/} 17 | \item \url{https://catalogue.data.gov.bc.ca/} 18 | \item \url{https://github.com/bcgov/bcdata/} 19 | \item Report bugs at \url{https://github.com/bcgov/bcdata/issues} 20 | } 21 | 22 | } 23 | \author{ 24 | \strong{Maintainer}: Andy Teucher \email{andy.teucher@gmail.com} (\href{https://orcid.org/0000-0002-7840-692X}{ORCID}) 25 | 26 | Authors: 27 | \itemize{ 28 | \item Sam Albers \email{sam.albers@gmail.com} (\href{https://orcid.org/0000-0002-9270-7884}{ORCID}) [contributor] 29 | \item Stephanie Hazlitt \email{stephhazlitt@gmail.com} (\href{https://orcid.org/0000-0002-3161-2304}{ORCID}) [contributor] 30 | } 31 | 32 | Other contributors: 33 | \itemize{ 34 | \item Province of British Columbia [copyright holder] 35 | } 36 | 37 | } 38 | \keyword{internal} 39 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | development: 2 | mode: auto 3 | 4 | url: https://bcgov.github.io/bcdata 5 | 6 | template: 7 | bootstrap: 5 8 | bslib: 9 | base_font: "BCSans" 10 | code_font: {google: "Fira Mono"} 11 | 12 | code: 13 | width: 60 14 | 15 | reference: 16 | - title: "Interacting with the B.C. Data Catalogue" 17 | desc: > 18 | Functions to search, browse, list, and explore records and their 19 | resources (data sets) in the B.C. Data Catalogue 20 | contents: 21 | - '`bcdc_browse`' 22 | - '`bcdc_search`' 23 | - '`bcdc_search_facets`' 24 | - '`bcdc_list`' 25 | - '`bcdc_get_record`' 26 | - '`bcdc_tidy_resources`' 27 | - '`bcdc_list_groups`' 28 | - '`bcdc_list_group_records`' 29 | - '`bcdc_list_organizations`' 30 | - '`bcdc_list_organization_records`' 31 | - '`bcdc_get_citation`' 32 | - title: "Direct downloads of data sets" 33 | desc: > 34 | Directly download (or preview) data sets (resources) from the 35 | B.C. Data Catalogue 36 | contents: 37 | - '`bcdc_get_data`' 38 | - '`bcdc_preview`' 39 | - '`bcdc_read_functions`' 40 | - title: "Querying data from a Web Feature Service catalogue record" 41 | desc: > 42 | Issue queries using `select` and `filter` verbs against data sets in the 43 | B.C. Data Catalogue that have a Web Feature Service. 44 | contents: 45 | - '`bcdc_query_geodata`' 46 | - '`bcdc_describe_feature`' 47 | - '`filter.bcdc_promise`' 48 | - '`select.bcdc_promise`' 49 | - '`mutate.bcdc_promise`' 50 | - '`collect.bcdc_promise`' 51 | - '`cql_geom_predicates`' 52 | - '`bcdc_check_geom_size`' 53 | - '`CQL`' 54 | - '`bcdc_options`' 55 | 56 | 57 | -------------------------------------------------------------------------------- /man/bcdc_get_citation.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bcdc-get-citation.R 3 | \name{bcdc_get_citation} 4 | \alias{bcdc_get_citation} 5 | \title{Generate a bibentry from a Data Catalogue Record} 6 | \usage{ 7 | bcdc_get_citation(record) 8 | } 9 | \arguments{ 10 | \item{record}{either a \code{bcdc_record} object (from the result of \code{bcdc_get_record()}), 11 | a character string denoting the name or ID of a resource (or the URL) 12 | 13 | It is advised to use the permanent ID for a record rather than the 14 | human-readable name to guard against future name changes of the record. 15 | If you use the human-readable name a warning will be issued once per 16 | session. You can silence these warnings altogether by setting an option: 17 | \code{options("silence_named_get_data_warning" = TRUE)} - which you can set 18 | in your .Rprofile file so the option persists across sessions.} 19 | } 20 | \description{ 21 | Generate a "TechReport" bibentry object directly from a catalogue record. 22 | The primary use of this function is as a helper to create a \code{.bib} file for use 23 | in reference management software to cite data from the B.C. Data Catalogue. 24 | This function is likely to be starting place for this process and manual 25 | adjustment will often be needed. The bibentries are not designed to be 26 | authoritative and may not reflect all fields required for individual 27 | citation requirements. 28 | } 29 | \examples{ 30 | 31 | try( 32 | bcdc_get_citation("76b1b7a3-2112-4444-857a-afccf7b20da8") 33 | ) 34 | 35 | ## Or directly on a record object 36 | try( 37 | bcdc_get_citation(bcdc_get_record("76b1b7a3-2112-4444-857a-afccf7b20da8")) 38 | ) 39 | } 40 | \seealso{ 41 | \code{\link[utils:bibentry]{utils::bibentry()}} 42 | } 43 | -------------------------------------------------------------------------------- /man/select.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-classes.R, R/utils-select.R 3 | \name{select.bcdc_promise} 4 | \alias{select.bcdc_promise} 5 | \alias{select} 6 | \title{Select columns from bcdc_query_geodata() call} 7 | \usage{ 8 | \method{select}{bcdc_promise}(.data, ...) 9 | } 10 | \arguments{ 11 | \item{.data}{object of class \code{bcdc_promise} (likely passed from \code{\link[=bcdc_query_geodata]{bcdc_query_geodata()}})} 12 | 13 | \item{...}{One or more unquoted expressions separated by commas. See details.} 14 | } 15 | \description{ 16 | Similar to a \code{dplyr::select} call, this allows you to select which columns you want the Web Feature Service to return. 17 | A key difference between \code{dplyr::select} and \code{bcdata::select} is the presence of "sticky" columns that are 18 | returned regardless of what columns are selected. If any of these "sticky" columns are selected 19 | only "sticky" columns are return. \code{bcdc_describe_feature} is one way to tell if columns are sticky in advance 20 | of issuing the Web Feature Service call. 21 | 22 | See \code{dplyr::\link[dplyr]{select}} for details. 23 | } 24 | \section{Methods (by class)}{ 25 | \itemize{ 26 | \item \code{select(bcdc_promise)}: select.bcdc_promise 27 | 28 | }} 29 | \examples{ 30 | \donttest{ 31 | try( 32 | feature_spec <- bcdc_describe_feature("bc-airports") 33 | ) 34 | 35 | try( 36 | ## Columns that can selected: 37 | feature_spec[feature_spec$sticky == TRUE,] 38 | ) 39 | 40 | ## Select columns 41 | try( 42 | res <- bcdc_query_geodata("bc-airports") \%>\% 43 | select(DESCRIPTION, PHYSICAL_ADDRESS) 44 | ) 45 | 46 | ## Select "sticky" columns 47 | try( 48 | res <- bcdc_query_geodata("bc-airports") \%>\% 49 | select(LOCALITY) 50 | ) 51 | } 52 | 53 | 54 | } 55 | \keyword{internal} 56 | -------------------------------------------------------------------------------- /vignettes/precompile.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | # Precompile vignettes 14 | 15 | precompile <- function(vignette_to_run = NULL) { 16 | orig_files <- file.path(list.files( 17 | path = "vignettes/", 18 | pattern = "*\\.Rmd\\.orig", 19 | full.names = TRUE 20 | )) 21 | 22 | if (!is.null(vignette_to_run)) { 23 | orig_files <- orig_files[basename(orig_files) %in% vignette_to_run] 24 | 25 | if (rlang::is_empty(orig_files)) stop("Not a vignette!") 26 | } 27 | 28 | # Convert *.orig to *.Rmd ------------------------------------------------- 29 | purrr::walk(orig_files, ~ knitr::knit(.x, tools::file_path_sans_ext(.x))) 30 | 31 | # Move .png files into correct directory so they render ------------------- 32 | images <- file.path(list.files(".", pattern = 'vignette-fig.*\\.png$')) 33 | success <- file.copy( 34 | from = images, 35 | to = file.path("vignettes", images), 36 | overwrite = TRUE 37 | ) 38 | 39 | # Clean up if successful -------------------------------------------------- 40 | if (!all(success)) { 41 | stop("Image files were not successfully transferred to vignettes directory") 42 | } else { 43 | unlink(images) 44 | } 45 | } 46 | 47 | ## Run all vignettes 48 | precompile() 49 | 50 | ## Or just one 51 | #precompile("bcdata.Rmd.orig") 52 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | schedule: 9 | - cron: '30 4 * * 1' 10 | 11 | name: R-CMD-check 12 | 13 | jobs: 14 | R-CMD-check: 15 | runs-on: ${{ matrix.config.os }} 16 | 17 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 18 | 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | config: 23 | - {os: macos-latest, r: 'release'} 24 | - {os: windows-latest, r: 'release'} 25 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 26 | - {os: ubuntu-latest, r: 'release'} 27 | - {os: ubuntu-latest, r: 'oldrel-1'} 28 | 29 | env: 30 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 31 | R_KEEP_PKG_SOURCE: yes 32 | # BCDC_KEY: ${{ secrets.BCDC_KEY }} 33 | BCDC_TEST_RECORD: ${{ secrets.BCDC_TEST_RECORD }} 34 | 35 | steps: 36 | - uses: actions/checkout@v4 37 | 38 | - uses: r-lib/actions/setup-pandoc@v2 39 | 40 | - uses: r-lib/actions/setup-r@v2 41 | with: 42 | r-version: ${{ matrix.config.r }} 43 | http-user-agent: ${{ matrix.config.http-user-agent }} 44 | use-public-rspm: true 45 | 46 | - name: install macOS system dependencies 47 | if: runner.os == 'macOS' 48 | continue-on-error: true 49 | run: | 50 | brew install pkg-config gdal udunits 51 | 52 | - uses: r-lib/actions/setup-r-dependencies@v2 53 | with: 54 | extra-packages: any::rcmdcheck 55 | needs: check 56 | 57 | 58 | - uses: r-lib/actions/check-r-package@v2 59 | with: 60 | upload-snapshots: true 61 | -------------------------------------------------------------------------------- /man/bcdc_describe_feature.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/describe-feature.R 3 | \name{bcdc_describe_feature} 4 | \alias{bcdc_describe_feature} 5 | \title{Describe the attributes of a Web Feature Service} 6 | \usage{ 7 | bcdc_describe_feature(record) 8 | } 9 | \arguments{ 10 | \item{record}{either a \code{bcdc_record} object (from the result of \code{bcdc_get_record()}), 11 | a character string denoting the name or ID of a resource (or the URL) or a BC Geographic 12 | Warehouse (BCGW) name. 13 | 14 | It is advised to use the permanent ID for a record or the BCGW name rather than the 15 | human-readable name to guard against future name changes of the record. 16 | If you use the human-readable name a warning will be issued once per 17 | session. You can silence these warnings altogether by setting an option: 18 | \code{options("silence_named_get_data_warning" = TRUE)} - which you can set 19 | in your .Rprofile file so the option persists across sessions.} 20 | } 21 | \value{ 22 | \code{bcdc_describe_feature} returns a tibble describing the attributes of a B.C. Data Catalogue record. 23 | The tibble returns the following columns: 24 | \itemize{ 25 | \item col_name: attributes of the feature 26 | \item sticky: whether a column can be separated from the record in a Web Feature Service call via the \code{dplyr::select} method 27 | \item remote_col_type: class of what is return by the web feature service 28 | \item local_col_type: the column class in R 29 | \item column_comments: additional metadata specific to that column 30 | } 31 | } 32 | \description{ 33 | Describe the attributes of column of a record accessed through the Web Feature Service. 34 | This can be a useful tool to examine a layer before issuing a query with \code{bcdc_query_geodata}. 35 | } 36 | \examples{ 37 | \donttest{ 38 | try( 39 | bcdc_describe_feature("bc-airports") 40 | ) 41 | 42 | try( 43 | bcdc_describe_feature("WHSE_IMAGERY_AND_BASE_MAPS.GSR_AIRPORTS_SVW") 44 | ) 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /man/bcdc_browse.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bcdc_browse.R 3 | \name{bcdc_browse} 4 | \alias{bcdc_browse} 5 | \title{Load the B.C. Data Catalogue URL into an HTML browser} 6 | \usage{ 7 | bcdc_browse( 8 | query = NULL, 9 | browser = getOption("browser"), 10 | encodeIfNeeded = FALSE 11 | ) 12 | } 13 | \arguments{ 14 | \item{query}{Default (NULL) opens a browser to \code{https://catalogue.data.gov.bc.ca}. 15 | This argument will also accept a B.C. Data Catalogue record ID or name to take you 16 | directly to that page. If the provided ID or name doesn't lead to a valid webpage, 17 | bcdc_browse will search the data catalogue for that string.} 18 | 19 | \item{browser}{a non-empty character string giving the name of the 20 | program to be used as the HTML browser. It should be in the PATH, 21 | or a full path specified. Alternatively, an \R function to be 22 | called to invoke the browser. 23 | 24 | Under Windows \code{NULL} is also allowed (and is the default), and 25 | implies that the file association mechanism will be used. 26 | } 27 | 28 | \item{encodeIfNeeded}{Should the URL be encoded by 29 | \code{\link[utils]{URLencode}} before passing to the browser? This is not 30 | needed (and might be harmful) if the \code{browser} program/function 31 | itself does encoding, and can be harmful for \samp{file://} URLs on some 32 | systems and for \samp{http://} URLs passed to some CGI applications. 33 | Fortunately, most URLs do not need encoding.} 34 | } 35 | \value{ 36 | A browser is opened with the B.C. Data Catalogue URL loaded if the 37 | session is interactive. The URL used is returned as a character string. 38 | } 39 | \description{ 40 | This is a wrapper around utils::browseURL with the URL for the B.C. Data Catalogue as 41 | the default 42 | } 43 | \examples{ 44 | \donttest{ 45 | ## Take me to the B.C. Data Catalogue home page 46 | try( 47 | bcdc_browse() 48 | ) 49 | 50 | ## Take me to the B.C. airports catalogue record 51 | try( 52 | bcdc_browse("bc-airports") 53 | ) 54 | 55 | ## Take me to the B.C. airports catalogue record 56 | try( 57 | bcdc_browse("76b1b7a3-2112-4444-857a-afccf7b20da8") 58 | ) 59 | } 60 | } 61 | \seealso{ 62 | \code{\link[utils]{browseURL}} 63 | } 64 | -------------------------------------------------------------------------------- /tests/testthat/test-print-methods.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | test_that("bcdc_promise print methods work", { 14 | skip_on_cran() 15 | skip_if_net_down() 16 | promise_print <- capture_output( 17 | bcdc_query_geodata('76b1b7a3-2112-4444-857a-afccf7b20da8'), 18 | print = TRUE 19 | ) 20 | expect_true(nzchar(promise_print)) 21 | }) 22 | 23 | test_that("bcdc_record print methods work", { 24 | skip_on_cran() 25 | skip_if_net_down() 26 | record_print <- capture_output( 27 | bcdc_get_record('76b1b7a3-2112-4444-857a-afccf7b20da8'), 28 | print = TRUE 29 | ) 30 | expect_true(nzchar(record_print)) 31 | }) 32 | 33 | test_that("bcdc_recordlist print methods work", { 34 | skip_on_cran() 35 | skip_if_net_down() 36 | recordlist_print <- capture_output(bcdc_search("bears"), print = TRUE) 37 | expect_true(nzchar(recordlist_print)) 38 | }) 39 | 40 | test_that("show query works for bcdc_promise object", { 41 | skip_on_cran() 42 | skip_if_net_down() 43 | prom_obj <- bcdc_query_geodata('76b1b7a3-2112-4444-857a-afccf7b20da8') 44 | expect_s3_class(show_query(prom_obj), "bcdc_query") 45 | }) 46 | 47 | 48 | test_that("show query works for bcdc_sf object", { 49 | skip_on_cran() 50 | skip_if_net_down() 51 | sf_obj <- collect(bcdc_query_geodata('76b1b7a3-2112-4444-857a-afccf7b20da8')) 52 | expect_s3_class(show_query(sf_obj), "bcdc_query") 53 | }) 54 | 55 | test_that("record with a zip file prints correctly", { 56 | skip_on_cran() 57 | skip_if_net_down() 58 | output <- capture_output( 59 | bcdc_get_record("bc-grizzly-bear-habitat-classification-and-rating"), 60 | print = TRUE 61 | ) 62 | expect_true(any(grepl("zip", output))) 63 | }) 64 | -------------------------------------------------------------------------------- /scratch/multipoint.R: -------------------------------------------------------------------------------- 1 | # Issues: 2 | # https://github.com/bcgov/bcdata/issues/159 3 | # https://github.com/r-spatial/sf/issues/1219 4 | 5 | library(sf) 6 | library(httr) 7 | 8 | mp_sfc <- sf::st_as_sfc("MULTIPOINT ((1236285 463726.8), (1228264 463547.4))") 9 | mp_sfc 10 | 11 | mp <- sf::st_as_text(mp_sfc) 12 | mp # inner parentheses removed 13 | 14 | format_multipoint <- function(x) { 15 | gsub("(-?[0-9.]+\\s+-?[0-9.]+)(,?)", "(\\1)\\2", x) 16 | } 17 | 18 | mp2 <- format_multipoint(mp) 19 | mp2 # inner parentheses added 20 | 21 | # Issue a request to geoserver using the multipoint without parentheses around 22 | # points 23 | a <- GET( 24 | "https://openmaps.gov.bc.ca/geo/pub/wfs", 25 | query = list( 26 | SERVICE = "WFS", 27 | VERSION = "2.0.0", 28 | REQUEST = "GetFeature", 29 | outputFormat = "application/json", 30 | typeNames = "WHSE_BASEMAPPING.GBA_LOCAL_REG_GREENSPACES_SP", 31 | SRSNAME = "EPSG:3005", 32 | CQL_FILTER = paste0("INTERSECTS(SHAPE, ", mp, ")") 33 | ) 34 | ) 35 | 36 | URLdecode(a$url) 37 | a$status_code 38 | content(a, as = "text") 39 | 40 | # Issue a request to geoserver using the multipoint *with* parentheses around 41 | # points 42 | b <- httr::GET( 43 | "https://openmaps.gov.bc.ca/geo/pub/wfs", 44 | query = list( 45 | SERVICE = "WFS", 46 | VERSION = "2.0.0", 47 | REQUEST = "GetFeature", 48 | outputFormat = "application/json", 49 | typeNames = "WHSE_BASEMAPPING.GBA_LOCAL_REG_GREENSPACES_SP", 50 | SRSNAME = "EPSG:3005", 51 | CQL_FILTER = paste0("INTERSECTS(SHAPE, ", mp2, ")") 52 | ) 53 | ) 54 | 55 | URLdecode(b$url) 56 | b$status_code 57 | b_content <- content(b, as = "text") 58 | read_sf(b_content) 59 | 60 | ## Check speed with biggish data set 61 | # wells <- bcdc_query_geodata("bc-environmental-monitoring-locations") %>% collect() 62 | # saveRDS(wells, "wells.rds") 63 | wells <- readRDS("wells.rds") %>% 64 | st_geometry() %>% 65 | st_combine() 66 | 67 | wells_4326 <- st_transform(wells, 4326) 68 | 69 | tictoc::tic() 70 | mp_text <- st_as_text(wells) 71 | tictoc::toc() 72 | tictoc::tic() 73 | mp_formatted <- format_multipoint(mp_text) 74 | tictoc::toc() 75 | 76 | # Decimal degrees, with negative signs 77 | mp_text <- st_as_text(wells_4326) 78 | mp_formatted <- format_multipoint(mp_text) 79 | substr(mp_formatted, 1, 500) 80 | -------------------------------------------------------------------------------- /man/cql_geom_predicates.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cql-geom-predicates.R 3 | \name{cql_geom_predicates} 4 | \alias{cql_geom_predicates} 5 | \alias{EQUALS} 6 | \alias{DISJOINT} 7 | \alias{INTERSECTS} 8 | \alias{TOUCHES} 9 | \alias{CROSSES} 10 | \alias{WITHIN} 11 | \alias{CONTAINS} 12 | \alias{OVERLAPS} 13 | \alias{BBOX} 14 | \alias{DWITHIN} 15 | \title{CQL Geometry Predicates} 16 | \usage{ 17 | EQUALS(geom) 18 | 19 | DISJOINT(geom) 20 | 21 | INTERSECTS(geom) 22 | 23 | TOUCHES(geom) 24 | 25 | CROSSES(geom) 26 | 27 | WITHIN(geom) 28 | 29 | CONTAINS(geom) 30 | 31 | OVERLAPS(geom) 32 | 33 | BBOX(coords, crs = NULL) 34 | 35 | DWITHIN( 36 | geom, 37 | distance, 38 | units = c("meters", "feet", "statute miles", "nautical miles", "kilometers") 39 | ) 40 | } 41 | \arguments{ 42 | \item{geom}{an \code{sf}/\code{sfc}/\code{sfg} or \code{bbox} object (from the \code{sf} package)} 43 | 44 | \item{coords}{the coordinates of the bounding box as four-element numeric 45 | vector \code{c(xmin, ymin, xmax, ymax)}, a \code{bbox} object from the \code{sf} 46 | package (the result of running \code{sf::st_bbox()} on an \code{sf} object), or 47 | an \code{sf} object which then gets converted to a bounding box on the fly.} 48 | 49 | \item{crs}{(Optional) A numeric value or string containing an SRS code. If 50 | \code{coords} is a \code{bbox} object with non-empty crs, it is taken from that. 51 | (For example, \code{'EPSG:3005'} or just \code{3005}. The default is to use the CRS of 52 | the queried layer)} 53 | 54 | \item{distance}{numeric value for distance tolerance} 55 | 56 | \item{units}{units that distance is specified in. One of 57 | \code{"feet"}, \code{"meters"}, \code{"statute miles"}, \code{"nautical miles"}, \code{"kilometers"}} 58 | } 59 | \value{ 60 | a CQL expression to be passed on to the WFS call 61 | } 62 | \description{ 63 | Functions to construct a CQL expression to be used 64 | to filter results from \code{\link[=bcdc_query_geodata]{bcdc_query_geodata()}}. 65 | See \href{https://docs.geoserver.org/stable/en/user/filter/ecql_reference.html#spatial-predicate}{the geoserver CQL documentation for details}. 66 | The sf object is automatically converted in a 67 | bounding box to reduce the complexity of the Web Feature Service call. Subsequent in-memory 68 | filtering may be needed to achieve exact results. 69 | } 70 | -------------------------------------------------------------------------------- /.github/workflows/pr-commands.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | issue_comment: 3 | types: [created] 4 | name: Commands 5 | jobs: 6 | document: 7 | if: startsWith(github.event.comment.body, '/document') 8 | name: document 9 | runs-on: macOS-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: r-lib/actions/pr-fetch@v2 13 | with: 14 | repo-token: ${{ secrets.GITHUB_TOKEN }} 15 | - uses: r-lib/actions/setup-r@v2 16 | - name: Install dependencies 17 | run: Rscript -e 'install.packages(c("remotes", "roxygen2"))' -e 'remotes::install_deps(dependencies = TRUE)' 18 | - name: Document 19 | run: Rscript -e 'roxygen2::roxygenise()' 20 | - name: commit 21 | run: | 22 | if [[ -n "$(git status --porcelain)" ]]; then 23 | git add man/\* NAMESPACE 24 | git add DESCRIPTION 25 | git commit -m 'Document' 26 | fi 27 | - uses: r-lib/actions/pr-push@v2 28 | with: 29 | repo-token: ${{ secrets.GITHUB_TOKEN }} 30 | precompile: 31 | if: startsWith(github.event.comment.body, '/precompile') 32 | name: precompile 33 | runs-on: macOS-latest 34 | steps: 35 | - uses: actions/checkout@v4 36 | - uses: r-lib/actions/pr-fetch@v2 37 | with: 38 | repo-token: ${{ secrets.GITHUB_TOKEN }} 39 | - uses: r-lib/actions/setup-r@v2 40 | - name: Install XQuartz on macOS 41 | if: runner.os == 'macOS' 42 | run: brew install xquartz 43 | - name: Install dependencies 44 | run: Rscript -e 'install.packages(c("devtools", "tools", "knitr", "purrr", "Cairo"))' 45 | - name: Install pr version of bcdata and pkg dependencies 46 | run: Rscript -e 'devtools::install()' 47 | - name: Precompile vignettes 48 | run: Rscript './vignettes/precompile.R' 49 | - name: commit 50 | run: | 51 | if [[ -n "$(git status --porcelain)" ]]; then 52 | git add \*.R 53 | git add \*.Rmd 54 | git add \*.png 55 | git commit -m 'precompile vignettes' 56 | fi 57 | - uses: r-lib/actions/pr-push@v2 58 | with: 59 | repo-token: ${{ secrets.GITHUB_TOKEN }} 60 | # A mock job just to ensure we have a successful build status 61 | finish: 62 | runs-on: ubuntu-latest 63 | steps: 64 | - run: true 65 | -------------------------------------------------------------------------------- /tests/testthat/test-query-geodata-base-methods.R: -------------------------------------------------------------------------------- 1 | test_that("head works", { 2 | skip_if_net_down() 3 | skip_on_cran() 4 | promise <- bcdc_query_geodata(point_record) %>% 5 | head() 6 | expect_s3_class(promise, "bcdc_promise") 7 | collected <- collect(promise) 8 | expect_equal(nrow(collected), 6L) 9 | d2 <- bcdc_query_geodata(point_record) %>% 10 | head(n = 3) %>% 11 | collect() 12 | expect_equal(nrow(d2), 3L) 13 | col <- pagination_sort_col(bcdc_describe_feature(point_record)) 14 | full_airport <- bcdc_get_data(point_record, resource = point_resource) 15 | expect_equal( 16 | d2[[col]], 17 | head(full_airport[order(full_airport[[col]]), ], 3L)[[col]] 18 | ) 19 | }) 20 | 21 | test_that("tail works", { 22 | skip_if_net_down() 23 | skip_on_cran() 24 | promise <- bcdc_query_geodata(point_record) %>% 25 | tail() 26 | expect_s3_class(promise, "bcdc_promise") 27 | collected <- collect(promise) 28 | expect_equal(nrow(collected), 6L) 29 | d2 <- bcdc_query_geodata(point_record) %>% 30 | tail(n = 3) %>% 31 | collect() 32 | expect_equal(nrow(d2), 3L) 33 | col <- pagination_sort_col(bcdc_describe_feature(point_record)) 34 | full_airport <- bcdc_get_data(point_record, resource = point_resource) 35 | expect_equal( 36 | d2[[col]], 37 | tail(full_airport[order(full_airport[[col]]), ], 3L)[[col]] 38 | ) 39 | }) 40 | 41 | 42 | test_that("head/tail works with a record that would otherwise require pagination", { 43 | skip_if_net_down() 44 | skip_on_cran() 45 | dh <- bcdc_query_geodata('2af1388e-d5f7-46dc-a6e2-f85415ddbd1c') %>% 46 | head(3) %>% 47 | collect() 48 | 49 | expect_equal(nrow(dh), 3L) 50 | 51 | dt <- bcdc_query_geodata('2af1388e-d5f7-46dc-a6e2-f85415ddbd1c') %>% 52 | tail(3) %>% 53 | collect() 54 | 55 | expect_equal(nrow(dt), 3L) 56 | }) 57 | 58 | test_that("names.bcdc_promise returns the same as names on a data.frame", { 59 | skip_if_net_down() 60 | skip_on_cran() 61 | query01 <- bcdc_query_geodata(point_record) %>% 62 | head() 63 | 64 | expect_identical( 65 | names(query01), 66 | names(collect(query01)) 67 | ) 68 | }) 69 | 70 | test_that("names.bcdc_promise returns the same as names on a data.frame when using select", { 71 | skip_if_net_down() 72 | skip_on_cran() 73 | query02 <- bcdc_query_geodata(polygon_record) %>% 74 | head() %>% 75 | select(1:3) 76 | 77 | expect_identical( 78 | names(query02), 79 | names(collect(query02)) 80 | ) 81 | }) 82 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of 4 | fostering an open and welcoming community, we pledge to respect all people who 5 | contribute through reporting issues, posting feature requests, updating 6 | documentation, submitting pull requests or patches, and other activities. 7 | 8 | We are committed to making participation in this project a harassment-free 9 | experience for everyone, regardless of level of experience, gender, gender 10 | identity and expression, sexual orientation, disability, personal appearance, 11 | body size, race, ethnicity, age, religion, or nationality. 12 | 13 | Examples of unacceptable behavior by participants include: 14 | 15 | * The use of sexualized language or imagery 16 | * Personal attacks 17 | * Trolling or insulting/derogatory comments 18 | * Public or private harassment 19 | * Publishing other's private information, such as physical or electronic 20 | addresses, without explicit permission 21 | * Other unethical or unprofessional conduct 22 | 23 | Project maintainers have the right and responsibility to remove, edit, or 24 | reject comments, commits, code, wiki edits, issues, and other contributions 25 | that are not aligned to this Code of Conduct, or to ban temporarily or 26 | permanently any contributor for other behaviors that they deem inappropriate, 27 | threatening, offensive, or harmful. 28 | 29 | By adopting this Code of Conduct, project maintainers commit themselves to 30 | fairly and consistently applying these principles to every aspect of managing 31 | this project. Project maintainers who do not follow or enforce the Code of 32 | Conduct may be permanently removed from the project team. 33 | 34 | This Code of Conduct applies both within project spaces and in public spaces 35 | when an individual is representing the project or its community. 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 38 | reported by contacting a project maintainer at andy.teucher@gmail.com, sam.albers@gmail.com, or stephhazlitt@gmail.com. All complaints will be reviewed and investigated 39 | and will result in a response that is deemed necessary and appropriate to the 40 | circumstances. Maintainers are obligated to maintain confidentiality with regard 41 | to the reporter of an incident. 42 | 43 | 44 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 45 | version 1.3.0, available at 46 | [http://contributor-covenant.org/version/1/3/0/][version] 47 | 48 | [homepage]: http://contributor-covenant.org 49 | [version]: http://contributor-covenant.org/version/1/3/0/ 50 | 51 | --- 52 | *This project was created using the [bcgovr](https://github.com/bcgov/bcgovr) package.* 53 | -------------------------------------------------------------------------------- /man/filter.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-classes.R, R/utils-filter.R 3 | \name{filter.bcdc_promise} 4 | \alias{filter.bcdc_promise} 5 | \alias{filter} 6 | \title{Filter a query from bcdc_query_geodata()} 7 | \usage{ 8 | \method{filter}{bcdc_promise}(.data, ...) 9 | } 10 | \arguments{ 11 | \item{.data}{object of class \code{bcdc_promise} (likely passed from \code{\link[=bcdc_query_geodata]{bcdc_query_geodata()}})} 12 | 13 | \item{...}{Logical predicates with which to filter the results. Multiple 14 | conditions are combined with \code{&}. Only rows where the condition evaluates to 15 | \code{TRUE} are kept. Accepts normal R expressions as well as any of the special 16 | \link[=cql_geom_predicates]{CQL geometry functions} such as \code{WITHIN()} or \code{INTERSECTS()}. 17 | If you know \code{CQL} and want to write a \code{CQL} query directly, write it enclosed 18 | in quotes, wrapped in the \code{\link[=CQL]{CQL()}} function. e.g., \code{CQL("ID = '42'")}. 19 | 20 | If your filter expression contains calls that need to be executed locally, wrap them 21 | in \code{local()} to force evaluation in R before the request is sent to the server.} 22 | } 23 | \description{ 24 | Filter a query from Web Feature Service using dplyr 25 | methods. This filtering is accomplished lazily so that 26 | the full sf object is not read into memory until 27 | \code{collect()} has been called. 28 | 29 | See \code{dplyr::\link[dplyr]{filter}} for details. 30 | } 31 | \section{Methods (by class)}{ 32 | \itemize{ 33 | \item \code{filter(bcdc_promise)}: filter.bcdc_promise 34 | 35 | }} 36 | \examples{ 37 | \donttest{ 38 | try( 39 | crd <- bcdc_query_geodata("regional-districts-legally-defined-administrative-areas-of-bc") \%>\% 40 | filter(ADMIN_AREA_NAME == "Cariboo Regional District") \%>\% 41 | collect() 42 | ) 43 | 44 | try( 45 | ret1 <- bcdc_query_geodata("bc-wildfire-fire-perimeters-historical") \%>\% 46 | filter(FIRE_YEAR == 2000, FIRE_CAUSE == "Person", INTERSECTS(crd)) \%>\% 47 | collect() 48 | ) 49 | 50 | # Use local() to force parts of your call to be evaluated in R: 51 | try({ 52 | # Create a bounding box around two points and use that to filter 53 | # the remote data set 54 | library(sf) 55 | two_points <- st_sfc(st_point(c(1164434, 368738)), 56 | st_point(c(1203023, 412959)), 57 | crs = 3005) 58 | 59 | # Wrapping the call to `st_bbox()` in `local()` ensures that it 60 | # is executed in R to make a bounding box that is then sent to 61 | # the server for the filtering operation: 62 | res <- bcdc_query_geodata("local-and-regional-greenspaces") \%>\% 63 | filter(BBOX(local(st_bbox(two_points, crs = st_crs(two_points))))) \%>\% 64 | collect() 65 | }) 66 | } 67 | } 68 | \keyword{internal} 69 | -------------------------------------------------------------------------------- /vignettes/local-filter.Rmd.orig: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Update to `filter()` behaviour in bcdata v0.4.0" 3 | date: "`r Sys.Date()`" 4 | output: rmarkdown::html_vignette 5 | vignette: > 6 | %\VignetteIndexEntry{Update to `filter()` behaviour in bcdata v0.4.0} 7 | %\VignetteEngine{knitr::rmarkdown} 8 | %\VignetteEncoding{UTF-8} 9 | --- 10 | 11 | This vignette describes a change in `{bcdata}` v0.4.0 related to 12 | using locally-executed functions in a `filter()` query with `bcdc_query_geodata()`: 13 | 14 | When using `bcdc_query_geodata()` with `filter()`, many functions are 15 | translated to a query plan that is passed to and executed on the server - this includes the 16 | CQL Geometry predicates such as `INTERESECTS()`, `CROSSES()`, `BBOX()` 17 | etc, as well as many base R functions. However you sometimes want to 18 | include a function call in your `filter()` statement which should be 19 | evaluated locally - i.e., it's an R function (often an `{sf}` function) 20 | with no equivalent function on the server. Prior to version 0.4.0, 21 | `{bcdata}` did a reasonable (though not perfect) job of detecting R 22 | functions inside a `filter()` statement that needed to be evaluated 23 | locally. In order to align with recommended best practices for 24 | `{dbplyr}` backends, as of v0.4.0, function calls that are to be 25 | evaluated locally now need to be wrapped in `local()`. 26 | 27 | For example, say we want to create a bounding box around two points and 28 | use that box to perform a spatial filter on the remote dataset, to 29 | give us just the set of local greenspaces that exist within that 30 | bounding box. 31 | 32 | ```{r} 33 | #| include: false 34 | Sys.unsetenv("BCDC_KEY") 35 | ``` 36 | 37 | 38 | ```{r} 39 | #| message: false 40 | library(sf) 41 | library(bcdata) 42 | 43 | two_points <- st_sfc(st_point(c(1164434, 368738)), 44 | st_point(c(1203023, 412959)), 45 | crs = 3005) 46 | ``` 47 | 48 | Previously, we could just do this, with `sf::st_bbox()` 49 | embedded in the call: 50 | 51 | ```{r} 52 | #| error: true 53 | #| warning: false 54 | bcdc_query_geodata("local-and-regional-greenspaces") %>% 55 | filter(BBOX(st_bbox(two_points, crs = st_crs(two_points)))) 56 | ``` 57 | 58 | However you must now use `local()` to force local evaluation of 59 | `st_bbox()` on your machine in R, before it is translated 60 | into a query plan to be executed on the server: 61 | 62 | ```{r} 63 | #| warning: false 64 | bcdc_query_geodata("local-and-regional-greenspaces") %>% 65 | filter(BBOX(local(st_bbox(two_points, crs = st_crs(two_points))))) 66 | ``` 67 | 68 | There is another illustration in the ["querying spatial data vignette"](https://bcgov.github.io/bcdata/articles/efficiently-query-spatial-data-in-the-bc-data-catalogue.html#a-note-about-using-local-r-functions-in-constructing-filter-queries). 69 | -------------------------------------------------------------------------------- /tests/testthat/test-search.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | test_that('bcdc_search subsetting works', { 14 | skip_on_cran() 15 | skip_if_net_down() 16 | rec_list <- bcdc_search("Container", n = 5) 17 | expect_s3_class(rec_list, "bcdc_recordlist") 18 | expect_length(rec_list, 5) 19 | shorter <- rec_list[3:5] 20 | expect_s3_class(shorter, "bcdc_recordlist") 21 | expect_length(shorter, 3) 22 | }) 23 | 24 | test_that("process_search_terms works", { 25 | terms <- process_search_terms("a", "b", "c") 26 | expect_equal(terms, "a+b+c") 27 | expect_error(process_search_terms(a = "one"), "should not be named") 28 | }) 29 | 30 | test_that("bcdc_search works with zero results", { 31 | skip_on_cran() 32 | skip_if_net_down() 33 | 34 | res <- bcdc_search("foobarbananas") 35 | expect_s3_class(res, "bcdc_recordlist") 36 | expect_length(res, 0L) 37 | 38 | expect_output(print(res), "returned no results") 39 | }) 40 | 41 | test_that('bcdc_search_facets works', { 42 | skip_on_cran() 43 | skip_if_net_down() 44 | orgs <- bcdc_search_facets("organization") 45 | grps <- bcdc_search_facets("groups") 46 | licences <- bcdc_search_facets("license_id") 47 | expect_s3_class(orgs, "data.frame") 48 | expect_s3_class(grps, "data.frame") 49 | expect_s3_class(licences, "data.frame") 50 | expect_gte(nrow(orgs), 1) 51 | expect_gte(nrow(grps), 1) 52 | expect_gte(nrow(licences), 1) 53 | }) 54 | 55 | test_that('bcdc_list_group_records works', { 56 | skip_on_cran() 57 | skip_if_net_down() 58 | census <- bcdc_list_group_records("census-profiles") 59 | grps <- bcdc_search_facets("groups") 60 | census_count <- grps |> 61 | dplyr::filter(name == "census-profiles") |> 62 | dplyr::pull(count) 63 | expect_s3_class(census, "data.frame") 64 | expect_gte(nrow(census), 1) 65 | expect_equal(nrow(census), census_count) 66 | }) 67 | 68 | test_that('bcdc_list_organization_records works', { 69 | skip_on_cran() 70 | skip_if_net_down() 71 | bcstats <- bcdc_list_organization_records("bc-stats") 72 | orgs <- bcdc_search_facets("organization") 73 | bcstats_count <- orgs |> 74 | dplyr::filter(name == "bc-stats") |> 75 | dplyr::pull(count) 76 | expect_s3_class(bcstats, "data.frame") 77 | expect_gte(nrow(bcstats), 1) 78 | expect_equal(nrow(bcstats), bcstats_count) 79 | }) 80 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: bcdata 2 | Title: Search and Retrieve Data from the BC Data Catalogue 3 | Version: 0.5.1.9000 4 | Authors@R: 5 | c(person(given = "Andy", 6 | family = "Teucher", 7 | role = c("aut", "cre"), 8 | email = "andy.teucher@gmail.com", 9 | comment = c(ORCID = "0000-0002-7840-692X")), 10 | person(given = "Sam", 11 | family = "Albers", 12 | role = c("aut", "ctb"), 13 | email = "sam.albers@gmail.com", 14 | comment = c(ORCID = "0000-0002-9270-7884")), 15 | person(given = "Stephanie", 16 | family = "Hazlitt", 17 | role = c("aut", "ctb"), 18 | email = "stephhazlitt@gmail.com", 19 | comment = c(ORCID = "0000-0002-3161-2304")), 20 | person(given = "Province of British Columbia", 21 | role = "cph")) 22 | Description: Search, query, and download tabular and 23 | 'geospatial' data from the British Columbia Data Catalogue 24 | (). Search catalogue data records 25 | based on keywords, data licence, sector, data format, and B.C. 26 | government organization. View metadata directly in R, download many 27 | data formats, and query 'geospatial' data available via the B.C. 28 | government Web Feature Service ('WFS') using 'dplyr' syntax. 29 | License: Apache License (== 2.0) 30 | URL: https://bcgov.github.io/bcdata/, https://catalogue.data.gov.bc.ca/, https://github.com/bcgov/bcdata/ 31 | BugReports: https://github.com/bcgov/bcdata/issues 32 | Imports: 33 | methods, 34 | utils, 35 | stats, 36 | cli (>= 3.3.0), 37 | DBI (>= 1.1.0), 38 | crul (>= 1.1.0), 39 | dbplyr (>= 2.3.4), 40 | dplyr (>= 1.1.2), 41 | tibble (>= 3.1.0), 42 | glue (>= 1.6.0), 43 | jsonlite (>= 1.6.0), 44 | leaflet (>= 2.1.0), 45 | leaflet.extras (>= 1.0.0), 46 | purrr (>= 0.3), 47 | readr (>= 2.1), 48 | readxl (>= 1.4.0), 49 | rlang (>= 1.0), 50 | sf (>= 1.0), 51 | tidyselect (>= 1.1.0), 52 | xml2 (>= 1.3.0) 53 | Suggests: 54 | covr, 55 | ggplot2, 56 | knitr, 57 | rmarkdown, 58 | testthat (>= 3.0.0), 59 | withr 60 | VignetteBuilder: 61 | knitr 62 | Encoding: UTF-8 63 | Roxygen: list(markdown = TRUE) 64 | RoxygenNote: 7.3.2 65 | Collate: 66 | 'bcdata-package.R' 67 | 'bcdc-get-citation.R' 68 | 'bcdc-web-services.R' 69 | 'bcdc_browse.R' 70 | 'bcdc_options.R' 71 | 'bcdc_search.R' 72 | 'cli.R' 73 | 'cql-geom-predicates.R' 74 | 'cql-translator.R' 75 | 'describe-feature.R' 76 | 'get_data.R' 77 | 'utils-as_tibble.R' 78 | 'utils-classes.R' 79 | 'utils-collect.R' 80 | 'utils-filter.R' 81 | 'utils-is.R' 82 | 'utils-mutate.R' 83 | 'utils-pipe.R' 84 | 'utils-select.R' 85 | 'utils-show-query.R' 86 | 'utils.R' 87 | 'zzz.R' 88 | Config/testthat/edition: 3 89 | -------------------------------------------------------------------------------- /tests/testthat/test-query-geodata.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | test_that("bcdc_query_geodata returns an bcdc_promise object for a valid id OR bcdc_record", { 14 | skip_on_cran() 15 | skip_if_net_down() 16 | # id (character) 17 | bc_airports <- bcdc_query_geodata("bc-airports") 18 | expect_s3_class(bc_airports, "bcdc_promise") 19 | 20 | # bcdc_record 21 | bc_airports_record <- bcdc_get_record("bc-airports") 22 | bc_airports2 <- bcdc_query_geodata(bc_airports_record) 23 | expect_equal(bc_airports, bc_airports2) 24 | 25 | # neither character nor bcdc_record 26 | expect_error( 27 | bcdc_query_geodata(1L), 28 | "No bcdc_query_geodata method for an object of class integer" 29 | ) 30 | }) 31 | 32 | test_that("bcdc_query_geodata returns an object with a query, a cli, the catalogue object, and a df of column names", { 33 | skip_if_net_down() 34 | skip_on_cran() 35 | bc_airports <- bcdc_query_geodata("bc-airports") 36 | expect_type(bc_airports[["query_list"]], "list") 37 | expect_s3_class(bc_airports[["cli"]], "HttpClient") 38 | expect_s3_class(bc_airports[["record"]], "bcdc_record") 39 | expect_s3_class(bc_airports[["cols_df"]], "data.frame") 40 | }) 41 | 42 | 43 | test_that("bcdc_query_geodata returns an object with bcdc_promise class when using filter", { 44 | skip_on_cran() 45 | skip_if_net_down() 46 | bc_eml <- bcdc_query_geodata("bc-environmental-monitoring-locations") %>% 47 | filter(PERMIT_RELATIONSHIP == "DISCHARGE") 48 | expect_s3_class(bc_eml, "bcdc_promise") 49 | }) 50 | 51 | 52 | test_that("bcdc_query_geodata returns an object with bcdc_promise class on record under 10000", { 53 | skip_on_cran() 54 | skip_if_net_down() 55 | airports <- bcdc_query_geodata("bc-airports") 56 | expect_s3_class(airports, "bcdc_promise") 57 | }) 58 | 59 | test_that("bcdc_query_geodata fails when >1 record", { 60 | skip_if_net_down() 61 | skip_on_cran() 62 | expect_error( 63 | bcdc_query_geodata(c( 64 | "bc-airports", 65 | "bc-environmental-monitoring-locations" 66 | )), 67 | "Only one record my be queried at a time" 68 | ) 69 | }) 70 | 71 | test_that("bcdc_query_geodata fails when no wfs available", { 72 | skip_if_net_down() 73 | skip_on_cran() 74 | expect_error( 75 | bcdc_query_geodata("dba6c78a-1bc1-4d4f-b75c-96b5b0e7fd30"), 76 | "No Web Feature Service resource available" 77 | ) 78 | }) 79 | -------------------------------------------------------------------------------- /vignettes/service_documentation.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bcdata Service Documentation" 3 | date: "2021-10-27" 4 | output: 5 | rmarkdown::html_vignette: 6 | md_extensions: [ 7 | "-autolink_bare_uris" 8 | ] 9 | vignette: > 10 | %\VignetteIndexEntry{bcdata Service Documentation} 11 | %\VignetteEngine{knitr::rmarkdown} 12 | %\VignetteEncoding{UTF-8} 13 | --- 14 | 15 | 16 | # DataBC Services used by `bcdata` 17 | 18 | This document is an attempt at a comprehensive list of services and API endpoints accessed by the bcdata R package, as well which return values we rely on from those endpoints. 19 | 20 | ## BC Data Catalogue 21 | 22 | ### API version: 23 | - PROD: `https://catalogue.data.gov.bc.ca/api/3` 24 | - BETA: `https://beta-catalogue.data.gov.bc.ca/api/3` 25 | 26 | ### Endpoints: 27 | - `/action/package_show` 28 | - `/action/package_search` 29 | - `license_id` 30 | - `download_audience` 31 | - `res_format` 32 | - `sector` 33 | - `organization` 34 | - `/action/package_list` 35 | - `/action/group_show` 36 | 37 | ### Response values used: 38 | - package: 39 | - `title` 40 | - `name` 41 | - `id` 42 | - `license_title` 43 | - `type` 44 | - `notes` 45 | - `layer_name` 46 | - `resources` (see below) 47 | 48 | - resource: 49 | - `id` 50 | - `package_id` 51 | - `object_name` 52 | (This is not always the same as the `typeNames` parameter in `resource.url`, as that is sometimes a simplified view - eg., `WHSE_ADMIN_BOUNDARIES.ADM_NR_DISTRICTS_SPG` vs 53 | `WHSE_ADMIN_BOUNDARIES.ADM_NR_DISTRICTS_SP`) 54 | - `details` 55 | - `column_comments` 56 | - `column_name` 57 | - `bcdc_type` (not actually using yet but [may be useful](https://github.com/bcgov/bcdata/pull/283#issuecomment-924442166)) 58 | - `format` 59 | - `resource_storage_location` 60 | - `name` 61 | - `url` 62 | 63 | - group: 64 | - `description` 65 | - `packages` 66 | 67 | ## Web Services 68 | 69 | ### API Version: 70 | 71 | - TEST: `https://test.openmaps.gov.bc.ca` 72 | - DELIVERY: `https://delivery.openmaps.gov.bc.ca` 73 | - PROD: `https://openmaps.gov.bc.ca` 74 | 75 | Endpoints: 76 | 77 | - wfs: `geo/pub/wfs` 78 | - wms: `geo/pub/wms` 79 | 80 | Query Parameters for `geo/pub/wfs`: 81 | 82 | - query is sent in the body of a `POST` request (with `encode = "form"`). If a dataset has > n records (default n = 1000), pagination is used to send sequential requests. Pagination is executed using `count`, `sortBY`, and `startIndex`. 83 | - SERVICE = "WFS" 84 | - VERSION = "2.0.0" 85 | - REQUEST = "GetCapabilities" 86 | - REQUEST = "GetFeature" 87 | - outputFormat = "application/json" 88 | - typeNames (extracted from `resource.url` and compared against `resource.object_name`) 89 | - SRSNAME (default `EPSG:3005`) 90 | - CQL_FILTER 91 | - count 92 | - propertyName 93 | - sortBy 94 | - startIndex 95 | -------------------------------------------------------------------------------- /tests/testthat/test-options.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | test_that("bcdc_options() returns a tibble", { 14 | skip_if_net_down() 15 | skip_on_cran() 16 | opts <- bcdc_options() 17 | expect_s3_class(opts, "tbl_df") 18 | }) 19 | 20 | test_that("bcdata.chunk_limit", { 21 | skip_if_net_down() 22 | skip_on_cran() 23 | withr::with_options(list(bcdata.chunk_limit = 100000), { 24 | expect_error(check_chunk_limit()) 25 | }) 26 | withr::with_options(list(bcdata.chunk_limit = 10), { 27 | expect_true(is.numeric(check_chunk_limit())) 28 | expect_equal(check_chunk_limit(), 10) 29 | }) 30 | }) 31 | 32 | test_that("bcdata.max_package_search_limit works", { 33 | skip_if_net_down() 34 | skip_on_cran() 35 | withr::with_options(list(bcdata.max_package_search_limit = 10), { 36 | bcstats <- bcdc_list_organization_records("bc-stats") 37 | expect_lte(nrow(bcstats), 10) 38 | }) 39 | }) 40 | 41 | test_that("bcdata.max_package_search_facet_limit works", { 42 | skip_if_net_down() 43 | skip_on_cran() 44 | withr::with_options(list(bcdata.max_package_search_facet_limit = 10), { 45 | orgs <- bcdc_search_facets("organization") 46 | expect_lte(nrow(orgs), 10) 47 | }) 48 | }) 49 | 50 | test_that("bcdata.max_group_package_show_limit works", { 51 | skip_if_net_down() 52 | skip_on_cran() 53 | withr::with_options(list(bcdata.max_group_package_show_limit = 10), { 54 | census <- bcdc_list_group_records("census-profiles") 55 | expect_lte(nrow(census), 10) 56 | }) 57 | }) 58 | 59 | test_that("bcdata.single_download_limit is deprecated but works", { 60 | # This can be removed when bcdata.single_download_limit is removed 61 | skip_if_net_down() 62 | skip_on_cran() 63 | withr::local_options(list(bcdata.single_download_limit = 1)) 64 | withr::local_envvar(list(BCDC_KEY = NULL)) # so snapshot not affected by message 65 | expect_s3_class( 66 | bcdc_query_geodata(record = '76b1b7a3-2112-4444-857a-afccf7b20da8'), 67 | "bcdc_promise" 68 | ) 69 | }) 70 | 71 | test_that("bcdata.single_download_limit can be changed", { 72 | # This can be removed when bcdata.single_download_limit is removed 73 | skip_if_net_down() 74 | skip_on_cran() 75 | withr::local_options(list(bcdata.single_download_limit = 13)) 76 | expect_equal(getOption("bcdata.single_download_limit"), 13) 77 | }) 78 | 79 | test_that("bcdc_single_download_limit returns a number", { 80 | skip_on_cran() 81 | skip_if_net_down() 82 | lt <- bcdc_single_download_limit() 83 | expect_type(lt, "integer") 84 | }) 85 | -------------------------------------------------------------------------------- /tests/testthat/test-query-geodata-select.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | test_that("select doesn't remove the geometry column", { 14 | skip_if_net_down() 15 | skip_on_cran() 16 | feat <- bcdc_query_geodata(point_record) %>% 17 | filter(SOURCE_DATA_ID == 455) %>% 18 | select(SOURCE_DATA_ID) %>% 19 | collect() 20 | expect_s3_class(feat, "bcdc_sf") 21 | }) 22 | 23 | test_that("select works when selecting a column that isn't sticky", { 24 | skip_if_net_down() 25 | skip_on_cran() 26 | feat <- bcdc_query_geodata(point_record) %>% 27 | filter(LOCALITY == 'Terrace') %>% 28 | select(DESCRIPTION) %>% 29 | collect() 30 | 31 | expect_true("DESCRIPTION" %in% names(feat)) 32 | }) 33 | 34 | 35 | test_that("select reduces the number of columns when a sticky ", { 36 | skip_if_net_down() 37 | skip_on_cran() 38 | feature_spec <- bcdc_describe_feature(point_record) 39 | ## Columns that can selected, while manually including GEOMETRY col 40 | sticky_cols <- c( 41 | feature_spec[feature_spec$sticky, ]$col_name, 42 | "geometry" 43 | ) 44 | 45 | sub_cols <- bcdc_query_geodata(point_record) %>% 46 | select(BUSINESS_CATEGORY_CLASS) %>% 47 | collect() 48 | 49 | expect_identical(names(sub_cols), sticky_cols) 50 | }) 51 | 52 | test_that("select works with BCGW name", { 53 | skip_on_cran() 54 | skip_if_net_down() 55 | expect_s3_class( 56 | bcdc_query_geodata(bcgw_point_record) %>% 57 | select(AIRPORT_NAME, DESCRIPTION) %>% 58 | collect(), 59 | "sf" 60 | ) 61 | }) 62 | 63 | 64 | test_that("select accept dplyr like column specifications", { 65 | skip_if_net_down() 66 | skip_on_cran() 67 | layer <- bcdc_query_geodata(polygon_record) 68 | wrong_fields <- c('ADMIN_AREA_NAME', 'dummy_col') 69 | correct_fields <- c('ADMIN_AREA_NAME', 'OIC_MO_YEAR') 70 | 71 | ## Most basic select 72 | expect_s3_class(select(layer, ADMIN_AREA_NAME, OIC_MO_YEAR), "bcdc_promise") 73 | ## Using a pre-assigned vector 74 | expect_s3_class(select(layer, all_of(correct_fields)), "bcdc_promise") 75 | ## Throws an error when column doesn't exist 76 | expect_error(select(layer, all_of(wrong_fields))) 77 | expect_s3_class(select(layer, ADMIN_AREA_NAME:OIC_MO_YEAR), "bcdc_promise") 78 | ## Some weird mix 79 | expect_s3_class(select(layer, 'ADMIN_AREA_NAME', OIC_MO_YEAR), "bcdc_promise") 80 | ## Another weird mix 81 | expect_s3_class( 82 | select(layer, c('ADMIN_AREA_NAME', 'OIC_MO_YEAR'), OIC_MO_NUMBER), 83 | "bcdc_promise" 84 | ) 85 | expect_s3_class(select(layer, 1:5), "bcdc_promise") 86 | }) 87 | -------------------------------------------------------------------------------- /R/bcdc_browse.R: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | #' Load the B.C. Data Catalogue URL into an HTML browser 14 | #' 15 | #' This is a wrapper around utils::browseURL with the URL for the B.C. Data Catalogue as 16 | #' the default 17 | #' 18 | #' @inheritParams utils::browseURL 19 | #' @param query Default (NULL) opens a browser to \code{https://catalogue.data.gov.bc.ca}. 20 | #' This argument will also accept a B.C. Data Catalogue record ID or name to take you 21 | #' directly to that page. If the provided ID or name doesn't lead to a valid webpage, 22 | #' bcdc_browse will search the data catalogue for that string. 23 | #' 24 | #' @seealso \code{\link[utils]{browseURL}} 25 | #' @return A browser is opened with the B.C. Data Catalogue URL loaded if the 26 | #' session is interactive. The URL used is returned as a character string. 27 | #' 28 | #' @export 29 | #' 30 | #' @examples 31 | #' \donttest{ 32 | #' ## Take me to the B.C. Data Catalogue home page 33 | #' try( 34 | #' bcdc_browse() 35 | #' ) 36 | #' 37 | #' ## Take me to the B.C. airports catalogue record 38 | #' try( 39 | #' bcdc_browse("bc-airports") 40 | #' ) 41 | #' 42 | #' ## Take me to the B.C. airports catalogue record 43 | #' try( 44 | #' bcdc_browse("76b1b7a3-2112-4444-857a-afccf7b20da8") 45 | #' ) 46 | #' } 47 | bcdc_browse <- function( 48 | query = NULL, 49 | browser = getOption("browser"), 50 | encodeIfNeeded = FALSE 51 | ) { 52 | if (!has_internet()) stop("No access to internet", call. = FALSE) # nocov 53 | 54 | base_url <- catalogue_base_url() 55 | 56 | if (is.null(query)) { 57 | url <- base_url 58 | } else { 59 | ## Check if the record is valid, if not return a query. 60 | # Need to check via HEAD request to the api as the catalogue 61 | # doesn't return a 404 status code. 62 | cli <- bcdc_catalogue_client("action/package_show") 63 | res <- cli$head(query = list(id = query)) 64 | 65 | if (res$status_code == 404) { 66 | stop("The specified record does not exist in the catalogue") 67 | ## NB - previous version would show a catalogue search in the 68 | ## browser, but with new catalogue it doesn't seem possible 69 | ## to set a browser-based catalogue search via url query parameters 70 | # url <- paste0(make_url(base_url, "dataset"), 71 | # "?q=", query) 72 | } 73 | 74 | url <- make_url(catalogue_base_url(), "dataset", query) 75 | } 76 | 77 | ## Facilitates testing 78 | if (interactive()) { 79 | # nocov start 80 | utils::browseURL( 81 | url = url, 82 | browser = browser, 83 | encodeIfNeeded = encodeIfNeeded 84 | ) 85 | # nocov end 86 | } 87 | 88 | invisible(url) 89 | } 90 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method("[",bcdc_recordlist) 4 | S3method(as_tibble,bcdc_promise) 5 | S3method(bcdc_describe_feature,bcdc_record) 6 | S3method(bcdc_describe_feature,character) 7 | S3method(bcdc_describe_feature,default) 8 | S3method(bcdc_get_citation,bcdc_record) 9 | S3method(bcdc_get_citation,character) 10 | S3method(bcdc_get_citation,default) 11 | S3method(bcdc_get_data,bcdc_record) 12 | S3method(bcdc_get_data,character) 13 | S3method(bcdc_get_data,default) 14 | S3method(bcdc_preview,bcdc_record) 15 | S3method(bcdc_preview,character) 16 | S3method(bcdc_preview,default) 17 | S3method(bcdc_query_geodata,bcdc_record) 18 | S3method(bcdc_query_geodata,character) 19 | S3method(bcdc_query_geodata,default) 20 | S3method(bcdc_tidy_resources,bcdc_record) 21 | S3method(bcdc_tidy_resources,character) 22 | S3method(bcdc_tidy_resources,default) 23 | S3method(collect,bcdc_promise) 24 | S3method(dbplyr_edition,wfsConnection) 25 | S3method(filter,bcdc_promise) 26 | S3method(head,bcdc_promise) 27 | S3method(mutate,bcdc_promise) 28 | S3method(names,bcdc_promise) 29 | S3method(print,bcdc_group) 30 | S3method(print,bcdc_promise) 31 | S3method(print,bcdc_query) 32 | S3method(print,bcdc_record) 33 | S3method(print,bcdc_recordlist) 34 | S3method(select,bcdc_promise) 35 | S3method(show_query,bcdc_promise) 36 | S3method(show_query,bcdc_sf) 37 | S3method(sql_translation,wfsConnection) 38 | S3method(tail,bcdc_promise) 39 | export("%>%") 40 | export(BBOX) 41 | export(CONTAINS) 42 | export(CQL) 43 | export(CROSSES) 44 | export(DISJOINT) 45 | export(DWITHIN) 46 | export(EQUALS) 47 | export(INTERSECTS) 48 | export(OVERLAPS) 49 | export(TOUCHES) 50 | export(WITHIN) 51 | export(as_tibble) 52 | export(bcdc_browse) 53 | export(bcdc_check_geom_size) 54 | export(bcdc_describe_feature) 55 | export(bcdc_get_citation) 56 | export(bcdc_get_data) 57 | export(bcdc_get_record) 58 | export(bcdc_list) 59 | export(bcdc_list_group_records) 60 | export(bcdc_list_groups) 61 | export(bcdc_list_organization_records) 62 | export(bcdc_list_organizations) 63 | export(bcdc_options) 64 | export(bcdc_preview) 65 | export(bcdc_query_geodata) 66 | export(bcdc_read_functions) 67 | export(bcdc_search) 68 | export(bcdc_search_facets) 69 | export(bcdc_tidy_resources) 70 | export(collect) 71 | export(filter) 72 | export(mutate) 73 | export(select) 74 | export(show_query) 75 | exportClasses(CQL) 76 | exportClasses(wfsConnection) 77 | exportMethods(dbQuoteIdentifier) 78 | exportMethods(dbQuoteString) 79 | import(DBI) 80 | import(methods) 81 | importFrom(cli,cat_bullet) 82 | importFrom(cli,cat_line) 83 | importFrom(cli,cat_rule) 84 | importFrom(cli,col_blue) 85 | importFrom(cli,col_green) 86 | importFrom(cli,col_red) 87 | importFrom(dbplyr,dbplyr_edition) 88 | importFrom(dbplyr,sql_translation) 89 | importFrom(dplyr,"%>%") 90 | importFrom(dplyr,collect) 91 | importFrom(dplyr,filter) 92 | importFrom(dplyr,mutate) 93 | importFrom(dplyr,select) 94 | importFrom(dplyr,show_query) 95 | importFrom(jsonlite,read_json) 96 | importFrom(methods,setOldClass) 97 | importFrom(readr,read_csv) 98 | importFrom(readr,read_tsv) 99 | importFrom(readxl,read_xls) 100 | importFrom(readxl,read_xlsx) 101 | importFrom(rlang,"%||%") 102 | importFrom(rlang,":=") 103 | importFrom(sf,read_sf) 104 | importFrom(tibble,as_tibble) 105 | importFrom(utils,head) 106 | importFrom(utils,tail) 107 | -------------------------------------------------------------------------------- /inst/sticker/make_sticker.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | library(hexSticker) 14 | library(ggplot2) 15 | library(bcmaps) 16 | library(bcdata) 17 | library(sf) 18 | library(dplyr) 19 | library(rmapshaper) 20 | 21 | ## bc boundary from bcmaps 22 | bc <- bc_bound() %>% ms_simplify(keep = .1) 23 | 24 | ## cities 25 | # city_lines_df <- cities %>% 26 | # st_union() %>% 27 | # st_triangulate(bOnlyEdges = TRUE) %>% 28 | # st_cast("LINESTRING") %>% 29 | # st_sf() %>% 30 | # mutate(length = as.numeric(st_length(.))) %>% 31 | # filter(length < 500000) 32 | # 33 | # p <- ggplot() + 34 | # geom_sf(data = bc, fill = NA, size = 0.2, colour = "grey70") + 35 | # geom_sf(data = city_lines_df, aes(colour = length), size = 0.2) + 36 | # scale_colour_viridis_c(direction = -1, option = "plasma", begin = .3) + 37 | # geom_sf(data = cities, colour = "white", size = 0.01, shape = 20) + 38 | # guides(colour = FALSE) + 39 | # theme_void() + 40 | # theme_transparent() + 41 | # coord_sf(datum = NULL) 42 | 43 | ## schools 44 | schools <- bcdc_query_geodata("schools-k-12-with-francophone-indicators") %>% 45 | collect() 46 | 47 | ## school lines 48 | school_lines_df <- schools %>% 49 | st_union() %>% 50 | st_triangulate(bOnlyEdges = TRUE) %>% 51 | st_cast("LINESTRING") %>% 52 | st_sf() %>% 53 | mutate(length = as.numeric(st_length(.))) %>% 54 | filter(length < 500000) 55 | 56 | ## map of bc + schools + school lines 57 | p <- ggplot() + 58 | geom_sf(data = bc, fill = NA, size = 0.2, colour = "grey70") + 59 | geom_sf(data = school_lines_df, aes(colour = length), size = 0.2) + 60 | scale_colour_viridis_c(direction = -1, option = "plasma", begin = .3) + 61 | geom_sf(data = schools, colour = "white", size = 0.01, shape = 20) + 62 | guides(colour = FALSE) + 63 | theme_void() + 64 | theme_transparent() + 65 | coord_sf(datum = NULL) 66 | 67 | ## fonts 68 | font_path <- switch( 69 | Sys.info()['sysname'], 70 | Darwin = "/Library/Fonts/Microsoft/Century Gothic", 71 | Windows = "C:/WINDOWS/FONTS/GOTHIC.TTF" 72 | ) 73 | 74 | sysfonts::font_add("Century Gothic", font_path) 75 | 76 | ## hex sticker 77 | 78 | write_sticker <- function(p, format) { 79 | sticker( 80 | p, 81 | package = "bcdata", 82 | p_size = 5, # This seems to behave very differently on a Mac vs PC 83 | p_y = 1.6, 84 | p_color = "#F6A97A", 85 | p_family = "Century Gothic", 86 | s_x = 1, 87 | s_y = .9, 88 | s_width = 1.5, 89 | s_height = 1.5, 90 | h_fill = "#29303a", 91 | h_color = "#F6A97A", 92 | filename = file.path(paste0("inst/sticker/bcdata.", format)) 93 | ) 94 | } 95 | 96 | write_sticker(p, "png") 97 | write_sticker(p, "svg") 98 | 99 | # Run: 100 | usethis::use_logo("inst/sticker/bcdata.png") 101 | -------------------------------------------------------------------------------- /tests/testthat/test-utils.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | test_that("check_geom_col_names works", { 14 | col_df_list <- lapply(gml_types(), function(x) { 15 | data.frame(col_name = "SHAPE", remote_col_type = x) 16 | }) 17 | lapply(col_df_list, function(x) { 18 | new_query <- specify_geom_name(x, "DWITHIN({geom_col}, foobar)") 19 | expect_equal(as.character(new_query), "DWITHIN(SHAPE, foobar)") 20 | expect_s3_class(new_query, "sql") 21 | }) 22 | }) 23 | 24 | test_that("get_record_warn_once warns once and only once", { 25 | options("silence_named_get_record_warning" = FALSE) 26 | expect_warning(get_record_warn_once("Hi")) 27 | expect_silent(get_record_warn_once("Hi")) 28 | options("silence_named_get_record_warning" = TRUE) 29 | }) 30 | 31 | test_that("pagination_sort_col works", { 32 | cols_df <- data.frame( 33 | col_name = c("foo", "OBJECTID", "OBJECT_ID", "SEQUENCE_ID", "FEATURE_ID"), 34 | stringsAsFactors = FALSE 35 | ) 36 | expect_equal(pagination_sort_col(cols_df), "OBJECTID") 37 | expect_equal(pagination_sort_col(cols_df[-2, , drop = FALSE]), "OBJECT_ID") 38 | expect_equal( 39 | pagination_sort_col(cols_df[c(-2, -3), , drop = FALSE]), 40 | "SEQUENCE_ID" 41 | ) 42 | expect_warning( 43 | expect_equal(pagination_sort_col(cols_df[1, , drop = FALSE]), "foo") 44 | ) 45 | }) 46 | 47 | test_that("is_whse_object_name works", { 48 | expect_true(is_whse_object_name("BCGW_FOO.BAR_BAZ")) 49 | expect_true(is_whse_object_name("BCGW_FOO1.BAR_BAZ")) 50 | expect_true(is_whse_object_name("BCGW_FOO6.BAR8_BAZ")) 51 | expect_true(is_whse_object_name("BCGW_FOO.BAR9_BAZ")) 52 | expect_false(is_whse_object_name("bcgw_foo.bar_baz")) 53 | expect_false(is_whse_object_name("foo")) 54 | expect_false(is_whse_object_name(structure(list(), class = "bcdc_record"))) 55 | }) 56 | 57 | test_that("bcdc_get_capabilities works", { 58 | skip_on_cran() 59 | skip_if_net_down() 60 | skip_if_no_capabilities() 61 | 62 | old_get_caps <- ._bcdataenv_$get_capabilities_xml 63 | 64 | on.exit( 65 | ._bcdataenv_$get_capabilities_xml <- old_get_caps 66 | ) 67 | 68 | ._bcdataenv_$get_capabilities_xml <- NULL 69 | expect_s3_class(bcdc_get_capabilities(), "xml_document") 70 | expect_equal(bcdc_get_capabilities(), ._bcdataenv_$get_capabilities_xml) 71 | }) 72 | 73 | test_that("make_url works", { 74 | expect_equal( 75 | make_url("https://foo.bar", "blah", "/buzz/", "/home.html"), 76 | "https://foo.bar/blah/buzz/home.html" 77 | ) 78 | expect_equal( 79 | make_url("https://foo.bar/", "blah/", "/buzz/", trailing_slash = TRUE), 80 | "https://foo.bar/blah/buzz/" 81 | ) 82 | }) 83 | 84 | test_that("names_to_lazy_tbl works", { 85 | nms <- letters[1:3] 86 | lazy <- names_to_lazy_tbl(nms) 87 | expect_s3_class(lazy, "tbl_lazy") 88 | expect_equal(lazy$lazy_query$vars, nms) 89 | }) 90 | -------------------------------------------------------------------------------- /man/bcdc_options.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bcdc_options.R 3 | \name{bcdc_options} 4 | \alias{bcdc_options} 5 | \title{Retrieve options used in bcdata, their value if set and the default value.} 6 | \usage{ 7 | bcdc_options() 8 | } 9 | \description{ 10 | This function retrieves bcdata specific options that can be set. These 11 | options can be set using \verb{option(\{name of the option\} = \{value of the option\})}. The default options are purposefully set conservatively to 12 | hopefully ensure successful requests. Resetting these options may result in 13 | failed calls to the data catalogue. Options in R are reset every time R is 14 | re-started. See examples for additional ways to restore your initial state. 15 | } 16 | \details{ 17 | \code{bcdata.max_geom_pred_size} is the maximum size in bytes of an object used 18 | for a geometric operation. Objects that are bigger than this value will have 19 | a bounding box drawn and apply the geometric operation on that simpler 20 | polygon. The \link{bcdc_check_geom_size} function can be used to assess whether a 21 | given spatial object exceeds the value of this option. Users can iteratively 22 | try to increase the maximum geometric predicate size and see if the bcdata 23 | catalogue accepts the request. 24 | 25 | \code{bcdata.chunk_limit} is an option useful when dealing with very large data 26 | sets. When requesting large objects from the catalogue, the request is broken 27 | up into smaller chunks which are then recombined after they've been 28 | downloaded. This is called "pagination". bcdata does this all for you, however by 29 | using this option you can set the size of the chunk requested. On slower 30 | connections, or when having problems, it may help to lower the chunk limit. 31 | 32 | \code{bcdata.max_package_search_limit} is an option for setting the maximum number of 33 | datasets returned when querying by organization with the package_search API endpoint. The 34 | default limit (1000) is purposely set high to return all datasets for a 35 | given organization. 36 | 37 | \code{bcdata.max_package_search_facet_limit} is an option for setting the maximum number of 38 | values returned when querying facet fields with the package_search API endpoint. The 39 | default limit (1000) is purposely set high to return all values for each facet field 40 | ("license_id", "download_audience", "res_format", "publish_state", "organization", "groups"). 41 | 42 | \code{bcdata.max_group_package_show_limit} is an option for setting the maximum number of 43 | datasets returned when querying by group with the group_package_show API endpoint. The 44 | default limit (1000) is purposely set high to return all datasets for a 45 | given group. 46 | 47 | \code{bcdata.single_download_limit} \emph{Deprecated}. This is the maximum number of 48 | records an object can be before forcing a paginated download; it is set by 49 | querying the server capabilities. This option is deprecated and will be 50 | removed in a future release. Use \code{bcdata.chunk_limit} to set a lower value 51 | pagination value. 52 | } 53 | \examples{ 54 | \donttest{ 55 | ## Save initial conditions 56 | try( 57 | original_options <- options() 58 | ) 59 | 60 | ## See initial options 61 | try( 62 | bcdc_options() 63 | ) 64 | 65 | try( 66 | options(bcdata.max_geom_pred_size = 1E6) 67 | ) 68 | 69 | ## See updated options 70 | try( 71 | bcdc_options() 72 | ) 73 | 74 | ## Reset initial conditions 75 | try( 76 | options(original_options) 77 | ) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /tests/testthat/test-describe-feature.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | test_that("Test that bcdc_describe feature returns the correct columns", { 14 | skip_on_cran() 15 | skip_if_net_down() 16 | airport_feature <- bcdc_describe_feature("bc-airports") 17 | expect_identical( 18 | names(airport_feature), 19 | c( 20 | "col_name", 21 | "sticky", 22 | "remote_col_type", 23 | "local_col_type", 24 | "column_comments" 25 | ) 26 | ) 27 | }) 28 | 29 | 30 | test_that("columns are the same as the query", { 31 | skip_on_cran() 32 | skip_if_net_down() 33 | query <- bcdc_query_geodata( 34 | "regional-districts-legally-defined-administrative-areas-of-bc" 35 | ) %>% 36 | filter(ADMIN_AREA_NAME == "Cariboo Regional District") %>% ## just to make the query smaller 37 | collect() 38 | 39 | description <- bcdc_describe_feature( 40 | "regional-districts-legally-defined-administrative-areas-of-bc" 41 | ) 42 | 43 | expect_identical( 44 | sort(setdiff(names(query), "geometry")), 45 | sort(setdiff(unique(description$col_name), "SHAPE")) 46 | ) 47 | }) 48 | 49 | test_that("bcdc_describe_feature accepts a bcdc_record object", { 50 | skip_on_cran() 51 | skip_if_net_down() 52 | airports <- bcdc_get_record('76b1b7a3-2112-4444-857a-afccf7b20da8') 53 | airport_feature <- bcdc_describe_feature(airports) 54 | expect_identical( 55 | names(airport_feature), 56 | c( 57 | "col_name", 58 | "sticky", 59 | "remote_col_type", 60 | "local_col_type", 61 | "column_comments" 62 | ) 63 | ) 64 | }) 65 | 66 | test_that("bcdc_describe_feature accepts BCGW name", { 67 | skip_on_cran() 68 | skip_if_net_down() 69 | skip_if_no_capabilities() 70 | airport_feature <- bcdc_describe_feature( 71 | "WHSE_IMAGERY_AND_BASE_MAPS.GSR_AIRPORTS_SVW" 72 | ) 73 | expect_identical( 74 | names(airport_feature), 75 | c( 76 | "col_name", 77 | "sticky", 78 | "remote_col_type", 79 | "local_col_type", 80 | "column_comments" 81 | ) 82 | ) 83 | }) 84 | 85 | test_that("bcdc_describe_feature fails on unsupported classes", { 86 | skip_on_cran() 87 | skip_if_net_down() 88 | expect_error(bcdc_describe_feature(1L)) 89 | expect_error(bcdc_describe_feature(list(a = 1))) 90 | }) 91 | 92 | test_that("bcdc_describe_feature fails with non-wfs record", { 93 | skip_if_net_down() 94 | skip_on_cran() 95 | skip_if_no_capabilities() 96 | expect_error( 97 | bcdc_describe_feature("dba6c78a-1bc1-4d4f-b75c-96b5b0e7fd30"), 98 | "No WFS resource available for this data set" 99 | ) 100 | }) 101 | 102 | test_that("bcdc_get_wfs_records works", { 103 | skip_if_net_down() 104 | skip_on_cran() 105 | skip_if_no_capabilities() 106 | 107 | wfs_records <- bcdc_get_wfs_records() 108 | 109 | expect_equal(names(wfs_records), c("whse_name", "title", "cat_url")) 110 | expect_true(nrow(wfs_records) > 0L) 111 | lapply(wfs_records, function(x) { 112 | expect_true(any(nzchar(x, keepNA = TRUE)) & any(!is.na(x))) 113 | }) 114 | }) 115 | -------------------------------------------------------------------------------- /R/bcdc-get-citation.R: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | #' Generate a bibentry from a Data Catalogue Record 14 | #' 15 | #' Generate a "TechReport" bibentry object directly from a catalogue record. 16 | #' The primary use of this function is as a helper to create a `.bib` file for use 17 | #' in reference management software to cite data from the B.C. Data Catalogue. 18 | #' This function is likely to be starting place for this process and manual 19 | #' adjustment will often be needed. The bibentries are not designed to be 20 | #' authoritative and may not reflect all fields required for individual 21 | #' citation requirements. 22 | #' 23 | #' 24 | #' @param record either a `bcdc_record` object (from the result of `bcdc_get_record()`), 25 | #' a character string denoting the name or ID of a resource (or the URL) 26 | #' 27 | #' It is advised to use the permanent ID for a record rather than the 28 | #' human-readable name to guard against future name changes of the record. 29 | #' If you use the human-readable name a warning will be issued once per 30 | #' session. You can silence these warnings altogether by setting an option: 31 | #' `options("silence_named_get_data_warning" = TRUE)` - which you can set 32 | #' in your .Rprofile file so the option persists across sessions. 33 | #' 34 | #' @seealso [utils::bibentry()] 35 | #' 36 | #' @examples 37 | #' 38 | #' try( 39 | #' bcdc_get_citation("76b1b7a3-2112-4444-857a-afccf7b20da8") 40 | #' ) 41 | #' 42 | #' ## Or directly on a record object 43 | #' try( 44 | #' bcdc_get_citation(bcdc_get_record("76b1b7a3-2112-4444-857a-afccf7b20da8")) 45 | #' ) 46 | #' @export 47 | bcdc_get_citation <- function(record) { 48 | if (!has_internet()) stop("No access to internet", call. = FALSE) # nocov 49 | UseMethod("bcdc_get_citation") 50 | } 51 | 52 | #' @export 53 | bcdc_get_citation.default <- function(record) { 54 | stop( 55 | "No bcdc_get_citation method for an object of class ", 56 | class(record), 57 | call. = FALSE 58 | ) 59 | } 60 | 61 | #' @export 62 | bcdc_get_citation.character <- function(record) { 63 | if (grepl("/resource/", record)) { 64 | # A full url was passed including record and resource compenents. 65 | # Grab the resource id and strip it off the url 66 | resource <- slug_from_url(record) 67 | record <- gsub("/resource/.+", "", record) 68 | } 69 | 70 | rec <- bcdc_get_record(record) 71 | 72 | bcdc_get_citation(rec) 73 | } 74 | 75 | #' @export 76 | bcdc_get_citation.bcdc_record <- function(record) { 77 | bib_rec <- utils::bibentry( 78 | bibtype = "techreport", 79 | title = record$title, 80 | author = utils::person(record$organization$title), 81 | address = clean_org_name(record), 82 | institution = "Province of British Columbia", 83 | year = format(as.Date(record$record_last_modified), "%Y"), 84 | howpublished = paste0("Record accessed ", Sys.Date()), 85 | url = paste0(catalogue_base_url(), "dataset/", record$id), 86 | note = record$license_title 87 | ) 88 | 89 | structure(bib_rec, class = c("citation", setdiff(class(bib_rec), "citation"))) 90 | } 91 | 92 | clean_org_name <- function(rec) { 93 | name <- vapply(rec$contacts, function(x) x$name, FUN.VALUE = character(1)) 94 | name <- trimws(name) 95 | name <- paste0(name, collapse = ", ") 96 | gsub(",([^,]*)$", " &\\1", name) 97 | } 98 | -------------------------------------------------------------------------------- /tests/testthat/test-cql-string.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | suppressPackageStartupMessages(library(sf, quietly = TRUE)) 14 | 15 | the_geom <- st_sf(st_sfc(st_point(c(1, 1)))) 16 | 17 | test_that("bcdc_cql_string fails when an invalid arguments are given", { 18 | expect_error(bcdc_cql_string(the_geom, "FOO")) 19 | expect_error(bcdc_cql_string(quakes, "DWITHIN")) 20 | }) 21 | 22 | test_that("bcdc_cql_string fails when used on an uncollected (promise) object", { 23 | expect_error( 24 | bcdc_cql_string(structure(list(), class = "bcdc_promise")), 25 | "you need to use collect" 26 | ) 27 | }) 28 | 29 | test_that("CQL function works", { 30 | expect_s3_class(CQL("SELECT * FROM foo;"), c("CQL", "SQL")) 31 | }) 32 | 33 | test_that("All cql geom predicate functions work", { 34 | single_arg_functions <- c( 35 | "EQUALS", 36 | "DISJOINT", 37 | "INTERSECTS", 38 | "TOUCHES", 39 | "CROSSES", 40 | "WITHIN", 41 | "CONTAINS", 42 | "OVERLAPS" 43 | ) 44 | for (f in single_arg_functions) { 45 | expect_equal( 46 | do.call(f, list(the_geom)), 47 | CQL(paste0(f, "({geom_name}, POINT (1 1))")) 48 | ) 49 | } 50 | expect_equal( 51 | DWITHIN(the_geom, 1), #default units meters 52 | CQL("DWITHIN({geom_name}, POINT (1 1), 1, meters)") 53 | ) 54 | expect_equal( 55 | DWITHIN(the_geom, 1, "meters"), 56 | CQL("DWITHIN({geom_name}, POINT (1 1), 1, meters)") 57 | ) 58 | expect_equal( 59 | BEYOND(the_geom, 1, "feet"), 60 | CQL("BEYOND({geom_name}, POINT (1 1), 1, feet)") 61 | ) 62 | expect_equal( 63 | RELATE(the_geom, "*********"), 64 | CQL("RELATE({geom_name}, POINT (1 1), *********)") 65 | ) 66 | expect_equal( 67 | BBOX(c(1, 2, 1, 2)), 68 | CQL("BBOX({geom_name}, 1, 2, 1, 2)") 69 | ) 70 | expect_equal( 71 | BBOX(c(1, 2, 1, 2), crs = 'EPSG:4326'), 72 | CQL("BBOX({geom_name}, 1, 2, 1, 2, 'EPSG:4326')") 73 | ) 74 | expect_equal( 75 | BBOX(c(1, 2, 1, 2), crs = 4326), 76 | CQL("BBOX({geom_name}, 1, 2, 1, 2, 'EPSG:4326')") 77 | ) 78 | }) 79 | 80 | test_that("CQL functions fail correctly", { 81 | expect_error(EQUALS(quakes), "x is not a valid sf object") 82 | expect_error(BEYOND(the_geom, "five"), "'distance' must be numeric") 83 | expect_error(DWITHIN(the_geom, 5, "fathoms"), "'arg' should be one of") 84 | expect_error(DWITHIN(the_geom, "10", "meters"), "must be numeric") 85 | expect_error(RELATE(the_geom, "********"), "pattern") # 8 characters 86 | expect_error(RELATE(the_geom, "********5"), "pattern") # invalid character 87 | expect_error(RELATE(the_geom, rep("TTTTTTTTT", 2)), "pattern") # > length 1 88 | expect_error(BBOX(c(1, 2, 3)), "numeric vector") 89 | expect_error(BBOX(c("1", "2", "3", "4")), "numeric vector") 90 | expect_error( 91 | BBOX(c(1, 2, 3, 4), crs = c("EPSG:4326", "EPSG:3005")), 92 | "must be a character string" 93 | ) 94 | }) 95 | 96 | test_that("unsupported aggregation functions fail correctly", { 97 | expect_error( 98 | filter( 99 | structure(list(cols_df = list(col_name = "x")), class = "bcdc_promise"), 100 | mean(x) > 5 101 | ), 102 | "not supported by this database" 103 | ) 104 | }) 105 | 106 | test_that("passing an non-existent object to a geom predicate", { 107 | skip_if_net_down() 108 | skip_on_cran() 109 | expect_error( 110 | bcdc_query_geodata("6a2fea1b-0cc4-4fc2-8017-eaf755d516da") %>% 111 | filter(INTERSECTS(districts)), 112 | 'not found' 113 | ) 114 | }) 115 | -------------------------------------------------------------------------------- /man/bcdc_query_geodata.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bcdc-web-services.R 3 | \name{bcdc_query_geodata} 4 | \alias{bcdc_query_geodata} 5 | \title{Query data from the B.C. Web Feature Service} 6 | \usage{ 7 | bcdc_query_geodata(record, crs = 3005) 8 | } 9 | \arguments{ 10 | \item{record}{either a \code{bcdc_record} object (from the result of \code{bcdc_get_record()}), 11 | a character string denoting the name or ID of a resource (or the URL) or a BC Geographic 12 | Warehouse (BCGW) name. 13 | 14 | It is advised to use the permanent ID for a record or the BCGW name rather than the 15 | human-readable name to guard against future name changes of the record. 16 | If you use the human-readable name a warning will be issued once per 17 | session. You can silence these warnings altogether by setting an option: 18 | \code{options("silence_named_get_data_warning" = TRUE)} - which you can set 19 | in your .Rprofile file so the option persists across sessions.} 20 | 21 | \item{crs}{the epsg code for the coordinate reference system. Defaults to 22 | \code{3005} (B.C. Albers). See https://epsg.io.} 23 | } 24 | \value{ 25 | A \code{bcdc_promise} object. This object includes all of the information 26 | required to retrieve the requested data. In order to get the actual data as 27 | an \code{sf} object, you need to run \code{\link[=collect]{collect()}} on the \code{bcdc_promise}. 28 | } 29 | \description{ 30 | Queries features from the B.C. Web Feature Service. See 31 | \code{\link[=bcdc_tidy_resources]{bcdc_tidy_resources()}} - if a resource has a value of 32 | \code{"wms"} in the \code{format} column it is available as a Web 33 | Feature Service, and you can query and download it 34 | using \code{bcdc_query_geodata()}. The response will be 35 | paginated if the number of features is greater than that allowed by the server. 36 | Please see \code{\link[=bcdc_options]{bcdc_options()}} for defaults and more 37 | information. 38 | } 39 | \details{ 40 | Note that this function doesn't actually return the data, but rather an 41 | object of class \code{bcdc_promise}, which includes all of the information 42 | required to retrieve the requested data. In order to get the actual data as 43 | an \code{sf} object, you need to run \code{\link[=collect]{collect()}} on the \code{bcdc_promise}. This 44 | allows further refining the call to \code{bcdc_query_geodata()} with \code{\link[=filter]{filter()}} 45 | and/or \code{\link[=select]{select()}} statements before pulling down the actual data as an \code{sf} 46 | object with \code{\link[=collect]{collect()}}. See examples. 47 | } 48 | \examples{ 49 | 50 | \donttest{ 51 | # Returns a bcdc_promise, which can be further refined using filter/select: 52 | try( 53 | res <- bcdc_query_geodata("bc-airports", crs = 3857) 54 | ) 55 | 56 | # To obtain the actual data as an sf object, collect() must be called: 57 | try( 58 | res <- bcdc_query_geodata("bc-airports", crs = 3857) \%>\% 59 | filter(PHYSICAL_ADDRESS == 'Victoria, BC') \%>\% 60 | collect() 61 | ) 62 | 63 | # To query based on partial matches, use \%LIKE\%: 64 | try( 65 | res <- bcdc_query_geodata("bc-airports") \%>\% 66 | filter(PHYSICAL_ADDRESS \%LIKE\% 'Vict\%') 67 | ) 68 | 69 | # To query using \%IN\% 70 | try( 71 | res <- bcdc_query_geodata("bc-airports") \%>\% 72 | filter( 73 | AIRPORT_NAME \%IN\% 74 | c( 75 | "Victoria Harbour (Camel Point) Heliport", 76 | "Victoria Harbour (Shoal Point) Heliport" 77 | ) 78 | ) \%>\% 79 | collect() 80 | ) 81 | 82 | 83 | try( 84 | res <- bcdc_query_geodata("groundwater-wells") \%>\% 85 | filter(OBSERVATION_WELL_NUMBER == "108") \%>\% 86 | select(WELL_TAG_NUMBER, INTENDED_WATER_USE) \%>\% 87 | collect() 88 | ) 89 | 90 | ## A moderately large layer 91 | try( 92 | res <- bcdc_query_geodata("bc-environmental-monitoring-locations") 93 | ) 94 | 95 | try( 96 | res <- bcdc_query_geodata("bc-environmental-monitoring-locations") \%>\% 97 | filter(PERMIT_RELATIONSHIP == "DISCHARGE") 98 | ) 99 | 100 | 101 | ## A very large layer 102 | try( 103 | res <- bcdc_query_geodata("terrestrial-protected-areas-representation-by-biogeoclimatic-unit") 104 | ) 105 | 106 | ## Using a BCGW name 107 | try( 108 | res <- bcdc_query_geodata("WHSE_IMAGERY_AND_BASE_MAPS.GSR_AIRPORTS_SVW") 109 | ) 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /vignettes/local-filter.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Update to `filter()` behaviour in bcdata v0.4.0" 3 | date: "2024-12-11" 4 | output: rmarkdown::html_vignette 5 | vignette: > 6 | %\VignetteIndexEntry{Update to `filter()` behaviour in bcdata v0.4.0} 7 | %\VignetteEngine{knitr::rmarkdown} 8 | %\VignetteEncoding{UTF-8} 9 | --- 10 | 11 | This vignette describes a change in `{bcdata}` v0.4.0 related to 12 | using locally-executed functions in a `filter()` query with `bcdc_query_geodata()`: 13 | 14 | When using `bcdc_query_geodata()` with `filter()`, many functions are 15 | translated to a query plan that is passed to and executed on the server - this includes the 16 | CQL Geometry predicates such as `INTERESECTS()`, `CROSSES()`, `BBOX()` 17 | etc, as well as many base R functions. However you sometimes want to 18 | include a function call in your `filter()` statement which should be 19 | evaluated locally - i.e., it's an R function (often an `{sf}` function) 20 | with no equivalent function on the server. Prior to version 0.4.0, 21 | `{bcdata}` did a reasonable (though not perfect) job of detecting R 22 | functions inside a `filter()` statement that needed to be evaluated 23 | locally. In order to align with recommended best practices for 24 | `{dbplyr}` backends, as of v0.4.0, function calls that are to be 25 | evaluated locally now need to be wrapped in `local()`. 26 | 27 | For example, say we want to create a bounding box around two points and 28 | use that box to perform a spatial filter on the remote dataset, to 29 | give us just the set of local greenspaces that exist within that 30 | bounding box. 31 | 32 | 33 | 34 | 35 | 36 | ``` r 37 | library(sf) 38 | library(bcdata) 39 | 40 | two_points <- st_sfc(st_point(c(1164434, 368738)), 41 | st_point(c(1203023, 412959)), 42 | crs = 3005) 43 | ``` 44 | 45 | Previously, we could just do this, with `sf::st_bbox()` 46 | embedded in the call: 47 | 48 | 49 | ``` r 50 | bcdc_query_geodata("local-and-regional-greenspaces") %>% 51 | filter(BBOX(st_bbox(two_points, crs = st_crs(two_points)))) 52 | ``` 53 | 54 | ``` 55 | ## Error: Error : Cannot translate a object to SQL. 56 | ## ℹ Do you want to force evaluation in R with (e.g.) `!!x` or `local(x)`? 57 | ``` 58 | 59 | However you must now use `local()` to force local evaluation of 60 | `st_bbox()` on your machine in R, before it is translated 61 | into a query plan to be executed on the server: 62 | 63 | 64 | ``` r 65 | bcdc_query_geodata("local-and-regional-greenspaces") %>% 66 | filter(BBOX(local(st_bbox(two_points, crs = st_crs(two_points))))) 67 | ``` 68 | 69 | ``` 70 | ## Querying 'local-and-regional-greenspaces' record 71 | ## • Using collect() on this object will return 1158 features and 19 fields 72 | ## • At most six rows of the record are printed here 73 | ## ──────────────────────────────────────────────────────────────────────────────────────────────────── 74 | ## Simple feature collection with 6 features and 19 fields 75 | ## Geometry type: POLYGON 76 | ## Dimension: XY 77 | ## Bounding box: xmin: 1200113 ymin: 385903.5 xmax: 1202130 ymax: 388026 78 | ## Projected CRS: NAD83 / BC Albers 79 | ## # A tibble: 6 × 20 80 | ## id LOCAL_REG_GREENSPACE…¹ PARK_NAME PARK_TYPE PARK_PRIMARY_USE REGIONAL_DISTRICT MUNICIPALITY 81 | ## 82 | ## 1 WHSE_B… 689 Cranford… Local Water Access Capital District of… 83 | ## 2 WHSE_B… 634 Local Water Access Capital District of… 84 | ## 3 WHSE_B… 725 Local Water Access Capital District of… 85 | ## 4 WHSE_B… 665 Konukson… Local Green Space Capital District of… 86 | ## 5 WHSE_B… 622 Local Trail Capital District of… 87 | ## 6 WHSE_B… 698 Local Water Access Capital District of… 88 | ## # ℹ abbreviated name: ¹​LOCAL_REG_GREENSPACE_ID 89 | ## # ℹ 13 more variables: CIVIC_NUMBER , CIVIC_NUMBER_SUFFIX , STREET_NAME , 90 | ## # LATITUDE , LONGITUDE , WHEN_UPDATED , WEBSITE_URL , 91 | ## # LICENCE_COMMENTS , FEATURE_AREA_SQM , FEATURE_LENGTH_M , OBJECTID , 92 | ## # SE_ANNO_CAD_DATA , geometry 93 | ``` 94 | 95 | There is another illustration in the ["querying spatial data vignette"](https://bcgov.github.io/bcdata/articles/efficiently-query-spatial-data-in-the-bc-data-catalogue.html#a-note-about-using-local-r-functions-in-constructing-filter-queries). 96 | -------------------------------------------------------------------------------- /man/bcdc_get_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/get_data.R 3 | \name{bcdc_get_data} 4 | \alias{bcdc_get_data} 5 | \title{Download and read a resource from a B.C. Data Catalogue record} 6 | \usage{ 7 | bcdc_get_data(record, resource = NULL, verbose = TRUE, ...) 8 | } 9 | \arguments{ 10 | \item{record}{either a \code{bcdc_record} object (from the result of \code{bcdc_get_record()}), 11 | a character string denoting the name or ID of a resource (or the URL) or a BC Geographic 12 | Warehouse (BCGW) name. 13 | 14 | It is advised to use the permanent ID for a record or the BCGW name rather than the 15 | human-readable name to guard against future name changes of the record. 16 | If you use the human-readable name a warning will be issued once per 17 | session. You can silence these warnings altogether by setting an option: 18 | \code{options("silence_named_get_data_warning" = TRUE)} - which you can set 19 | in your .Rprofile file so the option persists across sessions.} 20 | 21 | \item{resource}{optional argument used when there are multiple data files 22 | within the same record. See examples.} 23 | 24 | \item{verbose}{When more than one resource is available for a record, 25 | should extra information about those resources be printed to the console? 26 | Default \code{TRUE}} 27 | 28 | \item{...}{arguments passed to other functions. Tabular data is passed to a function to handle 29 | the import based on the file extension. \code{\link[=bcdc_read_functions]{bcdc_read_functions()}} provides details on which functions 30 | handle the data import. You can then use this information to look at the help pages of those functions. 31 | See the examples for a workflow that illustrates this process. 32 | For spatial Web Feature Service data the \code{...} arguments are passed to \code{\link[=bcdc_query_geodata]{bcdc_query_geodata()}}.} 33 | } 34 | \value{ 35 | An object of a type relevant to the resource (usually a tibble or an sf object, a list if the resource is a json file) 36 | } 37 | \description{ 38 | Download and read a resource from a B.C. Data Catalogue record 39 | } 40 | \examples{ 41 | \donttest{ 42 | # Using the record and resource ID: 43 | try( 44 | bcdc_get_data(record = '76b1b7a3-2112-4444-857a-afccf7b20da8', 45 | resource = '4d0377d9-e8a1-429b-824f-0ce8f363512c') 46 | ) 47 | 48 | try( 49 | bcdc_get_data('1d21922b-ec4f-42e5-8f6b-bf320a286157') 50 | ) 51 | 52 | # Using a `bcdc_record` object obtained from `bcdc_get_record`: 53 | try( 54 | record <- bcdc_get_record('1d21922b-ec4f-42e5-8f6b-bf320a286157') 55 | ) 56 | 57 | try( 58 | bcdc_get_data(record) 59 | ) 60 | 61 | # Using a BCGW name 62 | try( 63 | bcdc_get_data("WHSE_IMAGERY_AND_BASE_MAPS.GSR_AIRPORTS_SVW") 64 | ) 65 | 66 | # Using sf's sql querying ability 67 | try( 68 | bcdc_get_data( 69 | record = '30aeb5c1-4285-46c8-b60b-15b1a6f4258b', 70 | resource = '3d72cf36-ab53-4a2a-9988-a883d7488384', 71 | layer = 'BC_Boundary_Terrestrial_Line', 72 | query = "SELECT SHAPE_Length, geom FROM BC_Boundary_Terrestrial_Line WHERE SHAPE_Length < 100" 73 | ) 74 | ) 75 | 76 | ## Example of correcting import problems 77 | 78 | ## Some initial problems reading in the data 79 | try( 80 | bcdc_get_data('d7e6c8c7-052f-4f06-b178-74c02c243ea4') 81 | ) 82 | 83 | ## From bcdc_get_record we realize that the data is in xlsx format 84 | try( 85 | bcdc_get_record('8620ce82-4943-43c4-9932-40730a0255d6') 86 | ) 87 | 88 | ## bcdc_read_functions let's us know that bcdata 89 | ## uses readxl::read_excel to import xlsx files 90 | try( 91 | bcdc_read_functions() 92 | ) 93 | 94 | ## bcdata let's you know that this resource has 95 | ## multiple worksheets 96 | try( 97 | bcdc_get_data('8620ce82-4943-43c4-9932-40730a0255d6') 98 | ) 99 | 100 | ## we can control what is read in from an excel file 101 | ## using arguments from readxl::read_excel 102 | try( 103 | bcdc_get_data('8620ce82-4943-43c4-9932-40730a0255d6', sheet = 'Regional Districts') 104 | ) 105 | } 106 | 107 | ## Pass an argument through to a read_* function 108 | 109 | try( 110 | bcdc_get_data(record = "a2a2130b-e853-49e8-9b30-1d0c735aa3d9", 111 | resource = "0b9e7d31-91ff-4146-a473-106a3b301964") 112 | ) 113 | 114 | ## we can control some properties of the list object returned by 115 | ## jsonlite::read_json by setting simplifyVector = TRUE or 116 | ## simplifyDataframe = TRUE 117 | try( 118 | bcdc_get_data(record = "a2a2130b-e853-49e8-9b30-1d0c735aa3d9", 119 | resource = "0b9e7d31-91ff-4146-a473-106a3b301964", 120 | simplifyVector = TRUE) 121 | ) 122 | } 123 | -------------------------------------------------------------------------------- /pkgdown/assets/bc_sans/LICENSE_OFL: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Google Inc., copyright (c) 2019, Province of B.C. 2019 2 | 3 | This Font Software is licensed under the SIL Open Font License, 4 | Version 1.1. 5 | 6 | This license is copied below, and is also available with a FAQ at: 7 | http://scripts.sil.org/OFL 8 | 9 | ----------------------------------------------------------- 10 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 11 | ----------------------------------------------------------- 12 | 13 | PREAMBLE 14 | The goals of the Open Font License (OFL) are to stimulate worldwide 15 | development of collaborative font projects, to support the font 16 | creation efforts of academic and linguistic communities, and to 17 | provide a free and open framework in which fonts may be shared and 18 | improved in partnership with others. 19 | 20 | The OFL allows the licensed fonts to be used, studied, modified and 21 | redistributed freely as long as they are not sold by themselves. The 22 | fonts, including any derivative works, can be bundled, embedded, 23 | redistributed and/or sold with any software provided that any reserved 24 | names are not used by derivative works. The fonts and derivatives, 25 | however, cannot be released under any other type of license. The 26 | requirement for fonts to remain under this license does not apply to 27 | any document created using the fonts or their derivatives. 28 | 29 | DEFINITIONS 30 | "Font Software" refers to the set of files released by the Copyright 31 | Holder(s) under this license and clearly marked as such. This may 32 | include source files, build scripts and documentation. 33 | 34 | "Reserved Font Name" refers to any names specified as such after the 35 | copyright statement(s). 36 | 37 | "Original Version" refers to the collection of Font Software 38 | components as distributed by the Copyright Holder(s). 39 | 40 | "Modified Version" refers to any derivative made by adding to, 41 | deleting, or substituting -- in part or in whole -- any of the 42 | components of the Original Version, by changing formats or by porting 43 | the Font Software to a new environment. 44 | 45 | "Author" refers to any designer, engineer, programmer, technical 46 | writer or other person who contributed to the Font Software. 47 | 48 | PERMISSION & CONDITIONS 49 | Permission is hereby granted, free of charge, to any person obtaining 50 | a copy of the Font Software, to use, study, copy, merge, embed, 51 | modify, redistribute, and sell modified and unmodified copies of the 52 | Font Software, subject to the following conditions: 53 | 54 | 1) Neither the Font Software nor any of its individual components, in 55 | Original or Modified Versions, may be sold by itself. 56 | 57 | 2) Original or Modified Versions of the Font Software may be bundled, 58 | redistributed and/or sold with any software, provided that each copy 59 | contains the above copyright notice and this license. These can be 60 | included either as stand-alone text files, human-readable headers or 61 | in the appropriate machine-readable metadata fields within text or 62 | binary files as long as those fields can be easily viewed by the user. 63 | 64 | 3) No Modified Version of the Font Software may use the Reserved Font 65 | Name(s) unless explicit written permission is granted by the 66 | corresponding Copyright Holder. This restriction only applies to the 67 | primary font name as presented to the users. 68 | 69 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 70 | Software shall not be used to promote, endorse or advertise any 71 | Modified Version, except to acknowledge the contribution(s) of the 72 | Copyright Holder(s) and the Author(s) or with their explicit written 73 | permission. 74 | 75 | 5) The Font Software, modified or unmodified, in part or in whole, 76 | must be distributed entirely under this license, and must not be 77 | distributed under any other license. The requirement for fonts to 78 | remain under this license does not apply to any document created using 79 | the Font Software. 80 | 81 | TERMINATION 82 | This license becomes null and void if any of the above conditions are 83 | not met. 84 | 85 | DISCLAIMER 86 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 87 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 88 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 89 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 90 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 91 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 92 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 93 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 94 | OTHER DEALINGS IN THE FONT SOFTWARE. 95 | -------------------------------------------------------------------------------- /tests/testthat/test-query-geodata-collect.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | test_that("bcdc_query_geodata collects an sf object for a valid id", { 14 | skip_on_cran() 15 | skip_if_net_down() 16 | bc_airports <- bcdc_query_geodata("bc-airports") %>% collect() 17 | expect_s3_class(bc_airports, "sf") 18 | expect_equal(attr(bc_airports, "sf_column"), "geometry") 19 | }) 20 | 21 | test_that("bcdc_query_geodata collects using as_tibble", { 22 | skip_on_cran() 23 | skip_if_net_down() 24 | bc_airports <- bcdc_query_geodata("bc-airports") %>% as_tibble() 25 | expect_s3_class(bc_airports, "sf") 26 | expect_equal(attr(bc_airports, "sf_column"), "geometry") 27 | }) 28 | 29 | test_that("bcdc_query_geodata succeeds with a records over 10000 rows", { 30 | skip_on_cran() 31 | skip_if_net_down() 32 | skip("Skipping the BEC test, though available for testing") 33 | expect_s3_class( 34 | collect( 35 | bcdc_query_geodata( 36 | "terrestrial-protected-areas-representation-by-biogeoclimatic-unit" 37 | ) 38 | ), 39 | "bcdc_sf" 40 | ) 41 | }) 42 | 43 | 44 | test_that("bcdc_query_geodata works with slug and full url using collect", { 45 | skip_on_cran() 46 | skip_if_net_down() 47 | expect_s3_class( 48 | ret1 <- bcdc_query_geodata( 49 | glue::glue("{catalogue_base_url()}/dataset/bc-airports") 50 | ) %>% 51 | collect(), 52 | "sf" 53 | ) 54 | expect_s3_class( 55 | ret2 <- bcdc_query_geodata("bc-airports") %>% collect(), 56 | "sf" 57 | ) 58 | expect_s3_class( 59 | ret3 <- bcdc_query_geodata( 60 | glue::glue( 61 | "{catalogue_base_url()}/dataset/76b1b7a3-2112-4444-857a-afccf7b20da8" 62 | ) 63 | ) %>% 64 | collect(), 65 | "sf" 66 | ) 67 | expect_s3_class( 68 | ret4 <- bcdc_query_geodata("76b1b7a3-2112-4444-857a-afccf7b20da8") %>% 69 | collect(), 70 | "sf" 71 | ) 72 | expect_s3_class( 73 | ret5 <- bcdc_query_geodata( 74 | glue::glue( 75 | "{catalogue_base_url()}/dataset/76b1b7a3-2112-4444-857a-afccf7b20da8/resource/4d0377d9-e8a1-429b-824f-0ce8f363512c" 76 | ) 77 | ) %>% 78 | collect(), 79 | "sf" 80 | ) 81 | 82 | for (x in list(ret2, ret3, ret4, ret5)) { 83 | expect_equal(dim(x), dim(ret1)) 84 | expect_equal(names(x), names(ret1)) 85 | } 86 | }) 87 | 88 | 89 | test_that("bcdc_query_geodata works with spatial data that have SHAPE for the geom", { 90 | ## View metadata to see that geom is SHAPE 91 | ## bcdc_browse("bc-wildfire-fire-perimeters-historical") 92 | skip_on_cran() 93 | skip_if_net_down() 94 | crd <- bcdc_query_geodata( 95 | "regional-districts-legally-defined-administrative-areas-of-bc" 96 | ) %>% 97 | filter(ADMIN_AREA_NAME == "Cariboo Regional District") %>% 98 | collect() 99 | 100 | ret1 <- suppressWarnings( 101 | bcdc_query_geodata("22c7cb44-1463-48f7-8e47-88857f207702") %>% 102 | filter(FIRE_YEAR == 2000, FIRE_CAUSE == "Person", INTERSECTS(crd)) %>% 103 | collect() 104 | ) 105 | expect_s3_class(ret1, "sf") 106 | }) 107 | 108 | test_that("collect() returns a bcdc_sf object", { 109 | skip_on_cran() 110 | skip_if_net_down() 111 | sf_obj <- bcdc_query_geodata("76b1b7a3-2112-4444-857a-afccf7b20da8") %>% 112 | filter(LOCALITY == "Terrace") %>% 113 | select(LATITUDE) %>% 114 | collect() 115 | expect_s3_class(sf_obj, "bcdc_sf") 116 | }) 117 | 118 | test_that("bcdc_sf objects has attributes", { 119 | skip_on_cran() 120 | skip_if_net_down() 121 | sf_obj <- bcdc_query_geodata("76b1b7a3-2112-4444-857a-afccf7b20da8") %>% 122 | filter(LOCALITY == "Terrace") %>% 123 | select(LATITUDE) %>% 124 | collect() 125 | 126 | expect_identical( 127 | names(attributes(sf_obj)), 128 | c( 129 | "names", 130 | "row.names", 131 | "class", 132 | "sf_column", 133 | "agr", 134 | "query_list", 135 | "url", 136 | "full_url", 137 | "time_downloaded" 138 | ) 139 | ) 140 | expect_true(nzchar(attributes(sf_obj)$url)) 141 | expect_true(nzchar(attributes(sf_obj)$full_url)) 142 | expect_s3_class(attributes(sf_obj)$time_downloaded, "POSIXt") 143 | }) 144 | -------------------------------------------------------------------------------- /tests/testthat/test-geom-operators.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | if (has_internet() && identical(Sys.getenv("NOT_CRAN"), "true")) { 14 | local <- bcdc_query_geodata( 15 | "regional-districts-legally-defined-administrative-areas-of-bc" 16 | ) %>% 17 | filter(ADMIN_AREA_NAME == "Cariboo Regional District") %>% 18 | collect() 19 | } 20 | 21 | test_that("bcdc_check_geom_size outputs message with low threshold", { 22 | skip_on_cran() 23 | skip_if_net_down() 24 | 25 | withr::local_options(list(bcdata.max_geom_pred_size = 1)) 26 | expect_message(bcdc_check_geom_size(local), "The object is too large") 27 | expect_false(bcdc_check_geom_size(local)) 28 | }) 29 | 30 | test_that("bcdc_check_geom_size is silent with high threshold", { 31 | skip_on_cran() 32 | skip_if_net_down() 33 | 34 | withr::local_options(list(bcdata.max_geom_pred_size = 1E10)) 35 | expect_true(bcdc_check_geom_size(local)) 36 | }) 37 | 38 | 39 | test_that("WITHIN works", { 40 | skip_on_cran() 41 | skip_if_net_down() 42 | 43 | remote <- suppressWarnings( 44 | bcdc_query_geodata("bc-airports") %>% 45 | filter(WITHIN(local)) %>% 46 | collect() 47 | ) 48 | 49 | expect_s3_class(remote, "sf") 50 | expect_equal(attr(remote, "sf_column"), "geometry") 51 | }) 52 | 53 | 54 | test_that("INTERSECTS works", { 55 | skip_on_cran() 56 | skip_if_net_down() 57 | 58 | remote <- suppressWarnings( 59 | bcdc_query_geodata("bc-parks-ecological-reserves-and-protected-areas") %>% 60 | filter(FEATURE_LENGTH_M <= 1000, INTERSECTS(local)) %>% 61 | collect() 62 | ) 63 | 64 | expect_s3_class(remote, "sf") 65 | expect_equal(attr(remote, "sf_column"), "geometry") 66 | }) 67 | 68 | test_that("RELATE works", { 69 | skip("RELATE not supported. https://github.com/bcgov/bcdata/pull/154") 70 | skip_on_cran() 71 | skip_if_net_down() 72 | 73 | remote <- suppressWarnings( 74 | bcdc_query_geodata("bc-parks-ecological-reserves-and-protected-areas") %>% 75 | filter(RELATE(local, "*********")) %>% 76 | collect() 77 | ) 78 | 79 | expect_s3_class(remote, "sf") 80 | expect_equal(attr(remote, "sf_column"), "geometry") 81 | }) 82 | 83 | test_that("DWITHIN works", { 84 | skip_on_cran() 85 | skip_if_net_down() 86 | 87 | remote <- suppressWarnings( 88 | bcdc_query_geodata("bc-parks-ecological-reserves-and-protected-areas") %>% 89 | filter(DWITHIN(local, 100, "meters")) %>% 90 | collect() 91 | ) 92 | 93 | expect_s3_class(remote, "sf") 94 | expect_equal(attr(remote, "sf_column"), "geometry") 95 | }) 96 | 97 | test_that("BEYOND works", { 98 | skip("BEYOND currently not supported") 99 | # https://osgeo-org.atlassian.net/browse/GEOS-8922 100 | skip_on_cran() 101 | skip_if_net_down() 102 | 103 | remote <- suppressWarnings( 104 | bcdc_query_geodata("bc-parks-ecological-reserves-and-protected-areas") %>% 105 | filter(BEYOND(local, 100, "meters")) %>% 106 | collect() 107 | ) 108 | 109 | expect_s3_class(remote, "sf") 110 | expect_equal(attr(remote, "sf_column"), "geometry") 111 | }) 112 | 113 | test_that("BBOX works with an sf bbox", { 114 | skip_on_cran() 115 | skip_if_net_down() 116 | 117 | remote <- suppressWarnings( 118 | bcdc_query_geodata("bc-parks-ecological-reserves-and-protected-areas") %>% 119 | filter(FEATURE_LENGTH_M <= 1000, BBOX(!!sf::st_bbox(local))) %>% 120 | collect() 121 | ) 122 | 123 | expect_s3_class(remote, "sf") 124 | expect_equal(attr(remote, "sf_column"), "geometry") 125 | }) 126 | 127 | 128 | test_that("BBOX works with an sf object", { 129 | skip_on_cran() 130 | skip_if_net_down() 131 | 132 | remote <- suppressWarnings( 133 | bcdc_query_geodata("bc-parks-ecological-reserves-and-protected-areas") %>% 134 | filter(FEATURE_LENGTH_M <= 1000, BBOX(local)) %>% 135 | collect() 136 | ) 137 | 138 | expect_s3_class(remote, "sf") 139 | expect_equal(attr(remote, "sf_column"), "geometry") 140 | }) 141 | 142 | test_that("Other predicates work with an sf bbox", { 143 | skip_on_cran() 144 | skip_if_net_down() 145 | 146 | remote <- suppressWarnings( 147 | bcdc_query_geodata("bc-parks-ecological-reserves-and-protected-areas") %>% 148 | filter(FEATURE_LENGTH_M <= 1000, INTERSECTS(!!sf::st_bbox(local))) %>% 149 | collect() 150 | ) 151 | 152 | expect_s3_class(remote, "sf") 153 | expect_equal(attr(remote, "sf_column"), "geometry") 154 | }) 155 | -------------------------------------------------------------------------------- /R/describe-feature.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | #' Describe the attributes of a Web Feature Service 14 | #' 15 | #' Describe the attributes of column of a record accessed through the Web Feature Service. 16 | #' This can be a useful tool to examine a layer before issuing a query with `bcdc_query_geodata`. 17 | #' 18 | #' @return 19 | #' `bcdc_describe_feature` returns a tibble describing the attributes of a B.C. Data Catalogue record. 20 | #' The tibble returns the following columns: 21 | #' - col_name: attributes of the feature 22 | #' - sticky: whether a column can be separated from the record in a Web Feature Service call via the `dplyr::select` method 23 | #' - remote_col_type: class of what is return by the web feature service 24 | #' - local_col_type: the column class in R 25 | #' - column_comments: additional metadata specific to that column 26 | #' 27 | #' @inheritParams bcdc_query_geodata 28 | #' @export 29 | #' 30 | #' @examples 31 | #' \donttest{ 32 | #' try( 33 | #' bcdc_describe_feature("bc-airports") 34 | #' ) 35 | #' 36 | #' try( 37 | #' bcdc_describe_feature("WHSE_IMAGERY_AND_BASE_MAPS.GSR_AIRPORTS_SVW") 38 | #' ) 39 | #' } 40 | #' 41 | #' @export 42 | bcdc_describe_feature <- function(record) { 43 | if (!has_internet()) stop("No access to internet", call. = FALSE) # nocov 44 | UseMethod("bcdc_describe_feature") 45 | } 46 | 47 | #' @export 48 | bcdc_describe_feature.default <- function(record) { 49 | stop( 50 | "No bcdc_describe_feature method for an object of class ", 51 | class(record), 52 | call. = FALSE 53 | ) 54 | } 55 | 56 | #' @export 57 | bcdc_describe_feature.character <- function(record) { 58 | if (is_whse_object_name(record)) { 59 | bgc <- bcdc_get_wfs_records() 60 | cat_record <- bcdc_get_record(bgc$cat_url[grepl(record, bgc$whse_name)]) 61 | return(obj_desc_join(cat_record)) 62 | } 63 | 64 | bcdc_describe_feature(bcdc_get_record(record)) 65 | } 66 | 67 | 68 | #' @export 69 | bcdc_describe_feature.bcdc_record <- function(record) { 70 | if (!any(wfs_available(record$resource_df))) { 71 | stop("No WFS resource available for this data set.", call. = FALSE) 72 | } 73 | obj_desc_join(record) 74 | } 75 | 76 | parse_raw_feature_tbl <- function(query_list) { 77 | ## GET and parse data to sf object 78 | cli <- bcdc_wfs_client() 79 | 80 | cc <- cli$post(body = query_list, encode = "form") 81 | 82 | catch_wfs_error(cc) 83 | 84 | xml_res <- xml2::read_xml(cc$parse("UTF-8")) 85 | xml_res <- xml2::xml_find_all(xml_res, "//xsd:sequence") 86 | xml_res <- xml2::xml_find_all(xml_res, ".//xsd:element") 87 | xml_res <- purrr::map(xml_res, xml2::xml_attrs) 88 | xml_df <- purrr::map_df(xml_res, ~ as.list(.)) 89 | 90 | attr(xml_df, "geom_type") <- intersect(xml_df$type, gml_types()) 91 | 92 | return(xml_df) 93 | } 94 | 95 | feature_helper <- function(whse_name) { 96 | query_list <- list( 97 | SERVICE = "WFS", 98 | VERSION = "2.0.0", 99 | REQUEST = "DescribeFeatureType", 100 | typeNames = whse_name 101 | ) 102 | 103 | ## This is an ugly way of doing this 104 | ## Manually add id and turn into a row 105 | id_row <- dplyr::tibble(name = "id", nillable = TRUE, type = "xsd:string") 106 | 107 | xml_df <- parse_raw_feature_tbl(query_list) 108 | geom_type <- attr(xml_df, "geom_type") 109 | 110 | ## Fix logicals 111 | xml_df$nillable = ifelse(xml_df$nillable == "true", FALSE, TRUE) 112 | xml_df <- xml_df[, c("name", "nillable", "type")] 113 | 114 | ## Add the id_row back into the front 115 | xml_df <- dplyr::bind_rows(id_row, xml_df) 116 | colnames(xml_df) <- c("col_name", "sticky", "remote_col_type") 117 | xml_df$local_col_type <- wfs_to_r_col_type(xml_df$remote_col_type) 118 | 119 | xml_df 120 | } 121 | 122 | obj_desc_join <- function(record) { 123 | stopifnot(inherits(record, "bcdc_record")) 124 | 125 | wfs_resource <- get_wfs_resource_from_record(record) 126 | whse_name <- wfs_resource$object_name 127 | wfs_df <- purrr::list_rbind( 128 | purrr::map(wfs_resource$details, as.data.frame) 129 | ) 130 | 131 | dplyr::left_join( 132 | feature_helper(whse_name), 133 | wfs_df[, c("column_comments", "column_name")], 134 | by = c("col_name" = "column_name") 135 | ) 136 | } 137 | 138 | get_wfs_resource_from_record <- function(record) { 139 | wfs_res_id <- record$resource_df$id[record$resource_df$wfs_available] 140 | is_wfs <- vapply( 141 | record$resources, 142 | function(x) { 143 | x$id == wfs_res_id 144 | }, 145 | FUN.VALUE = logical(1) 146 | ) 147 | record$resources[[which(is_wfs)]] 148 | } 149 | -------------------------------------------------------------------------------- /revdep/README.md: -------------------------------------------------------------------------------- 1 | # Platform 2 | 3 | |field |value | 4 | |:--------|:------------------------------------------| 5 | |version |R version 4.4.3 (2025-02-28) | 6 | |os |macOS Sequoia 15.3.2 | 7 | |system |aarch64, darwin20 | 8 | |ui |X11 | 9 | |language |(EN) | 10 | |collate |en_US.UTF-8 | 11 | |ctype |en_US.UTF-8 | 12 | |tz |America/Vancouver | 13 | |date |2025-03-25 | 14 | |pandoc |3.6.4 @ /opt/homebrew/bin/ (via rmarkdown) | 15 | |quarto |1.6.42 @ /Applications/quarto/bin/quarto | 16 | 17 | # Dependencies 18 | 19 | |package |old |new |Δ | 20 | |:-----------------|:-------|:----------|:--| 21 | |bcdata |0.5.0 |0.5.0.9000 |* | 22 | |base64enc |0.1-3 |0.1-3 | | 23 | |bit |4.6.0 |4.6.0 | | 24 | |bit64 |4.6.0-1 |4.6.0-1 | | 25 | |blob |1.2.4 |1.2.4 | | 26 | |bslib |0.9.0 |0.9.0 | | 27 | |cachem |1.1.0 |1.1.0 | | 28 | |cellranger |1.1.0 |1.1.0 | | 29 | |classInt |0.4-11 |0.4-11 | | 30 | |cli |3.6.4 |3.6.4 | | 31 | |clipr |0.8.0 |0.8.0 | | 32 | |colorspace |2.1-1 |2.1-1 | | 33 | |cpp11 |0.5.2 |0.5.2 | | 34 | |crayon |1.5.3 |1.5.3 | | 35 | |crosstalk |1.2.1 |1.2.1 | | 36 | |crul |1.5.0 |1.5.0 | | 37 | |curl |6.2.2 |6.2.2 | | 38 | |DBI |1.2.3 |1.2.3 | | 39 | |dbplyr |2.5.0 |2.5.0 | | 40 | |digest |0.6.37 |0.6.37 | | 41 | |dplyr |1.1.4 |1.1.4 | | 42 | |e1071 |1.7-16 |1.7-16 | | 43 | |evaluate |1.0.3 |1.0.3 | | 44 | |fansi |1.0.6 |1.0.6 | | 45 | |farver |2.1.2 |2.1.2 | | 46 | |fastmap |1.2.0 |1.2.0 | | 47 | |fontawesome |0.5.3 |0.5.3 | | 48 | |fs |1.6.5 |1.6.5 | | 49 | |generics |0.1.3 |0.1.3 | | 50 | |glue |1.8.0 |1.8.0 | | 51 | |highr |0.11 |0.11 | | 52 | |hms |1.1.3 |1.1.3 | | 53 | |htmltools |0.5.8.1 |0.5.8.1 | | 54 | |htmlwidgets |1.6.4 |1.6.4 | | 55 | |httpcode |0.3.0 |0.3.0 | | 56 | |jquerylib |0.1.4 |0.1.4 | | 57 | |jsonlite |1.9.1 |1.9.1 | | 58 | |knitr |1.50 |1.50 | | 59 | |labeling |0.4.3 |0.4.3 | | 60 | |lazyeval |0.2.2 |0.2.2 | | 61 | |leaflet |2.2.2 |2.2.2 | | 62 | |leaflet.extras |2.0.1 |2.0.1 | | 63 | |leaflet.providers |2.0.0 |2.0.0 | | 64 | |lifecycle |1.0.4 |1.0.4 | | 65 | |magrittr |2.0.3 |2.0.3 | | 66 | |memoise |2.0.1 |2.0.1 | | 67 | |mime |0.13 |0.13 | | 68 | |munsell |0.5.1 |0.5.1 | | 69 | |pillar |1.10.1 |1.10.1 | | 70 | |pkgconfig |2.0.3 |2.0.3 | | 71 | |png |0.1-8 |0.1-8 | | 72 | |prettyunits |1.2.0 |1.2.0 | | 73 | |progress |1.2.3 |1.2.3 | | 74 | |proxy |0.4-27 |0.4-27 | | 75 | |purrr |1.0.4 |1.0.4 | | 76 | |R6 |2.6.1 |2.6.1 | | 77 | |rappdirs |0.3.3 |0.3.3 | | 78 | |raster |3.6-31 |3.6-31 | | 79 | |RColorBrewer |1.1-3 |1.1-3 | | 80 | |Rcpp |1.0.14 |1.0.14 | | 81 | |readr |2.1.5 |2.1.5 | | 82 | |readxl |1.4.5 |1.4.5 | | 83 | |rematch |2.0.0 |2.0.0 | | 84 | |rlang |1.1.5 |1.1.5 | | 85 | |rmarkdown |2.29 |2.29 | | 86 | |s2 |1.1.7 |1.1.7 | | 87 | |sass |0.4.9 |0.4.9 | | 88 | |scales |1.3.0 |1.3.0 | | 89 | |sf |1.0-20 |1.0-20 | | 90 | |sp |2.2-0 |2.2-0 | | 91 | |stringi |1.8.4 |1.8.4 | | 92 | |stringr |1.5.1 |1.5.1 | | 93 | |terra |1.8-29 |1.8-29 | | 94 | |tibble |3.2.1 |3.2.1 | | 95 | |tidyr |1.3.1 |1.3.1 | | 96 | |tidyselect |1.2.1 |1.2.1 | | 97 | |tinytex |0.56 |0.56 | | 98 | |triebeard |0.4.1 |0.4.1 | | 99 | |tzdb |0.5.0 |0.5.0 | | 100 | |units |0.8-7 |0.8-7 | | 101 | |urltools |1.7.3 |1.7.3 | | 102 | |utf8 |1.2.4 |1.2.4 | | 103 | |vctrs |0.6.5 |0.6.5 | | 104 | |viridisLite |0.4.2 |0.4.2 | | 105 | |vroom |1.6.5 |1.6.5 | | 106 | |withr |3.0.2 |3.0.2 | | 107 | |wk |0.9.4 |0.9.4 | | 108 | |xfun |0.51 |0.51 | | 109 | |xml2 |1.3.8 |1.3.8 | | 110 | |yaml |2.3.10 |2.3.10 | | 111 | 112 | # Revdeps 113 | 114 | -------------------------------------------------------------------------------- /R/cql-translator.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | # Ensure these are loaded first so dblplyr::sql_translator 14 | # can find them 15 | #' @include cql-geom-predicates.R 16 | NULL 17 | 18 | #' @importFrom rlang := 19 | 20 | # Function to translate R code to CQL 21 | cql_translate <- function(..., .colnames = character(0)) { 22 | ## convert dots to list of quosures 23 | dots <- rlang::quos(...) 24 | ## run partial_eval on them to evaluate named objects in the environment 25 | ## in which they were defined. 26 | ## e.g., if x is defined in the global env and passed as on object to 27 | ## filter, need to evaluate x in the global env. 28 | ## This also evaluates any functions defined in cql_scalar so that the spatial 29 | ## predicates and CQL() expressions are evaluated into valid CQL code 30 | ## so they can be combined with the rest of the query 31 | dots <- lapply(dots, function(x) { 32 | rlang::new_quosure( 33 | dbplyr::partial_eval(x, data = names_to_lazy_tbl(.colnames)) 34 | ) 35 | }) 36 | 37 | sql_where <- try( 38 | dbplyr::translate_sql_(dots, con = wfs_con, window = FALSE), 39 | silent = TRUE 40 | ) 41 | 42 | if (inherits(sql_where, "try-error")) { 43 | if (grepl("no applicable method", sql_where)) { 44 | stop( 45 | "Unable to process query. Did you use a function that should be evaluated locally? If so, try wrapping it in 'local()'.", 46 | call. = FALSE 47 | ) 48 | } 49 | stop(sql_where, call. = FALSE) 50 | } 51 | 52 | build_where(sql_where) 53 | } 54 | 55 | # Builds a complete WHERE clause from a vector of WHERE statements 56 | # Modified from dbplyr:::sql_clause_where 57 | build_where <- function(where, con = wfs_con) { 58 | if (length(where) == 0L) { 59 | return() 60 | } 61 | 62 | where_paren <- dbplyr::escape(where, parens = TRUE, con = con) 63 | dbplyr::build_sql( 64 | dbplyr::sql_vector(where_paren, collapse = " AND ", con = con), 65 | con = con 66 | ) 67 | } 68 | 69 | bcdc_identity <- function(f) { 70 | function(x, ...) { 71 | do.call(f, c(x, list(...))) 72 | } 73 | } 74 | 75 | # Define custom translations from R functions to filter functions supported 76 | # by cql: https://docs.geoserver.org/stable/en/user/filter/function_reference.html 77 | cql_scalar <- dbplyr::sql_translator( 78 | .parent = dbplyr::base_scalar, 79 | tolower = dbplyr::sql_prefix("strToLowerCase", 1), 80 | toupper = dbplyr::sql_prefix("strToUpperCase", 1), 81 | between = function(x, left, right) { 82 | CQL(paste0(x, " BETWEEN ", left, " AND ", right)) 83 | }, 84 | CQL = CQL, 85 | # Override dbplyr::base_scalar functions which convert to SQL 86 | # operations intended for the backend database, but we want them to operate 87 | # locally 88 | `[` = `[`, 89 | `[[` = `[[`, 90 | `$` = `$`, 91 | as.Date = function(x, ...) as.character(as.Date(x, ...)), 92 | as.POSIXct = function(x, ...) as.character(as.POSIXct(x, ...)), 93 | as.numeric = bcdc_identity("as.numeric"), 94 | as.double = bcdc_identity("as.double"), 95 | as.integer = bcdc_identity("as.integer"), 96 | as.character = bcdc_identity("as.character"), 97 | as.logical = function(x, ...) as.character(as.logical(x, ...)), 98 | # Geometry predicates 99 | EQUALS = EQUALS, 100 | DISJOINT = DISJOINT, 101 | INTERSECTS = INTERSECTS, 102 | TOUCHES = TOUCHES, 103 | CROSSES = CROSSES, 104 | WITHIN = WITHIN, 105 | CONTAINS = CONTAINS, 106 | OVERLAPS = OVERLAPS, 107 | RELATE = RELATE, 108 | DWITHIN = DWITHIN, 109 | BEYOND = BEYOND, 110 | BBOX = BBOX 111 | ) 112 | 113 | # No aggregation functions available in CQL 114 | no_agg <- function(f) { 115 | force(f) 116 | 117 | function(...) { 118 | stop( 119 | "Aggregation function `", 120 | f, 121 | "()` is not supported by this database", 122 | call. = FALSE 123 | ) 124 | } 125 | } 126 | 127 | # Construct the errors for common aggregation functions 128 | cql_agg <- dbplyr::sql_translator( 129 | n = no_agg("n"), 130 | mean = no_agg("mean"), 131 | var = no_agg("var"), 132 | sum = no_agg("sum"), 133 | min = no_agg("min"), 134 | max = no_agg("max") 135 | ) 136 | 137 | #' @importFrom dbplyr dbplyr_edition 138 | #' @export 139 | dbplyr_edition.wfsConnection <- function(con) 2L 140 | 141 | #' wfsConnection class 142 | #' 143 | #' @import methods 144 | #' @import DBI 145 | #' @export 146 | #' @keywords internal 147 | setClass("wfsConnection", contains = "DBIConnection") 148 | 149 | # A dummy connection object to ensure the correct sql_translate is used 150 | wfs_con <- structure( 151 | list(), 152 | class = c("wfsConnection", "DBIConnection") 153 | ) 154 | 155 | # Custom sql_translator using cql variants defined above 156 | #' @keywords internal 157 | #' @importFrom dbplyr sql_translation 158 | #' @export 159 | sql_translation.wfsConnection <- function(con) { 160 | dbplyr::sql_variant( 161 | cql_scalar, 162 | cql_agg, 163 | dbplyr::base_no_win 164 | ) 165 | } 166 | 167 | #' @rdname CQL 168 | #' @export 169 | #' @aliases 170 | #' CQL-class 171 | setClass("CQL", contains = c("SQL", "character")) 172 | 173 | # Make sure that identities (LHS of relations) are escaped with double quotes 174 | 175 | #' @keywords internal 176 | #' @rdname wfsConnection-class 177 | #' @exportMethod dbQuoteIdentifier 178 | #' @export 179 | setMethod( 180 | "dbQuoteIdentifier", 181 | c("wfsConnection", "CQL"), 182 | function(conn, x) dbplyr::sql_quote(x, "\"") 183 | ) 184 | 185 | # Make sure that strings (RHS of relations) are escaped with single quotes 186 | 187 | #' @keywords internal 188 | #' @rdname wfsConnection-class 189 | #' @exportMethod dbQuoteString 190 | #' @export 191 | setMethod( 192 | "dbQuoteString", 193 | c("wfsConnection", "CQL"), 194 | function(conn, x) dbplyr::sql_quote(x, "'") 195 | ) 196 | -------------------------------------------------------------------------------- /tests/testthat/test-get_record.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | test_that("bcdc_get_record works with slug and full url", { 14 | skip_on_cran() 15 | skip_if_net_down() 16 | expect_s3_class( 17 | ret1 <- bcdc_get_record( 18 | glue::glue("{catalogue_base_url()}/dataset/bc-airports") 19 | ), 20 | "bcdc_record" 21 | ) 22 | expect_s3_class( 23 | ret2 <- bcdc_get_record("bc-airports"), 24 | "bcdc_record" 25 | ) 26 | expect_s3_class( 27 | ret3 <- bcdc_get_record( 28 | glue::glue( 29 | "{catalogue_base_url()}/dataset/76b1b7a3-2112-4444-857a-afccf7b20da8" 30 | ) 31 | ), 32 | "bcdc_record" 33 | ) 34 | expect_s3_class( 35 | ret4 <- bcdc_get_record("76b1b7a3-2112-4444-857a-afccf7b20da8"), 36 | "bcdc_record" 37 | ) 38 | expect_equal(ret1$title, "BC Airports") 39 | lapply(list(ret2, ret3, ret4), expect_equal, ret1) 40 | }) 41 | 42 | test_that("bcdc_search_facets works", { 43 | skip_on_cran() 44 | skip_if_net_down() 45 | ret_names <- c("facet", "count", "display_name", "name") 46 | lapply( 47 | c( 48 | "license_id", 49 | "download_audience", 50 | "res_format", 51 | "publish_state", 52 | "organization" 53 | ), 54 | function(x) expect_named(bcdc_search_facets(x)) 55 | ) 56 | expect_error(bcdc_search_facets("foo"), "'arg' should be one of") 57 | }) 58 | 59 | 60 | test_that("bcdc_list_group_records works", { 61 | skip_on_cran() 62 | skip_if_net_down() 63 | 64 | expect_s3_class( 65 | bcdc_list_group_records('environmental-reporting-bc'), 66 | "bcdc_group" 67 | ) 68 | expect_s3_class( 69 | bcdc_list_group_records('environmental-reporting-bc'), 70 | "tbl_df" 71 | ) 72 | }) 73 | 74 | test_that("bcdc_list_groups", { 75 | skip_on_cran() 76 | skip_if_net_down() 77 | 78 | expect_s3_class(bcdc_list_groups(), "data.frame") 79 | }) 80 | 81 | test_that("bcdc_list_organization_records works", { 82 | skip_on_cran() 83 | skip_if_net_down() 84 | 85 | expect_s3_class( 86 | bcdc_list_organization_records('bc-stats'), 87 | "bcdc_organization" 88 | ) 89 | expect_s3_class(bcdc_list_organization_records('bc-stats'), "tbl_df") 90 | }) 91 | 92 | test_that("bcdc_list_organizations", { 93 | skip_on_cran() 94 | skip_if_net_down() 95 | 96 | expect_s3_class(bcdc_list_organizations(), "data.frame") 97 | }) 98 | 99 | test_that("bcdc_list works", { 100 | skip_on_cran() 101 | skip_if_net_down() 102 | ret <- bcdc_list() 103 | expect_type(ret, "character") 104 | expect_gt(length(ret), 1000) 105 | }) 106 | 107 | test_that("bcdc_search works", { 108 | skip_on_cran() 109 | skip_if_net_down() 110 | expect_s3_class(bcdc_search("forest"), "bcdc_recordlist") 111 | expect_s3_class( 112 | bcdc_search("regional district", res_format = "fgdb"), 113 | "bcdc_recordlist" 114 | ) 115 | expect_error( 116 | bcdc_search(organization = "foo"), 117 | "foo is not a valid value for organization" 118 | ) 119 | }) 120 | 121 | test_that("a record with bcgeographicwarehouse AND wms is return by bcdc_get_record", { 122 | skip_on_cran() 123 | skip_if_net_down() 124 | sr <- bcdc_get_record('95da1091-7e8c-4aa6-9c1b-5ab159ea7b42') 125 | d <- sr$resource_df 126 | expect_true(d$bcdata_available[ 127 | d$location == "bcgeographicwarehouse" & d$format == "wms" 128 | ]) 129 | }) 130 | 131 | test_that("a record with bcgeographicwarehouse AND wms is return by bcdc_get_record", { 132 | skip_on_cran() 133 | skip_if_net_down() 134 | sr <- bcdc_get_record('76b1b7a3-2112-4444-857a-afccf7b20da8') 135 | d <- sr$resource_df 136 | expect_false(all(d$bcdata_available[ 137 | d$location == "bcgeographicwarehouse" & d$format != "wms" 138 | ])) 139 | }) 140 | 141 | 142 | test_that("a data frame with 8 columns of expected types is returned by bcdc_tidy_resources", { 143 | skip_if_net_down() 144 | skip_on_cran() 145 | sr <- bcdc_get_record('76b1b7a3-2112-4444-857a-afccf7b20da8') 146 | d <- bcdc_tidy_resources(sr) 147 | expect_s3_class(d, "data.frame") 148 | expect_true(ncol(d) == 9) 149 | expect_type(d$name, "character") 150 | expect_type(d$url, "character") 151 | expect_type(d$id, "character") 152 | expect_type(d$format, "character") 153 | expect_type(d$ext, "character") 154 | expect_type(d$package_id, "character") 155 | expect_type(d$location, "character") 156 | expect_type(d$wfs_available, "logical") 157 | expect_type(d$bcdata_available, "logical") 158 | expect_equal(d, bcdc_tidy_resources('76b1b7a3-2112-4444-857a-afccf7b20da8')) 159 | expect_error( 160 | bcdc_tidy_resources(list()), 161 | "No bcdc_tidy_resources method for an object of class" 162 | ) 163 | expect_error( 164 | bcdc_tidy_resources("WHSE_IMAGERY_AND_BASE_MAPS.GSR_AIRPORTS_SVW"), 165 | "No bcdc_tidy_resources method for a BCGW object name" 166 | ) 167 | }) 168 | 169 | test_that("bcdc_get_record works with/without authentication", { 170 | skip_if_net_down() 171 | skip_on_cran() 172 | 173 | key_val <- Sys.getenv("BCDC_KEY") 174 | skip_if_not(nzchar(key_val)) 175 | on.exit(Sys.setenv(BCDC_KEY = key_val)) 176 | 177 | # record NOT requiring auth 178 | expect_message( 179 | res <- bcdc_get_record(point_record), 180 | "Authorizing with your stored API key" 181 | ) 182 | expect_s3_class(res, "bcdc_record") 183 | 184 | # record requiring auth 185 | auth_record_id <- Sys.getenv("BCDC_TEST_RECORD") 186 | skip_if_not(nzchar(key_val)) 187 | 188 | expect_message( 189 | res <- bcdc_get_record(auth_record_id), 190 | "Authorizing with your stored API key" 191 | ) 192 | expect_s3_class(res, "bcdc_record") 193 | 194 | Sys.unsetenv("BCDC_KEY") 195 | 196 | # record NOT requiring auth 197 | expect_silent(bcdc_get_record(point_record)) 198 | 199 | # record requiring auth (with no key set) 200 | expect_error(bcdc_get_record(auth_record_id)) 201 | 202 | # record requiring auth (with bad key set) 203 | Sys.setenv(BCDC_KEY = "not-a-valid-key") 204 | expect_error(bcdc_get_record(auth_record_id)) 205 | }) 206 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: 3 | github_document: 4 | html_preview: true 5 | --- 6 | 7 | 20 | 21 | 22 | 23 | ```{r setup, echo = FALSE, warning = FALSE, message = FALSE} 24 | knitr::opts_chunk$set( 25 | collapse = TRUE, 26 | comment = "#>", 27 | fig.path = "man/figures/" 28 | ) 29 | library(bcdata) 30 | ``` 31 | 32 | 33 | # bcdata 34 | 35 | 36 | 37 | 38 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/license/apache-2-0) 39 | [![CRAN\_Status\_Badge](https://www.r-pkg.org/badges/version/bcdata)](https://cran.r-project.org/package=bcdata) [![CRAN Downloads](https://cranlogs.r-pkg.org/badges/bcdata?color=brightgreen)](https://CRAN.R-project.org/package=bcdata) [![cran checks](https://cranchecks.info/badges/worst/bcdata)](https://CRAN.R-project.org/web/checks/check_results_bcdata.html) 40 | [![img](https://img.shields.io/badge/Lifecycle-Maturing-007EC6)](https://github.com/bcgov/repomountie/blob/master/doc/lifecycle-badges.md) 41 | [![DOI](https://joss.theoj.org/papers/10.21105/joss.02927/status.svg)](https://doi.org/10.21105/joss.02927) 42 | [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.4737824.svg)](https://doi.org/10.5281/zenodo.4737824) 43 | [![Codecov test coverage](https://codecov.io/gh/bcgov/bcdata/branch/main/graph/badge.svg)](https://app.codecov.io/gh/bcgov/bcdata?branch=main) 44 | [![R-CMD-check](https://github.com/bcgov/bcdata/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/bcgov/bcdata/actions/workflows/R-CMD-check.yaml) 45 | 46 | 47 | An R package 📦 for searching & retrieving data from the [B.C. Data Catalogue]( https://catalogue.data.gov.bc.ca). 48 | 49 | - `bcdc_browse()` - Open the catalogue in your default browser 50 | - `bcdc_search()` - Search records in the catalogue 51 | - `bcdc_search_facets()` - List catalogue facet search options 52 | - `bcdc_get_record()` - Print a catalogue record 53 | - `bcdc_tidy_resources()` - Get a data frame of resources for a record 54 | - `bcdc_get_data()` - Get catalogue data 55 | - `bcdc_query_geodata()` - Get & query catalogue geospatial data available through a [Web Feature Service](https://en.wikipedia.org/wiki/Web_Feature_Service) 56 | 57 | **Note:** The `bcdata` package supports downloading _most_ file types, including zip archives. It will do its best to identify and read data from 58 | zip files, however if there are multiple data files in the zip, or data files that `bcdata` doesn't know how to import, it will fail. 59 | If you encounter a file type in the B.C. Data Catalogue not currently supported by `bcdata` please file an [issue](https://github.com/bcgov/bcdata/issues/). 60 | 61 | ### Reference 62 | [bcdata package 📦 home page and reference guide](https://bcgov.github.io/bcdata/) 63 | 64 | ### Installation 65 | You can install `bcdata` directly from [CRAN](https://cran.r-project.org/package=bcdata): 66 | 67 | ```{r eval=FALSE} 68 | install.packages("bcdata") 69 | ``` 70 | 71 | To install the development version from GitHub, use the [remotes](https://cran.r-project.org/package=remotes) package: 72 | 73 | ```{r eval=FALSE} 74 | install.packages("remotes") 75 | 76 | remotes::install_github("bcgov/bcdata") 77 | library(bcdata) 78 | ``` 79 | 80 | 81 | ### Vignettes 82 | 83 | - [Get Started with bcdata](https://bcgov.github.io/bcdata/articles/bcdata.html) 84 | - [Querying Spatial Data with bcdata](https://bcgov.github.io/bcdata/articles/efficiently-query-spatial-data-in-the-bc-data-catalogue.html) 85 | - [Exploring Silviculture Data with bcdata](https://bcgov.github.io/bcdata/articles/explore-silviculture-data-using-bcdata.html) 86 | 87 | ### Methods for `bcdc_promise` 88 | 89 | The `bcdc_query_geodata()` returns an object of the class `bcdc_promise`. We have written an ever growing list methods for this class. You can use these methods directly on a object returned by `bcdc_query_geodata()`. Here are all the methods for the `bcdc_promise` class: 90 | 91 | ```{r echo=FALSE, results='asis'} 92 | bcdc_methods <- methods(class = "bcdc_promise") 93 | bcdc_methods <- sort(attributes(bcdc_methods)$info[,c("generic"), ]) 94 | 95 | cat(paste0("- `", bcdc_methods, "`", collapse = "\n")) 96 | ``` 97 | 98 | 99 | ### BCDC Authentication 100 | 101 | If you are an authorized editor of the B.C. Data Catalogue you may want to 102 | access records that are not publicly available (e.g., in DRAFT, waiting to be 103 | published). This can be done by authenticating with the catalogue with an API 104 | key. 105 | 106 | _**Important Note:**_ *Your API key is like a password and you must take care to 107 | keep it private. Do not share it, and be careful to not include it in any 108 | scripts or accidentally commit it to GitHub.* 109 | 110 | You can log in to the catalogue to obtain your API key, then store it as an 111 | environment variable in your [`.Renviron` file](https://rstats.wtf/r-startup.html#renviron). 112 | The environment variable must be called `BCDC_KEY`, set like this: 113 | 114 | ``` 115 | BCDC_KEY=your-api-key 116 | ``` 117 | 118 | This way, the relevant bcdata functions will read that key and use it to 119 | authorize your calls to the catalogue, allowing you to access additional records 120 | that you are authorized to see if you were logged into the catalogue web 121 | interface. Functions that benefit from this are: 122 | 123 | - `bcdc_search()` 124 | - `bcdc_list()` 125 | - `bcdc_get_record()` 126 | - `bcdc_get_data()` 127 | 128 | ### Getting Help or Reporting an Issue 129 | 130 | To report bugs/issues/feature requests, please file an [issue](https://github.com/bcgov/bcdata/issues/). 131 | 132 | ### How to Contribute 133 | 134 | If you would like to contribute to the package, please see our 135 | [CONTRIBUTING](https://github.com/bcgov/bcdata/blob/master/CONTRIBUTING.md) guidelines. 136 | 137 | Please note that this project is released with a [Contributor Code of Conduct](https://github.com/bcgov/bcdata/blob/master/CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. 138 | 139 | ### Citation 140 | ```{r, echo=FALSE, comment=""} 141 | citation("bcdata") 142 | ``` 143 | 144 | 145 | ### License 146 | 147 | Copyright 2018 Province of British Columbia 148 | 149 | Licensed under the Apache License, Version 2.0 (the "License"); 150 | you may not use this file except in compliance with the License. 151 | You may obtain a copy of the License at 152 | 153 | https://www.apache.org/licenses/LICENSE-2.0 154 | 155 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 156 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 157 | See the License for the specific language governing permissions and limitations under the License. 158 | 159 | --- 160 | *This project was created using the [bcgovr](https://github.com/bcgov/bcgovr) package.* 161 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | # bcdata 14 | 15 | 16 | 17 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/license/apache-2-0) 18 | [![CRAN_Status_Badge](https://www.r-pkg.org/badges/version/bcdata)](https://cran.r-project.org/package=bcdata) 19 | [![CRAN 20 | Downloads](https://cranlogs.r-pkg.org/badges/bcdata?color=brightgreen)](https://CRAN.R-project.org/package=bcdata) 21 | [![cran 22 | checks](https://cranchecks.info/badges/worst/bcdata)](https://CRAN.R-project.org/web/checks/check_results_bcdata.html) 23 | [![img](https://img.shields.io/badge/Lifecycle-Maturing-007EC6)](https://github.com/bcgov/repomountie/blob/master/doc/lifecycle-badges.md) 24 | [![DOI](https://joss.theoj.org/papers/10.21105/joss.02927/status.svg)](https://doi.org/10.21105/joss.02927) 25 | [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.4737824.svg)](https://doi.org/10.5281/zenodo.4737824) 26 | [![Codecov test 27 | coverage](https://codecov.io/gh/bcgov/bcdata/branch/main/graph/badge.svg)](https://app.codecov.io/gh/bcgov/bcdata?branch=main) 28 | [![R-CMD-check](https://github.com/bcgov/bcdata/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/bcgov/bcdata/actions/workflows/R-CMD-check.yaml) 29 | 30 | 31 | An R package 📦 for searching & retrieving data from the [B.C. Data 32 | Catalogue](https://catalogue.data.gov.bc.ca). 33 | 34 | - `bcdc_browse()` - Open the catalogue in your default browser 35 | - `bcdc_search()` - Search records in the catalogue 36 | - `bcdc_search_facets()` - List catalogue facet search options 37 | - `bcdc_get_record()` - Print a catalogue record 38 | - `bcdc_tidy_resources()` - Get a data frame of resources for a record 39 | - `bcdc_get_data()` - Get catalogue data 40 | - `bcdc_query_geodata()` - Get & query catalogue geospatial data 41 | available through a [Web Feature 42 | Service](https://en.wikipedia.org/wiki/Web_Feature_Service) 43 | 44 | **Note:** The `bcdata` package supports downloading *most* file types, 45 | including zip archives. It will do its best to identify and read data 46 | from zip files, however if there are multiple data files in the zip, or 47 | data files that `bcdata` doesn’t know how to import, it will fail. If 48 | you encounter a file type in the B.C. Data Catalogue not currently 49 | supported by `bcdata` please file an 50 | [issue](https://github.com/bcgov/bcdata/issues/). 51 | 52 | ### Reference 53 | 54 | [bcdata package 📦 home page and reference 55 | guide](https://bcgov.github.io/bcdata/) 56 | 57 | ### Installation 58 | 59 | You can install `bcdata` directly from 60 | [CRAN](https://cran.r-project.org/package=bcdata): 61 | 62 | ``` r 63 | install.packages("bcdata") 64 | ``` 65 | 66 | To install the development version from GitHub, use the 67 | [remotes](https://cran.r-project.org/package=remotes) package: 68 | 69 | ``` r 70 | install.packages("remotes") 71 | 72 | remotes::install_github("bcgov/bcdata") 73 | library(bcdata) 74 | ``` 75 | 76 | ### Vignettes 77 | 78 | - [Get Started with 79 | bcdata](https://bcgov.github.io/bcdata/articles/bcdata.html) 80 | - [Querying Spatial Data with 81 | bcdata](https://bcgov.github.io/bcdata/articles/efficiently-query-spatial-data-in-the-bc-data-catalogue.html) 82 | - [Exploring Silviculture Data with 83 | bcdata](https://bcgov.github.io/bcdata/articles/explore-silviculture-data-using-bcdata.html) 84 | 85 | ### Methods for `bcdc_promise` 86 | 87 | The `bcdc_query_geodata()` returns an object of the class 88 | `bcdc_promise`. We have written an ever growing list methods for this 89 | class. You can use these methods directly on a object returned by 90 | `bcdc_query_geodata()`. Here are all the methods for the `bcdc_promise` 91 | class: 92 | 93 | - `as_tibble` 94 | - `collect` 95 | - `filter` 96 | - `head` 97 | - `mutate` 98 | - `names` 99 | - `print` 100 | - `select` 101 | - `show_query` 102 | - `tail` 103 | 104 | ### BCDC Authentication 105 | 106 | If you are an authorized editor of the B.C. Data Catalogue you may want 107 | to access records that are not publicly available (e.g., in DRAFT, 108 | waiting to be published). This can be done by authenticating with the 109 | catalogue with an API key. 110 | 111 | ***Important Note:*** *Your API key is like a password and you must take 112 | care to keep it private. Do not share it, and be careful to not include 113 | it in any scripts or accidentally commit it to GitHub.* 114 | 115 | You can log in to the catalogue to obtain your API key, then store it as 116 | an environment variable in your [`.Renviron` 117 | file](https://rstats.wtf/r-startup.html#renviron). The environment 118 | variable must be called `BCDC_KEY`, set like this: 119 | 120 | BCDC_KEY=your-api-key 121 | 122 | This way, the relevant bcdata functions will read that key and use it to 123 | authorize your calls to the catalogue, allowing you to access additional 124 | records that you are authorized to see if you were logged into the 125 | catalogue web interface. Functions that benefit from this are: 126 | 127 | - `bcdc_search()` 128 | - `bcdc_list()` 129 | - `bcdc_get_record()` 130 | - `bcdc_get_data()` 131 | 132 | ### Getting Help or Reporting an Issue 133 | 134 | To report bugs/issues/feature requests, please file an 135 | [issue](https://github.com/bcgov/bcdata/issues/). 136 | 137 | ### How to Contribute 138 | 139 | If you would like to contribute to the package, please see our 140 | [CONTRIBUTING](https://github.com/bcgov/bcdata/blob/master/CONTRIBUTING.md) 141 | guidelines. 142 | 143 | Please note that this project is released with a [Contributor Code of 144 | Conduct](https://github.com/bcgov/bcdata/blob/master/CODE_OF_CONDUCT.md). 145 | By participating in this project you agree to abide by its terms. 146 | 147 | ### Citation 148 | 149 | To cite package 'bcdata' in publications use: 150 | 151 | Teucher AC, Albers SJ, Hazlitt SL (2021). "bcdata: An R package for 152 | searching and retrieving data from the B.C. Data Catalogue." _Journal 153 | of Open Source Software_, *6*(61), 2927. doi:10.21105/joss.02927 154 | . 155 | 156 | A BibTeX entry for LaTeX users is 157 | 158 | @Article{, 159 | doi = {10.21105/joss.02927}, 160 | year = {2021}, 161 | publisher = {The Open Journal}, 162 | volume = {6}, 163 | number = {61}, 164 | pages = {2927}, 165 | author = {Andrew C. Teucher and Sam J. Albers and Stephanie L. Hazlitt}, 166 | title = {bcdata: An R package for searching and retrieving data from the B.C. Data Catalogue}, 167 | journal = {Journal of Open Source Software}, 168 | } 169 | 170 | ### License 171 | 172 | Copyright 2018 Province of British Columbia 173 | 174 | Licensed under the Apache License, Version 2.0 (the “License”); you may 175 | not use this file except in compliance with the License. You may obtain 176 | a copy of the License at 177 | 178 | 179 | 180 | Unless required by applicable law or agreed to in writing, software 181 | distributed under the License is distributed on an “AS IS” BASIS, 182 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 183 | See the License for the specific language governing permissions and 184 | limitations under the License. 185 | 186 | ------------------------------------------------------------------------ 187 | 188 | *This project was created using the 189 | [bcgovr](https://github.com/bcgov/bcgovr) package.* 190 | -------------------------------------------------------------------------------- /tests/testthat/test-get-data.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | test_that("bcdc_get_data collects an sf object for a valid record and resource id", { 14 | skip_if_net_down() 15 | skip_on_cran() 16 | bc_airports <- bcdc_get_data( 17 | '76b1b7a3-2112-4444-857a-afccf7b20da8', 18 | resource = "4d0377d9-e8a1-429b-824f-0ce8f363512c" 19 | ) 20 | expect_s3_class(bc_airports, "sf") 21 | expect_equal(attr(bc_airports, "sf_column"), "geometry") 22 | }) 23 | 24 | 25 | test_that("bcdc_get_data works with slug and full url with corresponding resource", { 26 | skip_if_net_down() 27 | skip_on_cran() 28 | expect_s3_class( 29 | ret1 <- bcdc_get_data( 30 | glue::glue("{catalogue_base_url()}/dataset/bc-airports"), 31 | resource = "4d0377d9-e8a1-429b-824f-0ce8f363512c" 32 | ), 33 | "sf" 34 | ) 35 | expect_s3_class( 36 | ret2 <- bcdc_get_data( 37 | "bc-airports", 38 | resource = "4d0377d9-e8a1-429b-824f-0ce8f363512c" 39 | ), 40 | "sf" 41 | ) 42 | expect_s3_class( 43 | ret3 <- bcdc_get_data( 44 | glue::glue( 45 | "{catalogue_base_url()}/dataset/76b1b7a3-2112-4444-857a-afccf7b20da8" 46 | ), 47 | resource = "4d0377d9-e8a1-429b-824f-0ce8f363512c" 48 | ), 49 | "sf" 50 | ) 51 | expect_s3_class( 52 | ret4 <- bcdc_get_data( 53 | "76b1b7a3-2112-4444-857a-afccf7b20da8", 54 | resource = "4d0377d9-e8a1-429b-824f-0ce8f363512c" 55 | ), 56 | "sf" 57 | ) 58 | expect_s3_class( 59 | ret5 <- bcdc_get_data( 60 | glue::glue( 61 | "{catalogue_base_url()}/dataset/76b1b7a3-2112-4444-857a-afccf7b20da8/resource/4d0377d9-e8a1-429b-824f-0ce8f363512c" 62 | ) 63 | ), 64 | "sf" 65 | ) 66 | 67 | for (x in list(ret2, ret3, ret4, ret5)) { 68 | expect_equal(dim(x), dim(ret1)) 69 | expect_equal(names(x), names(ret1)) 70 | } 71 | }) 72 | 73 | 74 | test_that("bcdc_get_data works with a non-wms record with only one resource", { 75 | skip_if_net_down() 76 | skip_on_cran() 77 | name <- "ee9d4ee0-6a34-4dff-89e0-9add9a969168" # "criminal-code-traffic-offences" 78 | expect_s3_class(bcdc_get_data(name), "tbl") 79 | }) 80 | 81 | test_that("bcdc_get_data works when using read_excel arguments", { 82 | skip_if_net_down() 83 | skip_on_cran() 84 | ret <- bcdc_get_data( 85 | "2e469ff2-dadb-45ea-af9d-f5683a4b9465", 86 | resource = "18510a60-de82-440a-b806-06fba70eaf9d", 87 | skip = 4, 88 | n_max = 3 89 | ) 90 | expect_s3_class(ret, "tbl") 91 | expect_equal(nrow(ret), 3L, ignore_attr = TRUE) 92 | }) 93 | 94 | test_that("bcdc_get_data works with an xls when specifying a specific resource", { 95 | skip_if_net_down() 96 | skip_on_cran() 97 | name <- 'bc-grizzly-bear-habitat-classification-and-rating' 98 | expect_s3_class( 99 | bcdc_get_data(name, resource = '7b09f82f-e7d0-44bf-9310-b94039b323a8'), 100 | "tbl" 101 | ) 102 | }) 103 | 104 | test_that("bcdc_get_data will return non-wms resources", { 105 | skip_if_net_down() 106 | skip_on_cran() 107 | expect_s3_class( 108 | bcdc_get_data( 109 | record = '76b1b7a3-2112-4444-857a-afccf7b20da8', 110 | resource = 'fcccba36-b528-4731-8978-940b3cc04f69' 111 | ), 112 | "tbl" 113 | ) 114 | 115 | expect_s3_class( 116 | bcdc_get_data( 117 | record = 'fa542137-a976-49a6-856d-f1201adb2243', 118 | resource = 'dc1098a7-a4b8-49a3-adee-9badd4429279' 119 | ), 120 | "tbl" 121 | ) 122 | }) 123 | 124 | test_that("bcdc_get_data works with a zipped shp file", { 125 | skip_if_net_down() 126 | skip_on_cran() 127 | expect_s3_class( 128 | bcdc_get_data( 129 | record = '481d6d4d-a536-4df9-9e9c-7473cd2ed89e', 130 | resource = '41c9bff0-4e25-49fc-a3e2-2a2e426ac71d' 131 | ), 132 | "sf" 133 | ) 134 | }) 135 | 136 | test_that("unknown single file (shp) inside zip", { 137 | skip_if_net_down() 138 | skip_on_cran() 139 | expect_s3_class( 140 | bcdc_get_data("e31f7488-27fa-4330-ae86-160a0deb8a59"), 141 | "sf" 142 | ) 143 | }) 144 | 145 | test_that("fails when resource doesn't exist", { 146 | skip_if_net_down() 147 | skip_on_cran() 148 | expect_error( 149 | bcdc_get_data( 150 | "300c0980-b5e3-4202-b0da-d816f14fadad", 151 | resource = "not-a-real-resource" 152 | ), 153 | "The specified resource does not exist in this record" 154 | ) 155 | }) 156 | 157 | test_that("fails when multiple files in a zip", { 158 | skip_if_net_down() 159 | skip_on_cran() 160 | expect_error( 161 | bcdc_get_data( 162 | "300c0980-b5e3-4202-b0da-d816f14fadad", 163 | resource = "c212a8a7-c625-4464-b9c8-4527c843f52f" 164 | ), 165 | "More than one supported file in zip file" 166 | ) 167 | }) 168 | 169 | test_that("fails informatively when can't read a file", { 170 | skip_if_net_down() 171 | skip_on_cran() 172 | expect_error( 173 | suppressWarnings( 174 | bcdc_get_data( 175 | record = '523dce9d-b464-44a5-b733-2022e94546c3', 176 | resource = '4cc98644-f6eb-410b-9df0-f9b2beac9717' 177 | ) 178 | ), 179 | "Reading the data set failed with the following error message:" 180 | ) 181 | }) 182 | 183 | test_that("bcdc_get_data can return the wms resource when it is specified by resource", { 184 | skip_if_net_down() 185 | skip_on_cran() 186 | expect_s3_class( 187 | bcdc_get_data( 188 | '76b1b7a3-2112-4444-857a-afccf7b20da8', 189 | resource = "4d0377d9-e8a1-429b-824f-0ce8f363512c" 190 | ), 191 | "sf" 192 | ) 193 | }) 194 | 195 | 196 | test_that("a wms record with only one resource works with only the record id", { 197 | skip_if_net_down() 198 | skip_on_cran() 199 | expect_s3_class( 200 | bcdc_get_data("bc-college-region-boundaries"), 201 | "sf" 202 | ) 203 | }) 204 | 205 | test_that("bcdc_get_data works with a bcdc_record object", { 206 | skip_if_net_down() 207 | skip_on_cran() 208 | record <- bcdc_get_record("bc-college-region-boundaries") 209 | expect_s3_class(bcdc_get_data(record), "sf") 210 | 211 | record <- bcdc_get_record('fa542137-a976-49a6-856d-f1201adb2243') 212 | expect_s3_class( 213 | bcdc_get_data(record, resource = 'dc1098a7-a4b8-49a3-adee-9badd4429279'), 214 | "tbl" 215 | ) 216 | }) 217 | 218 | test_that("bcdc_get_data fails with invalid input", { 219 | skip_if_net_down() 220 | skip_on_cran() 221 | expect_error( 222 | bcdc_get_data(35L), 223 | "No bcdc_get_data method for an object of class integer" 224 | ) 225 | }) 226 | 227 | test_that("bcdc_get_data works with BCGW name", { 228 | skip_if_net_down() 229 | skip_on_cran() 230 | expect_s3_class( 231 | bcdc_get_data("WHSE_IMAGERY_AND_BASE_MAPS.GSR_AIRPORTS_SVW"), 232 | "bcdc_sf" 233 | ) 234 | }) 235 | 236 | test_that("bcdc_get_data fails when no downloadable resources", { 237 | skip_if_net_down() 238 | skip_on_cran() 239 | expect_error( 240 | bcdc_get_data("4e237966-3db8-4e28-8e59-296bf0b8d8e4"), 241 | "There are no resources that bcdata can download from this record" 242 | ) 243 | }) 244 | 245 | test_that("bcdc_get_data fails when >1 resource not specified & noninteractive", { 246 | skip_if_net_down() 247 | skip_on_cran() 248 | expect_error( 249 | bcdc_get_data("21c72822-2502-4431-b9a2-92fc9401ef12"), 250 | "The record you are trying to access appears to have more than one resource." 251 | ) 252 | }) 253 | 254 | test_that("bcdc_get_data handles sheet name specification", { 255 | skip_if_net_down() 256 | skip_on_cran() 257 | expect_message( 258 | bcdc_get_data('8620ce82-4943-43c4-9932-40730a0255d6'), 259 | 'This .xlsx resource contains the following sheets:' 260 | ) 261 | expect_error( 262 | bcdc_get_data('8620ce82-4943-43c4-9932-40730a0255d6', sheet = "foo"), 263 | "Error: Sheet 'foo' not found" 264 | ) 265 | expect_s3_class( 266 | bcdc_get_data( 267 | '8620ce82-4943-43c4-9932-40730a0255d6', 268 | sheet = "Multi Unit Homes" 269 | ), 270 | "data.frame" 271 | ) 272 | }) 273 | 274 | test_that("bcdc_get_data returns a list object when resource has a json extension", { 275 | skip_if_net_down() 276 | skip_on_cran() 277 | expect_type(bcdc_get_data("8e24f2bc-ab7a-49df-9418-539387180f33"), "list") 278 | }) 279 | -------------------------------------------------------------------------------- /R/bcdc_options.R: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Province of British Columbia 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and limitations under the License. 12 | 13 | #' Retrieve options used in bcdata, their value if set and the default value. 14 | #' 15 | #' This function retrieves bcdata specific options that can be set. These 16 | #' options can be set using `option({name of the option} = {value of the 17 | #' option})`. The default options are purposefully set conservatively to 18 | #' hopefully ensure successful requests. Resetting these options may result in 19 | #' failed calls to the data catalogue. Options in R are reset every time R is 20 | #' re-started. See examples for additional ways to restore your initial state. 21 | #' 22 | #' `bcdata.max_geom_pred_size` is the maximum size in bytes of an object used 23 | #' for a geometric operation. Objects that are bigger than this value will have 24 | #' a bounding box drawn and apply the geometric operation on that simpler 25 | #' polygon. The [bcdc_check_geom_size] function can be used to assess whether a 26 | #' given spatial object exceeds the value of this option. Users can iteratively 27 | #' try to increase the maximum geometric predicate size and see if the bcdata 28 | #' catalogue accepts the request. 29 | #' 30 | #' `bcdata.chunk_limit` is an option useful when dealing with very large data 31 | #' sets. When requesting large objects from the catalogue, the request is broken 32 | #' up into smaller chunks which are then recombined after they've been 33 | #' downloaded. This is called "pagination". bcdata does this all for you, however by 34 | #' using this option you can set the size of the chunk requested. On slower 35 | #' connections, or when having problems, it may help to lower the chunk limit. 36 | #' 37 | #' `bcdata.max_package_search_limit` is an option for setting the maximum number of 38 | #' datasets returned when querying by organization with the package_search API endpoint. The 39 | #' default limit (1000) is purposely set high to return all datasets for a 40 | #' given organization. 41 | #' 42 | #' `bcdata.max_package_search_facet_limit` is an option for setting the maximum number of 43 | #' values returned when querying facet fields with the package_search API endpoint. The 44 | #' default limit (1000) is purposely set high to return all values for each facet field 45 | #' ("license_id", "download_audience", "res_format", "publish_state", "organization", "groups"). 46 | #' 47 | #' `bcdata.max_group_package_show_limit` is an option for setting the maximum number of 48 | #' datasets returned when querying by group with the group_package_show API endpoint. The 49 | #' default limit (1000) is purposely set high to return all datasets for a 50 | #' given group. 51 | #' 52 | #' `bcdata.single_download_limit` *Deprecated*. This is the maximum number of 53 | #' records an object can be before forcing a paginated download; it is set by 54 | #' querying the server capabilities. This option is deprecated and will be 55 | #' removed in a future release. Use `bcdata.chunk_limit` to set a lower value 56 | #' pagination value. 57 | #' 58 | #' @examples 59 | #' \donttest{ 60 | #' ## Save initial conditions 61 | #' try( 62 | #' original_options <- options() 63 | #' ) 64 | #' 65 | #' ## See initial options 66 | #' try( 67 | #' bcdc_options() 68 | #' ) 69 | #' 70 | #' try( 71 | #' options(bcdata.max_geom_pred_size = 1E6) 72 | #' ) 73 | #' 74 | #' ## See updated options 75 | #' try( 76 | #' bcdc_options() 77 | #' ) 78 | #' 79 | #' ## Reset initial conditions 80 | #' try( 81 | #' options(original_options) 82 | #' ) 83 | #' } 84 | #' @export 85 | #' 86 | 87 | bcdc_options <- function() { 88 | null_to_na <- function(x) { 89 | ifelse(is.null(x), NA, as.numeric(x)) 90 | } 91 | 92 | server_single_download_limit <- bcdc_single_download_limit() 93 | 94 | dplyr::tribble( 95 | ~option, 96 | ~value, 97 | ~default, 98 | "bcdata.max_geom_pred_size", 99 | null_to_na(getOption("bcdata.max_geom_pred_size")), 100 | 5E5, 101 | "bcdata.chunk_limit", 102 | null_to_na(getOption("bcdata.chunk_limit")), 103 | server_single_download_limit, 104 | "bcdata.single_download_limit", 105 | null_to_na(deprecate_single_download_limit_option()), 106 | server_single_download_limit, 107 | "bcdata.max_package_search_limit", 108 | null_to_na(getOption("bcdata.max_package_search_limit")), 109 | 1000, 110 | "bcdata.max_package_search_facet_limit", 111 | null_to_na(getOption("bcdata.max_package_search_facet_limit")), 112 | 1000, 113 | "bcdata.max_group_package_show_limit", 114 | null_to_na(getOption("bcdata.max_group_package_show_limit")), 115 | 1000 116 | ) 117 | } 118 | 119 | 120 | check_chunk_limit <- function() { 121 | chunk_limit <- getOption("bcdata.chunk_limit") 122 | single_download_limit <- deprecate_single_download_limit_option() 123 | 124 | if (is.null(chunk_limit)) { 125 | return(single_download_limit) 126 | } 127 | if (chunk_limit > single_download_limit) { 128 | stop( 129 | glue::glue( 130 | "Your chunk value of {chunk_limit} exceeds the BC Data Catalogue chunk limit of {single_download_limit}" 131 | ), 132 | call. = FALSE 133 | ) 134 | } 135 | chunk_limit 136 | } 137 | 138 | bcdc_get_capabilities <- function() { 139 | current_xml <- ._bcdataenv_$get_capabilities_xml 140 | if (!is.null(current_xml) && inherits(current_xml, "xml_document")) { 141 | # Already retrieved and stored this session 142 | return(current_xml) 143 | } 144 | 145 | if (has_internet()) { 146 | url <- make_url(bcdc_web_service_host(), "geo/pub/ows") 147 | cli <- bcdc_http_client(url, auth = FALSE) 148 | 149 | get_caps <- function(cli) { 150 | cc <- cli$get( 151 | query = list( 152 | SERVICE = "WFS", 153 | VERSION = "2.0.0", 154 | REQUEST = "GetCapabilities" 155 | ) 156 | ) 157 | cc$raise_for_status() 158 | res <- cc$parse("UTF-8") 159 | xml2::read_xml(res) 160 | } 161 | 162 | # The GetCapabilities request can be fragile, 163 | # if it breaks return NULL (#339) 164 | ret <- try(get_caps(cli), silent = TRUE) 165 | 166 | if (inherits(ret, "try-error")) { 167 | return(NULL) 168 | } 169 | 170 | # store it and return it 171 | ._bcdataenv_$get_capabilities_xml <- ret 172 | return(ret) 173 | } 174 | 175 | invisible(NULL) 176 | } 177 | 178 | bcdc_get_wfs_records <- function() { 179 | doc <- bcdc_get_capabilities() 180 | 181 | if (is.null(doc)) 182 | stop( 183 | "Unable to access wfs listing from server. Please open an issue. ", 184 | call. = FALSE 185 | ) 186 | 187 | # d1 is the default xml namespace (see xml2::xml_ns(doc)) 188 | features <- xml2::xml_find_all(doc, "./d1:FeatureTypeList/d1:FeatureType") 189 | 190 | tibble::tibble( 191 | whse_name = gsub( 192 | "^pub:", 193 | "", 194 | xml2::xml_text(xml2::xml_find_first(features, "./d1:Name")) 195 | ), 196 | title = xml2::xml_text(xml2::xml_find_first(features, "./d1:Title")), 197 | cat_url = xml2::xml_attr( 198 | xml2::xml_find_first(features, "./d1:MetadataURL"), 199 | "href" 200 | ) 201 | ) 202 | } 203 | 204 | bcdc_single_download_limit <- function() { 205 | doc <- bcdc_get_capabilities() 206 | 207 | if (is.null(doc)) { 208 | message( 209 | "Unable to access server to determine single download limit; using default download limit of 10000" 210 | ) 211 | return(10000L) 212 | } 213 | 214 | count_default_xpath <- "./ows:OperationsMetadata/ows:Operation[@name='GetFeature']/ows:Constraint[@name='CountDefault']" 215 | # Looking globally also works but is slower: ".//ows:Constraint[@name='CountDefault']" 216 | count_defaults <- xml2::xml_find_first(doc, count_default_xpath) 217 | xml2::xml_integer(count_defaults) 218 | } 219 | 220 | # Used to send a message once per session that the single_download_limit option 221 | # will be deprecated. When we remove it, replace all calls to this function 222 | # with bcdc_single_download_limit() and remove the ._bcdataenv_$single_download_limit_warned 223 | # object from .onLoad. 224 | deprecate_single_download_limit_option <- function() { 225 | x <- getOption("bcdata.single_download_limit") 226 | if (!is.null(x)) { 227 | if (!isTRUE(._bcdataenv_$single_download_limit_warned)) { 228 | warning( 229 | "The bcdata.single_download_limit option is deprecated. Please use bcdata.chunk_limit instead.", 230 | call. = FALSE 231 | ) 232 | assign("single_download_limit_warned", TRUE, envir = ._bcdataenv_) 233 | } 234 | return(x) 235 | } 236 | bcdc_single_download_limit() 237 | } 238 | --------------------------------------------------------------------------------