Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions R/request.R
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 2 additions & 12 deletions R/search.R
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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()

Expand Down
19 changes: 9 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
#> <chr> <chr> <dbl>
#> 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
#> <chr> <chr>
#> 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
Expand Down Expand Up @@ -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 <chr>, title <chr>, relevance_score <dbl>
#> # A tibble: 0 × 2
#> # ℹ 2 variables: code <chr>, title <chr>
```

API errors are automatically handled with:
Expand Down Expand Up @@ -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")
Expand Down
1 change: 0 additions & 1 deletion man/onet_search.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions tests/testthat/test-helpers.R
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 4 additions & 5 deletions vignettes/getting-started.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -333,8 +333,8 @@ results <- onet_search("xyznonexistent123")

# Still returns a properly structured tibble
results
#> # A tibble: 0 × 3
#> # ℹ 3 variables: code <chr>, title <chr>, relevance_score <dbl>
#> # A tibble: 0 × 2
#> # ℹ 2 variables: code <chr>, title <chr>

# You can safely use it in pipelines
nrow(results) #> [1] 0
Expand Down Expand Up @@ -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 |>
Expand Down