Skip to content

Commit 795229c

Browse files
Copilotkrlmlr
andauthored
chore: Implement zoom v2 with internal dm_zoom2_to(), dm_update_zoom2ed(), dm_insert_zoom2ed(), dm_discard_zoom2ed() (#2399)
* Initial plan * feat: implement `dm_zoom2_to()`, `dm_update_zoom2ed()`, and `dm_insert_zoom2ed()` Co-authored-by: krlmlr <1741643+krlmlr@users.noreply.github.com> * Remove col_tracker attribute, add comprehensive dplyr verb snapshot tests Co-authored-by: krlmlr <1741643+krlmlr@users.noreply.github.com> * Rewrite dplyr verb tests: simple explicit tests, expand with right_join, full_join, relocate, group_by, count, 3-table join Co-authored-by: krlmlr <1741643+krlmlr@users.noreply.github.com> * Fix test names for consistency Co-authored-by: krlmlr <1741643+krlmlr@users.noreply.github.com> * Fix: uuid-based registry for attr-stripping verbs, 3-table joins, add missing verb tests Co-authored-by: krlmlr <1741643+krlmlr@users.noreply.github.com> * Use exists() instead of intersect() for uuid cleanup Co-authored-by: krlmlr <1741643+krlmlr@users.noreply.github.com> * Drop registry, store zoom2 info in dm_key_info, use cli::cli_abort, add dm_discard_zoom2ed Co-authored-by: krlmlr <1741643+krlmlr@users.noreply.github.com> * Don't export for now * Silent --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: krlmlr <1741643+krlmlr@users.noreply.github.com> Co-authored-by: Kirill Müller <krlmlr@users.noreply.github.com> Co-authored-by: Kirill Müller <kirill@cynkra.com>
1 parent 5c96021 commit 795229c

5 files changed

Lines changed: 2440 additions & 12 deletions

File tree

R/deconstruct.R

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ new_keyed_tbl <- function(
5454
uks = NULL,
5555
fks_in = NULL,
5656
fks_out = NULL,
57-
uuid = NULL
57+
uuid = NULL,
58+
zoom2 = NULL
5859
) {
5960
check_dots_empty()
6061

@@ -68,14 +69,20 @@ new_keyed_tbl <- function(
6869
}
6970

7071
class(x) <- unique(c("dm_keyed_tbl", class(x)))
71-
attr(x, "dm_key_info") <- list(
72+
dm_key_info <- list(
7273
pk = pk,
7374
uks = uks,
7475
fks_in = fks_in,
7576
fks_out = fks_out,
7677
uuid = uuid
7778
)
7879

80+
if (!is.null(zoom2)) {
81+
dm_key_info$zoom2 <- zoom2
82+
}
83+
84+
attr(x, "dm_key_info") <- dm_key_info
85+
7986
x
8087
}
8188

@@ -85,7 +92,8 @@ new_keyed_tbl_from_keys_info <- function(tbl, keys_info) {
8592
pk = keys_info$pk,
8693
fks_in = keys_info$fks_in,
8794
fks_out = keys_info$fks_out,
88-
uuid = keys_info$uuid
95+
uuid = keys_info$uuid,
96+
zoom2 = keys_info$zoom2
8997
)
9098
}
9199

R/dplyr.R

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,8 @@ summarise.dm_keyed_tbl <- function(.data, ..., .by = NULL, .groups = NULL) {
458458
new_keyed_tbl(
459459
summarised_tbl,
460460
pk = new_pk,
461-
uuid = keys_info$uuid
461+
uuid = keys_info$uuid,
462+
zoom2 = keys_info$zoom2
462463
)
463464
}
464465

@@ -492,7 +493,8 @@ reframe.dm_keyed_tbl <- function(.data, ..., .by = NULL) {
492493
# so the primary key is not preserved
493494
new_keyed_tbl(
494495
reframed_tbl,
495-
uuid = keys_info$uuid
496+
uuid = keys_info$uuid,
497+
zoom2 = keys_info$zoom2
496498
)
497499
}
498500

@@ -555,7 +557,8 @@ count.dm_keyed_tbl <- function(
555557
counted_tbl <- count(tbl, ..., wt = {{ wt }}, sort = sort, name = name, .drop = .drop)
556558
new_keyed_tbl(
557559
counted_tbl,
558-
uuid = keys_info$uuid
560+
uuid = keys_info$uuid,
561+
zoom2 = keys_info$zoom2
559562
)
560563
}
561564

@@ -589,7 +592,8 @@ tally.dm_keyed_tbl <- function(x, wt = NULL, sort = FALSE, name = NULL) {
589592
tallied_tbl <- tally(tbl, wt = {{ wt }}, sort = sort, name = name)
590593
new_keyed_tbl(
591594
tallied_tbl,
592-
uuid = keys_info$uuid
595+
uuid = keys_info$uuid,
596+
zoom2 = keys_info$zoom2
593597
)
594598
}
595599

@@ -729,7 +733,8 @@ left_join.dm_keyed_tbl <- function(
729733
pk = join_spec$new_pk,
730734
fks_in = join_spec$new_fks_in,
731735
fks_out = join_spec$new_fks_out,
732-
uuid = join_spec$new_uuid
736+
uuid = join_spec$new_uuid,
737+
zoom2 = keyed_get_info(x)$zoom2
733738
)
734739
}
735740

@@ -822,7 +827,8 @@ inner_join.dm_keyed_tbl <- function(
822827
pk = join_spec$new_pk,
823828
fks_in = join_spec$new_fks_in,
824829
fks_out = join_spec$new_fks_out,
825-
uuid = join_spec$new_uuid
830+
uuid = join_spec$new_uuid,
831+
zoom2 = keyed_get_info(x)$zoom2
826832
)
827833
}
828834

@@ -910,7 +916,8 @@ full_join.dm_keyed_tbl <- function(
910916
pk = join_spec$new_pk,
911917
fks_in = join_spec$new_fks_in,
912918
fks_out = join_spec$new_fks_out,
913-
uuid = join_spec$new_uuid
919+
uuid = join_spec$new_uuid,
920+
zoom2 = keyed_get_info(x)$zoom2
914921
)
915922
}
916923

@@ -1003,7 +1010,8 @@ right_join.dm_keyed_tbl <- function(
10031010
pk = join_spec$new_pk,
10041011
fks_in = join_spec$new_fks_in,
10051012
fks_out = join_spec$new_fks_out,
1006-
uuid = join_spec$new_uuid
1013+
uuid = join_spec$new_uuid,
1014+
zoom2 = keyed_get_info(x)$zoom2
10071015
)
10081016
}
10091017

@@ -1198,7 +1206,8 @@ cross_join.dm_keyed_tbl <- function(x, y, ..., copy = NULL, suffix = c(".x", ".y
11981206

11991207
new_keyed_tbl(
12001208
joined_tbl,
1201-
uuid = keyed_get_info(x)$uuid
1209+
uuid = keyed_get_info(x)$uuid,
1210+
zoom2 = keyed_get_info(x)$zoom2
12021211
)
12031212
}
12041213

R/zoom2.R

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#' Mark table for manipulation (v2)
2+
#'
3+
#' @description
4+
#' `r lifecycle::badge("experimental")`
5+
#'
6+
#' `dm_zoom2_to()` zooms to the given table, returning a keyed table
7+
#' that has the dm object as an attribute.
8+
#' Key column tracking (primary and foreign) is the responsibility
9+
#' of the `dm_keyed_tbl` object.
10+
#'
11+
#' `dm_update_zoom2ed()` overwrites the originally zoomed table
12+
#' with the manipulated table.
13+
#'
14+
#' `dm_insert_zoom2ed()` adds the manipulated table as a new table to the dm.
15+
#'
16+
#' `dm_discard_zoom2ed()` discards the zoomed table and returns the
17+
#' original `dm` as it was before zooming.
18+
#'
19+
#' @inheritParams dm_zoom_to
20+
#'
21+
#' @return For `dm_zoom2_to()`: A `dm_keyed_tbl` object with zoom2 info
22+
#' stored in `dm_key_info`.
23+
#'
24+
#' @noRd
25+
#' @examplesIf rlang::is_installed(c("nycflights13", "DiagrammeR"))
26+
#' flights_keyed <- dm_zoom2_to(dm_nycflights13(), flights)
27+
#'
28+
#' flights_keyed
29+
#'
30+
#' flights_keyed_transformed <-
31+
#' flights_keyed %>%
32+
#' mutate(am_pm_dep = ifelse(dep_time < 1200, "am", "pm"))
33+
#'
34+
#' # replace table `flights` with the zoomed table
35+
#' flights_keyed_transformed %>%
36+
#' dm_update_zoom2ed()
37+
#'
38+
#' # insert the zoomed table as a new table
39+
#' flights_keyed_transformed %>%
40+
#' dm_insert_zoom2ed("extended_flights")
41+
#'
42+
#' # discard changes and return original dm
43+
#' flights_keyed_transformed %>%
44+
#' dm_discard_zoom2ed()
45+
dm_zoom2_to <- function(dm, table) {
46+
check_not_zoomed(dm)
47+
table_name <- dm_tbl_name(dm, {{ table }})
48+
49+
keyed_tables <- dm_get_keyed_tables_impl(dm)
50+
keyed_tbl <- keyed_tables[[table_name]]
51+
52+
# Store zoom2 info inside dm_key_info so it survives all dplyr/tidyr verbs
53+
keys_info <- keyed_get_info(keyed_tbl)
54+
keys_info$zoom2 <- list(dm = dm, table_name = table_name)
55+
attr(keyed_tbl, "dm_key_info") <- keys_info
56+
57+
keyed_tbl
58+
}
59+
60+
#' @rdname dm_zoom2_to
61+
#' @param zoomed_tbl A `dm_keyed_tbl` object returned by `dm_zoom2_to()`
62+
#' or modified via dplyr operations.
63+
#'
64+
#' @return For `dm_update_zoom2ed()`, `dm_insert_zoom2ed()` and
65+
#' `dm_discard_zoom2ed()`: A `dm` object.
66+
#'
67+
#' @noRd
68+
dm_update_zoom2ed <- function(zoomed_tbl) {
69+
zoom2_info <- zoom2_get_info(zoomed_tbl)
70+
dm <- zoom2_info$dm
71+
table_name <- zoom2_info$table_name
72+
73+
keyed_tables <- dm_get_keyed_tables_impl(dm)
74+
keyed_tables[[table_name]] <- zoom2_clean_keys_info(zoomed_tbl)
75+
76+
# Preserve table order by using names from original keyed_tables
77+
new_dm(keyed_tables)
78+
}
79+
80+
#' @rdname dm_zoom2_to
81+
#' @param new_tbl_name Name of the new table.
82+
#' @inheritParams vctrs::vec_as_names
83+
#'
84+
#' @noRd
85+
dm_insert_zoom2ed <- function(zoomed_tbl, new_tbl_name = NULL, repair = "unique", quiet = FALSE) {
86+
zoom2_info <- zoom2_get_info(zoomed_tbl)
87+
dm <- zoom2_info$dm
88+
table_name <- zoom2_info$table_name
89+
90+
if (is.null(new_tbl_name)) {
91+
new_tbl_name <- table_name
92+
}
93+
94+
keyed_tables <- dm_get_keyed_tables_impl(dm)
95+
96+
# Repair names if needed
97+
names_list <- repair_table_names(
98+
old_names = names(keyed_tables),
99+
new_names = new_tbl_name,
100+
repair,
101+
quiet
102+
)
103+
104+
# Rename existing tables if name repair occurred
105+
names(keyed_tables) <- names_list$old_new_names[names(keyed_tables)]
106+
new_tbl_name <- names_list$new_names
107+
108+
# Add the new table
109+
keyed_tables[[new_tbl_name]] <- zoom2_clean_keys_info(zoomed_tbl)
110+
111+
out <- new_dm(keyed_tables)
112+
113+
# Transfer color from original table to new table
114+
orig_def <- dm_get_def(dm)
115+
orig_display <- orig_def$display[orig_def$table == table_name]
116+
if (!is.na(orig_display)) {
117+
out <- dm_set_colors(out, !!!set_names(new_tbl_name, orig_display))
118+
}
119+
120+
out
121+
}
122+
123+
#' @rdname dm_zoom2_to
124+
#' @noRd
125+
dm_discard_zoom2ed <- function(zoomed_tbl) {
126+
zoom2_info <- zoom2_get_info(zoomed_tbl)
127+
zoom2_info$dm
128+
}
129+
130+
131+
# Internal helpers --------------------------------------------------------
132+
133+
zoom2_get_info <- function(zoomed_tbl) {
134+
if (!is_dm_keyed_tbl(zoomed_tbl)) {
135+
cli::cli_abort("This object was not created by {.fn dm_zoom2_to}.")
136+
}
137+
138+
keys_info <- keyed_get_info(zoomed_tbl)
139+
zoom2 <- keys_info$zoom2
140+
141+
if (is.null(zoom2)) {
142+
cli::cli_abort("This object was not created by {.fn dm_zoom2_to}.")
143+
}
144+
145+
zoom2
146+
}
147+
148+
zoom2_clean_keys_info <- function(x) {
149+
if (is_dm_keyed_tbl(x)) {
150+
keys_info <- keyed_get_info(x)
151+
keys_info$zoom2 <- NULL
152+
attr(x, "dm_key_info") <- keys_info
153+
}
154+
x
155+
}

0 commit comments

Comments
 (0)