Skip to content

Commit f69a4ad

Browse files
committed
add more tests, fix doc
1 parent a038b97 commit f69a4ad

2 files changed

Lines changed: 65 additions & 33 deletions

File tree

r/R/dplyr-funcs-conditional.R

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,12 @@ parse_condition_formulas <- function(formulas, mask, fn) {
5252
list(query = query, value = value)
5353
}
5454

55-
# Create case_when Expression from query/value lists
55+
#' Create case_when Expression from query/value lists
56+
#' @param query List of logical Arrow Expressions.
57+
#' @param value List of value Arrow Expressions.
58+
#' @return An Arrow Expression representing the case_when.
59+
#' @keywords internal
60+
#' @noRd
5661
build_case_when_expr <- function(query, value) {
5762
Expression$create(
5863
"case_when",
@@ -67,16 +72,17 @@ build_case_when_expr <- function(query, value) {
6772
)
6873
}
6974

70-
# Build query/value lists from parallel from/to vectors.
71-
# NA values in `from` use is.na() for matching.
72-
# @param x Arrow Expression for the column to match against.
73-
# @param from Vector of values to match.
74-
# @param to Vector of replacement values (recycled to length of `from`).
75-
# @return list(query, value) for use with build_case_when_expr().
76-
# @examples
77-
# x_expr <- Expression$field_ref("x")
78-
# parse_from_to_mapping(x_expr, from = c("a", "b"), to = c("A", "B"))
79-
# @keywords internal
75+
#' Build query/value lists from parallel from/to vectors.
76+
#' NA values in `from` use is.na() for matching.
77+
#' @param x Arrow Expression for the column to match against.
78+
#' @param from Vector of values to match.
79+
#' @param to Vector of replacement values (recycled to length of `from`).
80+
#' @return list(query, value) for use with build_case_when_expr().
81+
#' @examples
82+
#' x_expr <- Expression$field_ref("x")
83+
#' parse_from_to_mapping(x_expr, from = c("a", "b"), to = c("A", "B"))
84+
#' @keywords internal
85+
#' @noRd
8086
parse_from_to_mapping <- function(x, from, to) {
8187
n <- length(from)
8288
to <- vctrs::vec_recycle(to, n)
@@ -94,18 +100,19 @@ parse_from_to_mapping <- function(x, from, to) {
94100
list(query = query, value = value)
95101
}
96102

97-
# Build query/value lists from value ~ replacement formulas.
98-
# NA values on LHS use is.na() for matching.
99-
# @param x Arrow Expression for the column to match against.
100-
# @param formulas List of two-sided formulas (value ~ replacement).
101-
# @param mask Data mask for evaluating formula expressions.
102-
# @param fn Calling function name (for error messages).
103-
# @return list(query, value) for use with build_case_when_expr().
104-
# @examples
105-
# x_expr <- Expression$field_ref("x")
106-
# mask <- rlang::new_data_mask(rlang::current_env())
107-
# parse_formula_mapping(x_expr, list("a" ~ "A", "b" ~ "B"), mask, "replace_values")
108-
# @keywords internal
103+
#' Build query/value lists from value ~ replacement formulas.
104+
#' NA values on LHS use is.na() for matching.
105+
#' @param x Arrow Expression for the column to match against.
106+
#' @param formulas List of two-sided formulas (value ~ replacement).
107+
#' @param mask Data mask for evaluating formula expressions.
108+
#' @param fn Calling function name (for error messages).
109+
#' @return list(query, value) for use with build_case_when_expr().
110+
#' @examples
111+
#' x_expr <- Expression$field_ref("x")
112+
#' mask <- rlang::new_data_mask(rlang::current_env())
113+
#' parse_formula_mapping(x_expr, list("a" ~ "A", "b" ~ "B"), mask, "replace_values")
114+
#' @keywords internal
115+
#' @noRd
109116
parse_formula_mapping <- function(x, formulas, mask, fn) {
110117
n <- length(formulas)
111118
query <- vector("list", n)
@@ -122,9 +129,12 @@ parse_formula_mapping <- function(x, formulas, mask, fn) {
122129
if (inherits(lhs, "Expression") && lhs$type_id() == Type[["NA"]]) {
123130
# NA evaluated to an Arrow NA Expression
124131
query[[i]] <- call_binding("is.na", x)
125-
} else if (!inherits(lhs, "Expression") && is.na(lhs)) {
132+
} else if (!inherits(lhs, "Expression") && length(lhs) == 1 && is.na(lhs)) {
126133
# NA is a bare R value
127134
query[[i]] <- call_binding("is.na", x)
135+
} else if (!inherits(lhs, "Expression") && length(lhs) > 1) {
136+
# Vector LHS: c("a", "b") ~ "X" matches any value in the vector
137+
query[[i]] <- call_binding("%in%", x, lhs)
128138
} else {
129139
query[[i]] <- x == lhs
130140
}
@@ -133,15 +143,16 @@ parse_formula_mapping <- function(x, formulas, mask, fn) {
133143
list(query = query, value = value)
134144
}
135145

136-
# Dispatch to formula or from/to parser based on which args are provided.
137-
# Returns list(query, value) or NULL if no mappings.
138-
# @param x Arrow Expression for the column to match against.
139-
# @param formulas List of two-sided formulas (value ~ replacement).
140-
# @param from Vector of values to match (alternative to formulas).
141-
# @param to Vector of replacement values (used with `from`).
142-
# @param mask Data mask for evaluating formula expressions.
143-
# @param fn Calling function name (for error messages).
144-
# @keywords internal
146+
#' Dispatch to formula or from/to parser based on which args are provided.
147+
#' Returns list(query, value) or NULL if no mappings.
148+
#' @param x Arrow Expression for the column to match against.
149+
#' @param formulas List of two-sided formulas (value ~ replacement).
150+
#' @param from Vector of values to match (alternative to formulas).
151+
#' @param to Vector of replacement values (used with `from`).
152+
#' @param mask Data mask for evaluating formula expressions.
153+
#' @param fn Calling function name (for error messages).
154+
#' @keywords internal
155+
#' @noRd
145156
parse_value_mapping <- function(x, formulas = list(), from = NULL, to = NULL, mask, fn) {
146157
# Mutually exclusive interfaces
147158
if (length(formulas) > 0 && !is.null(from)) {

r/tests/testthat/test-dplyr-funcs-conditional.R

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,14 @@ test_that("replace_values()", {
613613
tbl
614614
)
615615

616+
# multiple values on LHS matches any
617+
compare_dplyr_binding(
618+
.input |>
619+
mutate(result = replace_values(chr, c("a", "b") ~ "AB")) |>
620+
collect(),
621+
tbl
622+
)
623+
616624
# no replacements returns x unchanged
617625
compare_dplyr_binding(
618626
.input |>
@@ -675,7 +683,20 @@ test_that("recode_values()", {
675683
tbl
676684
)
677685

686+
# multiple values on LHS matches any
687+
compare_dplyr_binding(
688+
.input |>
689+
mutate(result = recode_values(chr, c("a", "b") ~ "AB", default = "other")) |>
690+
collect(),
691+
tbl
692+
)
693+
678694
# validation errors
695+
expect_arrow_eval_error(
696+
recode_values(chr),
697+
"`\\.\\.\\.` can't be empty",
698+
class = "validation_error"
699+
)
679700
expect_arrow_eval_error(
680701
recode_values(chr, "a" ~ "A", from = "b"),
681702
"Can't use both `...` and `from`/`to` in recode_values\\(\\)",

0 commit comments

Comments
 (0)