Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #229

Merged
merged 25 commits into from
Feb 5, 2024
Merged

Dev #229

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d9f2cfc
Enable thumbnails to download when some are missing #215
daxkellie Nov 29, 2023
be472e8
Parse apostrophes correctly using `%in%` & `galah_filter()` #214
daxkellie Nov 29, 2023
550b475
Query errors early when no taxa search terms are matched #219
daxkellie Dec 15, 2023
2b112c7
Fix facet limit for `show_values()` #222
daxkellie Dec 21, 2023
12d441f
Increase internal `limit` of `atlas_counts()` #198
daxkellie Dec 22, 2023
d0f1931
Rename column to `species_list_uid` in `search_all(lists)` #225
daxkellie Jan 12, 2024
1ac19b4
First pass at rewiring `collapse()` as per issue #217
mjwestgate Jan 23, 2024
76b93f1
update tests for `atlas_counts()`
mjwestgate Jan 24, 2024
9cb305a
Add test systems documentation
daxkellie Jan 24, 2024
7b9b2d6
change object name returned by `compute` to `computed_query`
mjwestgate Jan 30, 2024
49f2e31
fix bugs when passing `thumbnail` or `mint_doi` to `collect()`
mjwestgate Jan 31, 2024
71c81d9
update remaining tests to new `collapse()` behaviour
mjwestgate Jan 31, 2024
1016ae0
clean up tests relating to #225
mjwestgate Feb 1, 2024
24124b1
clean up tests
mjwestgate Feb 1, 2024
40b0ced
Add `try()` and `skip_if()` to tests for International Atlases to avo…
mjwestgate Feb 1, 2024
6870a21
update international tests to skip before failing if API is down
mjwestgate Feb 2, 2024
db2cfcc
update object-oriented programming vignette to new behavior
mjwestgate Feb 2, 2024
48801bd
update to version 2.0-1; add content to NEWS
mjwestgate Feb 2, 2024
9a0e179
undo mistaken commit of commented out code
mjwestgate Feb 2, 2024
b4aeca7
Merge pull request #228 from AtlasOfLivingAustralia/dev-collapse-testing
mjwestgate Feb 2, 2024
749f7f3
fix bug in `atlas_species()`
mjwestgate Feb 2, 2024
2ff99b7
add missing `skip_if_offline()` to tests that only use `collapse()`
mjwestgate Feb 5, 2024
69304bb
remove problem links identified by win-builder
mjwestgate Feb 5, 2024
8a7b6be
use standard R version numbering
mjwestgate Feb 5, 2024
9e4e5d7
Merge branch 'main' into dev
mjwestgate Feb 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: galah
Type: Package
Title: Biodiversity Data from the GBIF Node Network
Version: 2.0.0
Version: 2.0.1
Authors@R:
c(person(given = "Martin",
family = "Westgate",
Expand Down
5 changes: 3 additions & 2 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ S3method(arrange,metadata_request)
S3method(collapse,data_request)
S3method(collapse,files_request)
S3method(collapse,metadata_request)
S3method(collect,computed_query)
S3method(collect,data_request)
S3method(collect,files_request)
S3method(collect,metadata_request)
S3method(collect,query)
S3method(collect,query_set)
S3method(compute,data_request)
S3method(compute,files_request)
S3method(compute,metadata_request)
S3method(compute,query)
S3method(compute,query_set)
S3method(count,data_request)
S3method(filter,data_request)
S3method(filter,files_request)
S3method(filter,metadata_request)
S3method(group_by,data_request)
S3method(identify,data_request)
S3method(identify,metadata_request)
S3method(print,computed_query)
S3method(print,data_request)
S3method(print,files_request)
S3method(print,galah_config)
Expand Down Expand Up @@ -139,6 +139,7 @@ importFrom(httr2,req_body_raw)
importFrom(httr2,req_error)
importFrom(httr2,req_headers)
importFrom(httr2,req_perform)
importFrom(httr2,req_timeout)
importFrom(httr2,request)
importFrom(httr2,resp_body_json)
importFrom(httr2,resp_body_string)
Expand Down
13 changes: 13 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# galah 2.0.1

### Minor improvements
`collapse()` now returns a `query` object, rather than a `query_set`,
and gains a `.expand` argument to optionally append a `query_set` for debugging
purposes (#217).

### Bug fixes
* Avoid triggering multiple errors when galah_identify() returns no matched taxa (#219)
* Improve clarity of quick start guide vignette (#221)
* show_values() no longer truncates rows to 30 (#222)
* Column ID name returned by search_all(lists) now matches the correct field ID for galah_filter() (#225)

# galah 2.0.0

### Object-oriented programming
Expand Down
5 changes: 1 addition & 4 deletions R/atlas_media.R
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,7 @@ atlas_media <- function(request = NULL,
present_fields <- media_fields
# if `select` is present, ensure that at least one 'media' field is requested
}else{
# new check using compute_checks()
x <- collapse(.query) |>
build_checks() |>
compute_checks()
x <- collapse(.query)

# now check whether valid fields are present
selected_fields <- x$url |>
Expand Down
62 changes: 62 additions & 0 deletions R/build_checks.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#' Internal function to build necessary metadata into a single object
#' I.e. to parse a `query_set` object within `collapse()`
#' @noRd
#' @keywords Internal
build_checks <- function(.query){
# get basic description of `query_set` object
n <- length(.query)
names_vec <- unlist(lapply(.query, function(a){a$type}))
# look for any `data`
data_lookup <- grepl("^data", names_vec)
if(any(data_lookup)){
data_names <- names_vec[data_lookup]
# parse any `metadata`
metadata_results <- parse_metadata(names_vec, .query)
# parse `data`, including supplied metadata
# this assumes only one `data` field is available per `query_set`
.query[[which(data_lookup)]] |>
add_metadata(metadata_results)
}else if(any(names_vec %in% c("metadata/fields-unnest",
"metadata/profiles-unnest",
"metadata/taxa-unnest"))){
# this code accounts for `unnest` functions that require lookups
# metadata/fields-unnest calls check_fields(), requiring fields and assertions
# metadata/profiles-unnest calls profile_short_name(), which requires profiles
if(length(.query) > 1){
metadata_results <- parse_metadata(names_vec, .query)
.query[[2]] |>
add_metadata(metadata_results)
}else{
.query[[1]]
}
}else{
# if no metadata are needed, return .query unaltered
.query[[1]]
}
}

#' Internal function to parse metadata
#' @noRd
#' @keywords Internal
parse_metadata <- function(names_vec, .query){
metadata_lookup <- grepl("^metadata", names_vec) &
!grepl("-unnest$", names_vec) # unnest functions only parse in collect()
if(any(metadata_lookup)){
metadata_names <- names_vec[metadata_lookup]
metadata_results <- lapply(.query[metadata_lookup], collect)
names(metadata_results) <- metadata_names
metadata_results
}else{
NULL
}
}

#' Internal function to pass metadata to `collapse()` functions
#' called by `compute.query_set()`
#' @noRd
#' @keywords Internal
add_metadata <- function(query, meta){
result <- c(query, meta)
class(result) <- "query"
return(result)
}
134 changes: 134 additions & 0 deletions R/build_query_set.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#' Internal function to build a `query_set` object
#' for object of class `data_request`
#' @noRd
#' @keywords Internal
build_query_set_data <- function(x, mint_doi, ...){
if(!missing(mint_doi)){
x$mint_doi <- mint_doi
}
# x$type <- check_type(x$type) # needed?
# handle sending dois via `filter()`
# important this happens first, as it affects `type` which affects later code
variables <- x$filter$variable
if(!is.null(variables)){
if(length(variables) == 1 & variables[1] == "doi"){
x$type <- "occurrences-doi"
}
}
# handle `run_checks`
fields_absent <- lapply(
x[c("arrange", "filter", "select", "group_by")],
is.null
) |>
unlist()
if (pour("package", "run_checks") & x$type != "occurrences-doi") {
# add check here to see whether any filters are specified
# it is possible to only call `identify()`, for example
if (any(!fields_absent) | x$type %in% c("species-count", "species")) {
result <- list(collapse_fields(), collapse_assertions())
} else {
# for living atlases, we need `collapse_fields()` to check the `lsid` field
# this isn't required for GBIF which doesn't use `fq` for taxon queries
if(!is.null(x$identify) &!is_gbif()){
result <- list(collapse_fields())
}else{
result <- list()
}
}
if (x$type %in% c("occurrences", "media", "species") &
atlas_supports_reasons_api()) {
result[[(length(result) + 1)]] <- collapse_reasons()
}
} else { # if select is required, we need fields even if `run_checks == FALSE`
if(!fields_absent[["select"]] | x$type %in% c("occurrences", "species")){
result <- list(collapse_fields(), collapse_assertions())
}else{
result <- list()
}
}
# handle `identify()`
if(!is.null(x$identify) & x$type != "occurrences-doi"){
result[[(length(result) + 1)]] <- collapse_taxa(list(identify = x$identify))
}
# handle `apply_profile()`
if(!is.null(x$data_profile)){
result[[(length(result) + 1)]] <- collapse_profiles()
}
# handle query
result[[(length(result) + 1)]] <- switch(
x$type,
"occurrences" = collapse_occurrences(x),
"occurrences-count" = collapse_occurrences_count(x),
"occurrences-doi" = collapse_occurrences_doi(x),
"species" = collapse_species(x),
"species-count" = collapse_species_count(x),
abort("unrecognised 'type'"))
class(result) <- "query_set"
result
}

#' Internal function to build a `query_set` object
#' for object of class `metadata_request`
#' @noRd
#' @keywords Internal
build_query_set_metadata <- function(x, ...){
if(pour("package", "run_checks")){
result <- switch(x$type,
"fields-unnest" = list(collapse_fields()),
"profiles-unnest" = list(collapse_profiles()),
list())
}else{
result <- list()
}
if(grepl("-unnest$", x$type)){
if(x$type == "taxa-unnest"){
# identify() calls must be parsed, irrespective of `run_checks` (which is parsed above)
if(!is.null(x$identify)){
result[[(length(result) + 1)]] <- collapse_taxa(x)
}
if(is.null(x$identify) & is.null(x$filter)){
abort("Requests of type `taxa-unnest` must also supply one of `filter()` or `identify()`.")
}
}else if(is.null(x$filter)){
current_type <- x$type
bullets <- glue("Requests of type `{current_type}` containing `unnest` must supply `filter()`.")
abort(bullets)
}
}
result[[(length(result) + 1)]] <- switch(x$type,
"apis" = collapse_apis(),
"assertions" = collapse_assertions(),
"atlases" = collapse_atlases(),
"collections" = collapse_collections(x),
"datasets" = collapse_datasets(x),
"fields" = collapse_fields(),
"fields-unnest" = collapse_fields_unnest(x),
"licences" = collapse_licences(),
"lists" = collapse_lists(x),
"lists-unnest" = collapse_lists_unnest(x),
"media" = collapse_media(x),
"profiles" = collapse_profiles(),
"profiles-unnest" = collapse_profiles_unnest(x),
"providers" = collapse_providers(x),
"ranks" = collapse_ranks(),
"reasons" = collapse_reasons(),
"taxa" = collapse_taxa(x),
"taxa-unnest" = collapse_taxa_unnest(x),
"identifiers" = collapse_identifiers(x),
abort("unrecognised 'type'")
)
class(result) <- "query_set"
result
}

#' Internal function to build a `query_set` object
#' for object of class `files_request`
#' @noRd
#' @keywords Internal
build_query_set_files <- function(x, ..., thumbnail){
result <- list(switch(x$type,
"media" = collapse_media_files(x, thumbnail = thumbnail)
))
class(result) <- "query_set"
result
}
8 changes: 7 additions & 1 deletion R/check.R
Original file line number Diff line number Diff line change
Expand Up @@ -359,14 +359,20 @@ check_identifiers_gbif_predicates <- function(.query){
#' @importFrom stringr str_replace_all
#' @noRd
#' @keywords Internal
check_identifiers_la <- function(.query){
check_identifiers_la <- function(.query, error_call = caller_env()){
url <- url_parse(.query$url[1]) # FIXME: test if every >1 urls here
queries <- url$query
if(!is.null(queries$fq)){
if(grepl("(`TAXON_PLACEHOLDER`)", queries$fq)){
metadata_lookup <- grepl("^metadata/taxa", names(.query))
if(any(metadata_lookup)){
identifiers <- .query[[which(metadata_lookup)[1]]]

# End query early when no taxonomic search terms were matched
if (nrow(identifiers) > 0 && !("taxon_concept_id" %in% colnames(identifiers))) {
abort("No valid taxonomic identifiers detected.", call = error_call)
}

taxa_ids <- build_taxa_query(identifiers$taxon_concept_id)
queries$fq <- str_replace_all(queries$fq,
"\\(`TAXON_PLACEHOLDER`\\)",
Expand Down
4 changes: 2 additions & 2 deletions R/check_queue.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ check_queue <- function(.query, wait = FALSE){
if(.query$status == "incomplete"){
download_response <- c(list(type = .query$type),
check_occurrence_status(.query))
class(download_response) <- "query"
class(download_response) <- "computed_query"
if(wait){
download_response <- c(list(type = .query$type),
check_queue_loop(.query))
class(download_response) <- "query"
class(download_response) <- "computed_query"
download_response
}else{
download_response
Expand Down