Search Shortcut cmd + k | ctrl + k
anofox_scenario

Git-like branching for analytical databases. Attach isolated what-if scenarios as catalogs, edit them with ordinary SQL on copy-on-write delta storage, branch, diff, and merge them back.

Maintainer(s): jrosskopf

Installing and Loading

INSTALL anofox_scenario FROM community;
LOAD anofox_scenario;

Example

-- History as recorded
CREATE TABLE sales_plan (region VARCHAR PRIMARY KEY, units INTEGER);
INSERT INTO sales_plan VALUES ('EMEA', 1000), ('AMER', 2000), ('APAC', 500);

-- Branch a what-if world: two statements, then it's just SQL
CALL scenario_create('aggressive_q4', 'push APAC hard');
ATTACH 'aggressive_q4' AS q4 (TYPE scenario);

UPDATE q4.sales_plan SET units = 1500 WHERE region = 'APAC';
DELETE FROM q4.sales_plan WHERE region = 'EMEA';

-- Both worlds coexist; the base is never written
SELECT 'base' AS world, * FROM sales_plan
UNION ALL
SELECT 'scenario', * FROM q4.sales_plan ORDER BY world, region;

-- Audit the changes, then promote them
SELECT * FROM scenario_diff('aggressive_q4', 'sales_plan');
SELECT * FROM scenario_merge('aggressive_q4');

About anofox_scenario

anofox_scenario brings git-like branching to DuckDB databases. A scenario is an attached catalog (ATTACH 'name' AS s (TYPE scenario)) over your existing tables: reads merge the base with the scenario's copy-on-write delta on the fly, and INSERT / UPDATE / DELETE / MERGE INTO / ON CONFLICT (all with RETURNING) land in the delta — the base tables are never modified.

Three isolation tiers: a live overlay (default), mode := 'materialized' point-in-time copies, and DuckLake bases pinned to creation time via AT (TIMESTAMP) for zero-copy snapshot isolation. Scenarios branch from each other (from_scenario :=), inheriting changes, declared row identities, and snapshot pins.

A streaming diff engine (scenario_diff, scenario_diff_summary) audits any world against its origin or another world, and scenario_merge(name, on_conflict := 'abort'|'ours'|'theirs') promotes a scenario into its base atomically — with true 3-way drift conflicts when a creation snapshot exists. Views rebind inside scenarios, all base schemas are mirrored, and tables without a primary key work either via key_columns := declared identity or bag semantics with multiplicity tracking.

Scenario worlds compose with table-name-driven extensions: for example ts_forecast_by('s.demand', ...) (anofox_forecast) forecasts a what-if world directly, no copies needed.

The extension collects anonymous usage telemetry (an envelope-only extension_loaded event; never table names, keys, or SQL). Disable with SET anofox_scenario_telemetry_enabled = false or DATAZOO_DISABLE_TELEMETRY=1; see TELEMETRY.md in the repository.

Added Functions

function_name function_type description comment examples
scenario_create table NULL NULL  
scenario_diff table NULL NULL  
scenario_diff_summary table NULL NULL  
scenario_drop table NULL NULL  
scenario_freeze table NULL NULL  
scenario_list table NULL NULL  
scenario_merge table NULL NULL  
scenario_merge_preview table NULL NULL  
scenario_migrate table NULL NULL  
scenario_refresh table NULL NULL  
scenario_unfreeze table NULL NULL  

Overloaded Functions

This extension does not add any function overloads.

Added Types

This extension does not add any types.

Added Settings

name description input_type scope aliases
anofox_scenario_telemetry_enabled Enable or disable anonymous usage telemetry for anofox_scenario BOOLEAN GLOBAL []