Skip to content

Commit 77b265b

Browse files
committed
feat+bugs: add epix_as_of_now()
* fix yearmonth in epix_as_of and epix_slide \
1 parent 0ec829c commit 77b265b

8 files changed

+168
-16
lines changed

NAMESPACE

+3
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export(epi_slide_mean)
7373
export(epi_slide_opt)
7474
export(epi_slide_sum)
7575
export(epix_as_of)
76+
export(epix_as_of_now)
7677
export(epix_fill_through_version)
7778
export(epix_merge)
7879
export(epix_slide)
@@ -95,6 +96,7 @@ export(new_epi_df)
9596
export(relocate)
9697
export(rename)
9798
export(revision_summary)
99+
export(set_versions_end)
98100
export(slice)
99101
export(sum_groups_epi_df)
100102
export(time_column_names)
@@ -245,6 +247,7 @@ importFrom(tidyselect,eval_select)
245247
importFrom(tidyselect,starts_with)
246248
importFrom(tools,toTitleCase)
247249
importFrom(tsibble,as_tsibble)
250+
importFrom(tsibble,yearmonth)
248251
importFrom(utils,capture.output)
249252
importFrom(utils,tail)
250253
importFrom(vctrs,"vec_slice<-")

R/grouped_epi_archive.R

+5-1
Original file line numberDiff line numberDiff line change
@@ -437,9 +437,13 @@ epix_slide.grouped_epi_archive <- function(
437437
out <- lapply(.versions, function(.version) {
438438
# Ungrouped as-of data; `epi_df` if `all_versions` is `FALSE`,
439439
# `epi_archive` if `all_versions` is `TRUE`:
440+
min_time_value <- .version - .before
441+
if (is.na(min_time_value)) {
442+
min_time_value <- -Inf
443+
}
440444
as_of_raw <- .x$private$ungrouped %>% epix_as_of(
441445
.version,
442-
min_time_value = .version - .before,
446+
min_time_value = min_time_value,
443447
all_versions = .all_versions
444448
)
445449

R/methods-epi_archive.R

+69-14
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,9 @@
5959
#'
6060
#' @importFrom data.table between key
6161
#' @export
62-
epix_as_of <- function(x, version = NULL, min_time_value = -Inf, all_versions = FALSE,
62+
epix_as_of <- function(x, version, min_time_value = -Inf, all_versions = FALSE,
6363
max_version = deprecated()) {
6464
assert_class(x, "epi_archive")
65-
version <- version %||% x$versions_end
6665

6766
if (lifecycle::is_present(max_version)) {
6867
lifecycle::deprecate_warn("0.8.1", "epix_as_of(max_version =)", "epix_as_of(version =)")
@@ -114,26 +113,79 @@ epix_as_of <- function(x, version = NULL, min_time_value = -Inf, all_versions =
114113
if (all_versions) {
115114
# epi_archive is copied into result, so we can modify result directly
116115
result <- epix_truncate_versions_after(x, version)
117-
result$DT <- result$DT[time_value >= .min_time_value, ] # nolint: object_usage_linter
116+
if (!identical(.min_time_value, -Inf)) {
117+
# See below for why we need this branch.
118+
result$DT <- result$DT[time_value >= .min_time_value, ] # nolint: object_usage_linter
119+
}
118120
return(result)
119121
}
120122

121123
# Make sure to use data.table ways of filtering and selecting
122-
as_of_epi_df <- x$DT[time_value >= .min_time_value & version <= .version, ] %>% # nolint: object_usage_linter
123-
unique(
124-
by = c("geo_value", "time_value", other_keys),
125-
fromLast = TRUE
126-
) %>%
124+
as_of_epi_df <- if (identical(.min_time_value, -Inf)) {
125+
# This branch is needed for `epix_as_of` to work with `yearmonth` time type
126+
# to avoid time_value > .min_time_value, which is NA for `yearmonth`.
127+
x$DT[version <= .version, ]
128+
} else {
129+
x$DT[time_value >= .min_time_value & version <= .version, ]
130+
} # nolint: object_usage_linter
131+
as_of_epi_df <- as_of_epi_df %>%
132+
unique(by = c("geo_value", "time_value", other_keys), fromLast = TRUE) %>%
127133
tibble::as_tibble() %>%
128134
dplyr::select(-"version") %>%
129-
as_epi_df(
130-
as_of = version,
131-
other_keys = other_keys
132-
)
135+
as_epi_df(as_of = .version, other_keys = other_keys)
133136

134137
return(as_of_epi_df)
135138
}
136139

140+
#' Get the latest snapshot from an `epi_archive` object, using
141+
#' the current time value for the time type.
142+
#'
143+
#' @param x An `epi_archive` object
144+
#' @return The latest snapshot from an `epi_archive` object
145+
#' @export
146+
epix_as_of_now <- function(x) {
147+
current_time_value <- current_time_value(x)
148+
x %>%
149+
set_versions_end(current_time_value) %>%
150+
epix_as_of(current_time_value)
151+
}
152+
153+
#' Get the latest time value for an `epi_archive` object
154+
#'
155+
#' @param x An `epi_archive` object
156+
#' @return The latest time value for an `epi_archive` object
157+
#' @importFrom tsibble yearmonth
158+
#' @noRd
159+
#' @keywords internal
160+
current_time_value <- function(x) {
161+
if (x$time_type == "day") {
162+
Sys.Date()
163+
} else if (x$time_type == "week") {
164+
max(seq(from = max(x$DT$time_value), to = Sys.Date(), by = "week"))
165+
} else if (x$time_type == "yearmonth") {
166+
yearmonth(Sys.Date())
167+
} else if (x$time_type == "integer") {
168+
cli_abort("Unable to determine the latest time value for an integer time type. Use `epix_as_of` instead.")
169+
} else {
170+
cli_abort("Unsupported time type in column `{time_value_arg}`, with class {.code {class(time_value)}}.
171+
Time-related functionality may have unexpected behavior.
172+
", class = "epiprocess__epix_as_of_now_unsupported_time_type")
173+
}
174+
}
175+
176+
#' Set the `versions_end` attribute of an `epi_archive` object
177+
#'
178+
#' An escape hatch for epix_as_of, which does not allow version >
179+
#' `$versions_end`.
180+
#'
181+
#' @param x An `epi_archive` object
182+
#' @param versions_end The new `versions_end` value
183+
#' @return An `epi_archive` object with the updated `versions_end` attribute
184+
#' @export
185+
set_versions_end <- function(x, versions_end) {
186+
x$versions_end <- versions_end
187+
x
188+
}
137189

138190
#' Fill `epi_archive` unobserved history
139191
#'
@@ -880,10 +932,13 @@ epix_slide.epi_archive <- function(
880932
#' @noRd
881933
epix_slide_versions_default <- function(ea) {
882934
versions_with_updates <- c(ea$DT$version, ea$versions_end)
883-
tidyr::full_seq(versions_with_updates, guess_period(versions_with_updates))
935+
if (ea$time_type == "yearmonth") {
936+
min(versions_with_updates) + seq(0, max(versions_with_updates) - min(versions_with_updates), by = 1)
937+
} else {
938+
tidyr::full_seq(versions_with_updates, guess_period(versions_with_updates))
939+
}
884940
}
885941

886-
887942
#' Filter an `epi_archive` object to keep only older versions
888943
#'
889944
#' Generates a filtered `epi_archive` from an `epi_archive` object, keeping

man/epix_as_of.Rd

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/epix_as_of_now.Rd

+19
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/set_versions_end.Rd

+20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# epix_as_of_now works as expected
2+
3+
Code
4+
attr(df %>% as_epi_archive() %>% epix_as_of_now(), "metadata")$as_of
5+
Condition
6+
Error in `current_time_value()`:
7+
! Unable to determine the latest time value for an integer time type. Use `epix_as_of` instead.
8+

tests/testthat/test-methods-epi_archive.R

+43
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,46 @@ test_that("group_vars works as expected", {
128128
"geo_value"
129129
)
130130
})
131+
132+
test_that("epix_as_of_now works as expected", {
133+
local_mocked_bindings(
134+
Sys.Date = function(...) {
135+
as.Date("2020-06-08")
136+
},
137+
.package = "base"
138+
)
139+
expect_equal(
140+
attr(ea2_data %>% as_epi_archive() %>% epix_as_of_now(), "metadata")$as_of,
141+
as.Date("2020-06-08")
142+
)
143+
time_value <- as.Date("2020-06-01")
144+
df <- dplyr::tribble(
145+
~geo_value, ~time_value, ~version, ~cases,
146+
"ca", time_value, time_value, 1,
147+
"ca", time_value + 7, time_value + 7, 2,
148+
)
149+
expect_equal(
150+
attr(df %>% as_epi_archive() %>% epix_as_of_now(), "metadata")$as_of,
151+
as.Date("2020-06-08")
152+
)
153+
time_value <- tsibble::yearmonth(as.Date("2020-06-01") - lubridate::month(1))
154+
df <- dplyr::tribble(
155+
~geo_value, ~time_value, ~version, ~cases,
156+
"ca", time_value, time_value, 1,
157+
"ca", time_value + lubridate::month(1), time_value + lubridate::month(1), 2,
158+
)
159+
expect_equal(
160+
attr(df %>% as_epi_archive() %>% epix_as_of_now(), "metadata")$as_of,
161+
tsibble::yearmonth("2020-06")
162+
)
163+
time_value <- 202006
164+
df <- dplyr::tribble(
165+
~geo_value, ~time_value, ~version, ~cases,
166+
"ca", time_value, time_value, 1,
167+
"ca", time_value + 7, time_value + 7, 2,
168+
)
169+
expect_snapshot(
170+
error = TRUE,
171+
attr(df %>% as_epi_archive() %>% epix_as_of_now(), "metadata")$as_of
172+
)
173+
})

0 commit comments

Comments
 (0)