## ----include = FALSE---------------------------------------------------------- # Evaluate chunks only where the ducklake DuckDB extension is already # installed. The probe never downloads anything, so building this vignette # needs no network access. ducklake_available <- ducklake::ducklake_extension_available() knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = ducklake_available ) # Use a unique temp directory for this vignette to avoid conflicts during R CMD check vignette_temp_dir <- file.path(tempdir(), "modifying_tables_vignette") dir.create(vignette_temp_dir, showWarnings = FALSE, recursive = TRUE) knitr::opts_knit$set(root.dir = vignette_temp_dir) ## ----setup, message = FALSE--------------------------------------------------- library(ducklake) library(dplyr) # Setup for examples # The ducklake extension only needs installing once per machine: # install_ducklake() attach_ducklake("modifying_tables_lake", lake_path = vignette_temp_dir) # Load a sample dataset with_transaction( create_table(mtcars, "cars"), author = "Data Engineer", commit_message = "Initial car data load" ) ## ----rows-setup--------------------------------------------------------------- fleet <- data.frame( car_id = 1:3, model = c("Corolla", "Civic", "Model 3"), mileage = c(42000, 38500, 12000) ) with_transaction( create_table(fleet, "fleet"), author = "Fleet Manager", commit_message = "Initial fleet inventory" ) ## ----rows-insert-------------------------------------------------------------- new_cars <- data.frame( car_id = 4:5, model = c("Leaf", "Ioniq 5"), mileage = c(500, 120) ) rows_insert(get_ducklake_table("fleet"), new_cars, by = "car_id") get_ducklake_table("fleet") |> collect() ## ----rows-update-------------------------------------------------------------- correction <- data.frame(car_id = 2, mileage = 39000) rows_update(get_ducklake_table("fleet"), correction, by = "car_id") get_ducklake_table("fleet") |> filter(car_id == 2) |> collect() ## ----rows-delete-------------------------------------------------------------- sold <- data.frame(car_id = 1) rows_delete(get_ducklake_table("fleet"), sold, by = "car_id") get_ducklake_table("fleet") |> collect() ## ----rows-transaction--------------------------------------------------------- april_arrivals <- data.frame(car_id = 6, model = "ID.4", mileage = 60) recalled <- data.frame(car_id = 4) with_transaction({ rows_insert(get_ducklake_table("fleet"), april_arrivals, by = "car_id") rows_delete(get_ducklake_table("fleet"), recalled, by = "car_id") }, author = "Fleet Manager", commit_message = "April intake; remove recalled Leaf" ) # The full history: every change is versioned, wrapped or not list_table_snapshots("fleet") ## ----rows-upsert-------------------------------------------------------------- service_batch <- data.frame( car_id = c(3, 7), model = c("Model 3", "Kona"), mileage = c(15200, 8000) ) rows_upsert(get_ducklake_table("fleet"), service_batch, by = "car_id") get_ducklake_table("fleet") |> arrange(car_id) |> collect() ## ----merge-into--------------------------------------------------------------- registry <- data.frame( car_id = c(3, 5, 8), model = c("Model 3", "Ioniq 5", "e-Golf"), mileage = c(15400, 900, 21000) ) with_transaction( merge_into("fleet", registry, by = "car_id", delete_missing = TRUE), author = "Fleet Manager", commit_message = "Quarterly registry sync" ) get_ducklake_table("fleet") |> arrange(car_id) |> collect() ## ----merge-into-changes------------------------------------------------------- latest <- max(list_table_snapshots("fleet")$snapshot_id) get_table_changes("fleet", latest, latest) |> select(change_type, car_id, model, mileage) |> collect() ## ----update-rows-------------------------------------------------------------- # Update mpg values for specific cars (4-cylinder cars get a 5% efficiency boost) with_transaction( get_ducklake_table("cars") |> mutate( mpg = if_else(cyl == 4, mpg * 1.05, mpg) ) |> replace_table("cars"), author = "Data Engineer", commit_message = "Update MPG for 4-cylinder vehicles" ) # Check version history - should show the new snapshot list_table_snapshots("cars") ## ----add-columns-------------------------------------------------------------- with_transaction({ add_table_column("cars", "hp_per_cyl", "DOUBLE") add_table_column("cars", "high_performance", "VARCHAR") get_ducklake_table("cars") |> mutate( hp_per_cyl = hp / cyl, high_performance = if_else(hp > 200, "Y", "N") ) |> ducklake_exec() }, author = "Data Engineer", commit_message = "Add HP per cylinder and performance flag" ) # Verify new columns exist get_ducklake_table("cars") |> filter(hp > 200) |> select(hp, cyl, hp_per_cyl, high_performance) ## ----schema-evolution--------------------------------------------------------- snapshot_before <- max(list_table_snapshots("cars")$snapshot_id) rename_table_column("cars", from = "high_performance", to = "high_perf_flag") drop_table_column("cars", "hp_per_cyl") # Widen fleet's integer key without rewriting any data set_column_type("fleet", "car_id", "BIGINT") # Current schema reflects the rename and the drop get_ducklake_table("cars") |> colnames() # The pre-change snapshot still shows the old shape get_ducklake_table_version("cars", snapshot_before) |> colnames() ## ----filter------------------------------------------------------------------- # Keep only specific rows - creates a versioned snapshot with_transaction( get_ducklake_table("cars") |> filter(cyl == 8) |> replace_table("cars"), author = "Data Engineer", commit_message = "Filter to V8 engines only" ) # Show the filtered table get_ducklake_table("cars") # View version history - old versions still accessible via time travel list_table_snapshots("cars") ## ----time-travel-------------------------------------------------------------- # Get the current version current <- get_ducklake_table("cars") |> collect() # List all snapshots to see available versions snapshots <- list_table_snapshots("cars") snapshots # Access a specific previous version by snapshot_id original_version <- get_ducklake_table_version( "cars", snapshots$snapshot_id[1] ) |> collect() # Compare: how many rows changed? nrow(current) nrow(original_version) ## ----cleanup, include=FALSE--------------------------------------------------- detach_ducklake("modifying_tables_lake")