@@ -2454,6 +2454,131 @@ def test_unaligned_start_snapshot_with_non_deployable_downstream(init_and_plan_c
24542454 assert snapshot_interval .intervals [0 ][0 ] == to_timestamp ("2023-01-07" )
24552455
24562456
2457+ @time_machine .travel ("2023-01-08 15:00:00 UTC" )
2458+ def test_virtual_environment_mode_dev_only (init_and_plan_context : t .Callable ):
2459+ context , _ = init_and_plan_context (
2460+ "examples/sushi" , config = "test_config_virtual_environment_mode_dev_only"
2461+ )
2462+
2463+ assert all (
2464+ s .virtual_environment_mode .is_dev_only or not s .is_model or s .is_symbolic
2465+ for s in context .snapshots .values ()
2466+ )
2467+
2468+ # Init prod
2469+ context .plan ("prod" , auto_apply = True , no_prompts = True )
2470+
2471+ # Make a change in dev
2472+ original_model = context .get_model ("sushi.waiter_revenue_by_day" )
2473+ original_fingerprint = context .get_snapshot (original_model .name ).fingerprint
2474+ model = original_model .copy (update = {"query" : original_model .query .order_by ("waiter_id" )})
2475+ model = add_projection_to_model (t .cast (SqlModel , model ))
2476+ context .upsert_model (model )
2477+
2478+ plan_dev = context .plan_builder ("dev" ).build ()
2479+ assert to_timestamp (plan_dev .start ) == to_timestamp ("2023-01-07" )
2480+ assert plan_dev .requires_backfill
2481+ assert plan_dev .missing_intervals == [
2482+ SnapshotIntervals (
2483+ snapshot_id = context .get_snapshot ("sushi.top_waiters" ).snapshot_id ,
2484+ intervals = [(to_timestamp ("2023-01-07" ), to_timestamp ("2023-01-08" ))],
2485+ ),
2486+ SnapshotIntervals (
2487+ snapshot_id = context .get_snapshot ("sushi.waiter_revenue_by_day" ).snapshot_id ,
2488+ intervals = [(to_timestamp ("2023-01-07" ), to_timestamp ("2023-01-08" ))],
2489+ ),
2490+ ]
2491+ context .apply (plan_dev )
2492+
2493+ # Make sure the waiter_revenue_by_day model is a table in prod and a view in dev
2494+ table_types_df = context .engine_adapter .fetchdf (
2495+ "SELECT table_schema, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_name = 'waiter_revenue_by_day'"
2496+ )
2497+ assert table_types_df .to_dict ("records" ) == [
2498+ {"table_schema" : "sushi" , "table_type" : "BASE TABLE" },
2499+ {"table_schema" : "sushi__dev" , "table_type" : "VIEW" },
2500+ ]
2501+
2502+ # Check that the specified dates were backfilled
2503+ min_event_date = context .engine_adapter .fetchone (
2504+ "SELECT MIN(event_date) FROM sushi__dev.waiter_revenue_by_day"
2505+ )[0 ]
2506+ assert min_event_date == to_date ("2023-01-07" )
2507+
2508+ # Make sure the changed models are fully rebuilt when deploying to prod
2509+ plan_prod = context .plan_builder ("prod" ).build ()
2510+ assert plan_prod .requires_backfill
2511+ assert plan_prod .missing_intervals == [
2512+ SnapshotIntervals (
2513+ snapshot_id = context .get_snapshot ("sushi.top_waiters" ).snapshot_id ,
2514+ intervals = [
2515+ (to_timestamp ("2023-01-01" ), to_timestamp ("2023-01-02" )),
2516+ (to_timestamp ("2023-01-02" ), to_timestamp ("2023-01-03" )),
2517+ (to_timestamp ("2023-01-03" ), to_timestamp ("2023-01-04" )),
2518+ (to_timestamp ("2023-01-04" ), to_timestamp ("2023-01-05" )),
2519+ (to_timestamp ("2023-01-05" ), to_timestamp ("2023-01-06" )),
2520+ (to_timestamp ("2023-01-06" ), to_timestamp ("2023-01-07" )),
2521+ (to_timestamp ("2023-01-07" ), to_timestamp ("2023-01-08" )),
2522+ ],
2523+ ),
2524+ SnapshotIntervals (
2525+ snapshot_id = context .get_snapshot ("sushi.waiter_revenue_by_day" ).snapshot_id ,
2526+ intervals = [
2527+ (to_timestamp ("2023-01-01" ), to_timestamp ("2023-01-02" )),
2528+ (to_timestamp ("2023-01-02" ), to_timestamp ("2023-01-03" )),
2529+ (to_timestamp ("2023-01-03" ), to_timestamp ("2023-01-04" )),
2530+ (to_timestamp ("2023-01-04" ), to_timestamp ("2023-01-05" )),
2531+ (to_timestamp ("2023-01-05" ), to_timestamp ("2023-01-06" )),
2532+ (to_timestamp ("2023-01-06" ), to_timestamp ("2023-01-07" )),
2533+ (to_timestamp ("2023-01-07" ), to_timestamp ("2023-01-08" )),
2534+ ],
2535+ ),
2536+ ]
2537+ context .apply (plan_prod )
2538+ assert "one" in context .engine_adapter .columns ("sushi.waiter_revenue_by_day" )
2539+ assert (
2540+ context .engine_adapter .fetchone (
2541+ "SELECT COUNT(*) FROM sushi.waiter_revenue_by_day WHERE one is NULL"
2542+ )[0 ]
2543+ == 0
2544+ )
2545+
2546+ # Make sure the revert of a breaking changes results in a full rebuild
2547+ context .upsert_model (original_model )
2548+ assert context .get_snapshot (original_model .name ).fingerprint == original_fingerprint
2549+
2550+ plan_prod = context .plan_builder ("prod" ).build ()
2551+ assert plan_prod .requires_backfill
2552+ assert plan_prod .missing_intervals == [
2553+ SnapshotIntervals (
2554+ snapshot_id = context .get_snapshot ("sushi.top_waiters" ).snapshot_id ,
2555+ intervals = [
2556+ (to_timestamp ("2023-01-01" ), to_timestamp ("2023-01-02" )),
2557+ (to_timestamp ("2023-01-02" ), to_timestamp ("2023-01-03" )),
2558+ (to_timestamp ("2023-01-03" ), to_timestamp ("2023-01-04" )),
2559+ (to_timestamp ("2023-01-04" ), to_timestamp ("2023-01-05" )),
2560+ (to_timestamp ("2023-01-05" ), to_timestamp ("2023-01-06" )),
2561+ (to_timestamp ("2023-01-06" ), to_timestamp ("2023-01-07" )),
2562+ (to_timestamp ("2023-01-07" ), to_timestamp ("2023-01-08" )),
2563+ ],
2564+ ),
2565+ SnapshotIntervals (
2566+ snapshot_id = context .get_snapshot ("sushi.waiter_revenue_by_day" ).snapshot_id ,
2567+ intervals = [
2568+ (to_timestamp ("2023-01-01" ), to_timestamp ("2023-01-02" )),
2569+ (to_timestamp ("2023-01-02" ), to_timestamp ("2023-01-03" )),
2570+ (to_timestamp ("2023-01-03" ), to_timestamp ("2023-01-04" )),
2571+ (to_timestamp ("2023-01-04" ), to_timestamp ("2023-01-05" )),
2572+ (to_timestamp ("2023-01-05" ), to_timestamp ("2023-01-06" )),
2573+ (to_timestamp ("2023-01-06" ), to_timestamp ("2023-01-07" )),
2574+ (to_timestamp ("2023-01-07" ), to_timestamp ("2023-01-08" )),
2575+ ],
2576+ ),
2577+ ]
2578+ context .apply (plan_prod )
2579+ assert "one" not in context .engine_adapter .columns ("sushi.waiter_revenue_by_day" )
2580+
2581+
24572582@time_machine .travel ("2023-01-08 15:00:00 UTC" )
24582583def test_restatement_plan_ignores_changes (init_and_plan_context : t .Callable ):
24592584 context , plan = init_and_plan_context ("examples/sushi" )
0 commit comments