Skip to content

Commit 96a82a6

Browse files
authored
Merge pull request #460 from Crunch-io/expr-as-methods
Expr as methods
2 parents 24d9187 + 875dfdc commit 96a82a6

File tree

4 files changed

+174
-2
lines changed

4 files changed

+174
-2
lines changed

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ S3method(as.array,CrunchCube)
1010
S3method(as.array,CrunchCubeCalculation)
1111
S3method(as.array,MultitableResult)
1212
S3method(as.array,TabBookResult)
13+
S3method(as.character,CrunchExpr)
1314
S3method(as.character,CrunchVariable)
1415
S3method(as.data.frame,BatchCatalog)
1516
S3method(as.data.frame,CrunchDataFrame)
@@ -18,6 +19,7 @@ S3method(as.data.frame,FilterCatalog)
1819
S3method(as.data.frame,ShojiCatalog)
1920
S3method(as.data.frame,UserCatalog)
2021
S3method(as.data.frame,VariableCatalog)
22+
S3method(as.double,CrunchExpr)
2123
S3method(as.double,CrunchVariable)
2224
S3method(as.list,CrunchDataset)
2325
S3method(as.list,OrderGroup)

R/variable-as-methods.R

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
#' @param ... additional arguments for `as.character` and `as.numeric`, ignored when used with
3030
#' Crunch variables
3131
#'
32-
#' @return a `VariableDefinition` to be used as the derivation
32+
#' @return a `CrunchExpr` to be used as the derivation
3333
#'
3434
#' @examples
3535
#' \dontrun{
@@ -138,3 +138,71 @@ as.double.CrunchVariable <- function(x, ...) as.Numeric(x)
138138
#' @rdname variable-as-methods
139139
#' @export
140140
as.character.CrunchVariable <- function(x, ...) as.Text(x)
141+
142+
# Expressions ----
143+
#' @rdname variable-as-methods
144+
#' @export
145+
setMethod("as.Numeric", "CrunchExpr", function(x) {
146+
return(zfuncExpr("cast", x, "numeric"))
147+
})
148+
149+
#' @rdname variable-as-methods
150+
#' @export
151+
setMethod("as.Text", "CrunchExpr", function(x, format) {
152+
# format is for DateTimes only, but we have to rely on user
153+
# doing this correctly because we can't tell for an expression
154+
if (!missing(format)) {
155+
return(zfuncExpr("format_datetime", x, list(value = format)))
156+
}
157+
158+
return(zfuncExpr("cast", x, "text"))
159+
})
160+
161+
#' @rdname variable-as-methods
162+
#' @export
163+
setMethod("as.Categorical", "CrunchExpr", function(x, format) {
164+
# format is for DateTimes only, but we have to rely on user
165+
# doing this correctly because we can't tell for an expression
166+
# no direct datetime to cat ZCL function, so must format first then cast
167+
if (!missing(format)) {
168+
x <- zfunc("format_datetime", x, list(value = format))
169+
}
170+
171+
return(zfuncExpr("cast", x, "categorical"))
172+
})
173+
174+
#' @rdname variable-as-methods
175+
#' @export
176+
setMethod(
177+
"as.Datetime", "CrunchExpr",
178+
function(x, format, resolution, offset) {
179+
# datetimes are special, so each source type must be determined
180+
# resolution non-missing indicate numeric
181+
# format non-missing indicates categorical/text
182+
if (missing(format) & !missing(resolution)) {
183+
validateResolution(resolution)
184+
185+
args <- list("numeric_to_datetime", x, list(value = resolution))
186+
if (!missing(offset)) {
187+
args <- append(args, list(list(value = offset)))
188+
}
189+
190+
return(do.call(zfuncExpr, args))
191+
} else if (!missing(format) & missing(resolution) & missing(offset)) {
192+
return(zfuncExpr("parse_datetime", x, list(value = format)))
193+
}
194+
195+
halt(
196+
"Invalid arguments to `as.Datetime`. Must provide either `resolution` for Numeric ",
197+
"expressions or `format` for Categorical/Text expressions."
198+
)
199+
}
200+
)
201+
202+
#' @rdname variable-as-methods
203+
#' @export
204+
as.double.CrunchExpr <- function(x, ...) as.Numeric(x)
205+
206+
#' @rdname variable-as-methods
207+
#' @export
208+
as.character.CrunchExpr <- function(x, ...) as.Text(x)

man/variable-as-methods.Rd

Lines changed: 19 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-variable-as-methods.R

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,70 @@ with_mock_crunch({
173173
})
174174
})
175175

176+
test_that("cast expressions modifies zcl expression", {
177+
# simple expression, which we'll reuse even if it wouldn't actually work in
178+
# a real cast
179+
this_expr <- CrunchExpr(expression = zfunc("now"))
180+
181+
expect_equal(
182+
as.Numeric(this_expr),
183+
CrunchExpr(expression = zfunc("cast", this_expr, "numeric"))
184+
)
185+
186+
expect_equal(
187+
as.Text(this_expr),
188+
CrunchExpr(expression = zfunc("cast", this_expr, "text"))
189+
)
190+
191+
expect_equal(
192+
as.Text(this_expr, format = "%Y-%m-%d %H:%M:%S"),
193+
CrunchExpr(
194+
expression = zfunc("format_datetime", this_expr, list(value = "%Y-%m-%d %H:%M:%S"))
195+
)
196+
)
197+
198+
expect_equal(
199+
as.Categorical(this_expr),
200+
CrunchExpr(expression = zfunc("cast", this_expr, "categorical"))
201+
)
202+
203+
expect_equal(
204+
as.Categorical(this_expr, format = "%Y-%m-%d %H:%M:%S"),
205+
CrunchExpr(
206+
expression = zfunc(
207+
"cast",
208+
zfunc("format_datetime", this_expr, list(value = "%Y-%m-%d %H:%M:%S")),
209+
"categorical"
210+
)
211+
)
212+
)
213+
214+
expect_equal(
215+
as.Datetime(this_expr, format = "%Y-%m-%d %H:%M:%S"),
216+
CrunchExpr(
217+
expression = zfunc("parse_datetime", this_expr, list(value = "%Y-%m-%d %H:%M:%S"))
218+
)
219+
)
220+
221+
expect_equal(
222+
as.Datetime(this_expr, resolution = "D", offset = "1975-01-01"),
223+
CrunchExpr(
224+
expression = zfunc(
225+
"numeric_to_datetime", this_expr, list(value = "D"), list(value = "1975-01-01")
226+
)
227+
)
228+
)
229+
230+
expect_error(as.Datetime(this_expr), "Invalid arguments to `as.Datetime`")
231+
232+
# R base aliases
233+
expect_equal(as.Numeric(this_expr), as.numeric(this_expr))
234+
expect_equal(as.Text(this_expr), as.character(this_expr))
235+
})
236+
237+
238+
239+
176240
with_test_authentication({
177241
ds <- newDataset(df)
178242
# make a text variable with numbers
@@ -317,4 +381,24 @@ with_test_authentication({
317381
cubify(10, 11, dims = list(v4 = list("B", "C")))
318382
)
319383
})
384+
385+
test_that("categorical expression to numeric", {
386+
ds$v3_gt_ten_num <- as.Numeric(ds$v3 > 10)
387+
expect_true(is.derived(ds$v3_gt_ten_num))
388+
expect_true(is.Numeric(ds$v3_gt_ten_num))
389+
expect_equal(
390+
as.vector(ds$v3_gt_ten_num),
391+
as.numeric(as.vector(ds$v3 > 10))
392+
)
393+
})
394+
395+
test_that("numeric expression to text", {
396+
ds$v3_plus_one_text <- as.Text(ds$v3 + 1)
397+
expect_true(is.derived(ds$v3_plus_one_text))
398+
expect_true(is.Text(ds$v3_plus_one_text))
399+
expect_equal(
400+
as.vector(ds$v3_plus_one_text),
401+
sprintf("%1.1f", as.vector(ds$v3 + 1))
402+
)
403+
})
320404
})

0 commit comments

Comments
 (0)