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