diff --git a/R/request.R b/R/request.R index 98d48d3..c3a9c6e 100644 --- a/R/request.R +++ b/R/request.R @@ -90,6 +90,16 @@ as_onet_tibble <- function(x) { if (length(x) == 0) { return(tibble()) } + + # Handle NULL columns by converting them to NA vectors + # This prevents as_tibble() from erroring on NULL values + if (is.list(x) && !is.data.frame(x)) { + # For named lists, replace NULL values with NA + x <- lapply(x, function(col) { + if (is.null(col)) NA else col + }) + } + tbl <- as_tibble(x) names(tbl) <- to_snake_case(names(tbl)) tbl diff --git a/R/search.R b/R/search.R index f02cc01..f5d1301 100644 --- a/R/search.R +++ b/R/search.R @@ -10,7 +10,6 @@ #' \describe{ #' \item{code}{O*NET-SOC occupation code} #' \item{title}{Occupation title} -#' \item{relevance_score}{Search relevance score (if keyword search)} #' } #' #' @export @@ -33,8 +32,7 @@ onet_search <- function(keyword, start = 1, end = 20) { # Define expected schema for empty results schema <- empty_tibble( code = character(), - title = character(), - relevance_score = numeric() + title = character() ) # Extract data with schema @@ -44,17 +42,9 @@ onet_search <- function(keyword, start = 1, end = 20) { } results <- map(resp$occupation, \(x) { - # Try multiple field names for relevance score - relevance <- x$relevance_score %||% - x$relevanceScore %||% - x$relevance %||% - x$score %||% - NA_real_ - tibble( code = x$code %||% NA_character_, - title = x$title %||% NA_character_, - relevance_score = relevance + title = x$title %||% NA_character_ ) }) |> list_rbind() diff --git a/README.md b/README.md index 0f15b7d..cc001b0 100644 --- a/README.md +++ b/README.md @@ -72,12 +72,12 @@ library(onet2r) # Search for software-related occupations results <- onet_search("software developer") results -#> # A tibble: 20 × 3 -#> code title relevance_score -#> -#> 1 15-1252.00 Software Developers 100 -#> 2 15-1251.00 Computer Programmers 95 -#> 3 15-1256.00 Software Quality Assurance Analysts… 92 +#> # A tibble: 20 × 2 +#> code title +#> +#> 1 15-1252.00 Software Developers +#> 2 15-1251.00 Computer Programmers +#> 3 15-1256.00 Software Quality Assurance Analysts… #> # ℹ 17 more rows # Search by O*NET-SOC code @@ -185,8 +185,8 @@ onet_skills("invalid-code") results <- onet_search("xyzabc123nonexistent") #> No occupations found for keyword: "xyzabc123nonexistent" results -#> # A tibble: 0 × 3 -#> # ℹ 3 variables: code , title , relevance_score +#> # A tibble: 0 × 2 +#> # ℹ 2 variables: code , title ``` API errors are automatically handled with: @@ -217,8 +217,7 @@ library(dplyr) # Find occupations related to "data" results <- onet_search("data analyst") |> - filter(relevance_score > 80) |> - arrange(desc(relevance_score)) + arrange(title) # Get skills for multiple occupations codes <- c("15-1252.00", "15-1251.00") diff --git a/man/onet_search.Rd b/man/onet_search.Rd index 1187453..0b60b88 100644 --- a/man/onet_search.Rd +++ b/man/onet_search.Rd @@ -18,7 +18,6 @@ A tibble with columns: \describe{ \item{code}{O*NET-SOC occupation code} \item{title}{Occupation title} -\item{relevance_score}{Search relevance score (if keyword search)} } } \description{ diff --git a/tests/testthat/test-helpers.R b/tests/testthat/test-helpers.R index bbd6572..3d1dc9a 100644 --- a/tests/testthat/test-helpers.R +++ b/tests/testthat/test-helpers.R @@ -60,6 +60,25 @@ test_that("as_onet_tibble converts column names", { expect_equal(result$first_name, "John") }) +test_that("as_onet_tibble handles NULL columns", { + # Test with NULL values in list - simulates API returning NULL for a field + input <- list( + code = "15-1252.00", + title = "Software Developer", + not_relevant = NULL, + scale_id = "IM" + ) + + # Should convert NULL to NA without error + result <- onet2r:::as_onet_tibble(input) + expect_s3_class(result, "tbl_df") + expect_equal(nrow(result), 1) + expect_equal(result$code, "15-1252.00") + expect_equal(result$title, "Software Developer") + expect_true(is.na(result$not_relevant)) + expect_equal(result$scale_id, "IM") +}) + test_that("extract_list_data handles empty results", { # Test with NULL data resp_null <- list(occupation = NULL) diff --git a/vignettes/getting-started.Rmd b/vignettes/getting-started.Rmd index ae9d0d5..61174bd 100644 --- a/vignettes/getting-started.Rmd +++ b/vignettes/getting-started.Rmd @@ -74,7 +74,7 @@ software_jobs <- onet_search("software developer") software_jobs ``` -This returns a tibble with occupation codes, titles, and relevance scores. The results are ordered by relevance to your search term. +This returns a tibble with occupation codes and titles. You can control the number of results: @@ -333,8 +333,8 @@ results <- onet_search("xyznonexistent123") # Still returns a properly structured tibble results -#> # A tibble: 0 × 3 -#> # ℹ 3 variables: code , title , relevance_score +#> # A tibble: 0 × 2 +#> # ℹ 2 variables: code , title # You can safely use it in pipelines nrow(results) #> [1] 0 @@ -365,8 +365,7 @@ library(tidyr) library(ggplot2) # Find healthcare occupations and analyze skills -healthcare <- onet_search("healthcare", start = 1, end = 20) |> - filter(relevance_score > 70) +healthcare <- onet_search("healthcare", start = 1, end = 20) # Get skills for top 5 occupations skills <- healthcare |>