@@ -2094,6 +2094,7 @@ def test_plan_audit_intervals(tmp_path: pathlib.Path, caplog):
20942094 plan = ctx .plan (
20952095 environment = "dev" , auto_apply = True , no_prompts = True , start = "2025-02-01" , end = "2025-02-01"
20962096 )
2097+ assert plan .missing_intervals
20972098
20982099 date_snapshot = next (s for s in plan .new_snapshots if "date_example" in s .name )
20992100 timestamp_snapshot = next (s for s in plan .new_snapshots if "timestamp_example" in s .name )
@@ -2304,3 +2305,136 @@ def test_dev_environment_virtual_update_with_environment_statements(tmp_path: Pa
23042305 updated_statements [0 ].before_all [1 ]
23052306 == "CREATE TABLE IF NOT EXISTS metrics (metric_name VARCHAR(50), value INT)"
23062307 )
2308+
2309+
2310+ def test_plan_relative_start_min_intervals (tmp_path : Path ):
2311+ init_example_project (tmp_path , engine_type = "duckdb" , dialect = "duckdb" )
2312+
2313+ context = Context (
2314+ paths = tmp_path , config = Config (model_defaults = ModelDefaultsConfig (dialect = "duckdb" ))
2315+ )
2316+
2317+ current_time = to_datetime ("2020-02-01 00:00:01" )
2318+
2319+ # initial state of example project
2320+ context .plan (auto_apply = True , execution_time = current_time )
2321+
2322+ (tmp_path / "models" / "daily_model.sql" ).write_text ("""
2323+ MODEL (
2324+ name sqlmesh_example.daily_model,
2325+ kind INCREMENTAL_BY_TIME_RANGE (
2326+ time_column event_date
2327+ ),
2328+ start '2020-01-01',
2329+ cron '@daily'
2330+ );
2331+
2332+ select * from sqlmesh_example.incremental_model where event_date between @start_ds and @end_ds
2333+ """ )
2334+
2335+ (tmp_path / "models" / "weekly_model.sql" ).write_text ("""
2336+ MODEL (
2337+ name sqlmesh_example.weekly_model,
2338+ kind INCREMENTAL_BY_TIME_RANGE (
2339+ time_column event_date
2340+ ),
2341+ start '2020-01-01',
2342+ cron '@weekly'
2343+ );
2344+
2345+ select * from sqlmesh_example.incremental_model where event_date between @start_ds and @end_ds
2346+ """ )
2347+
2348+ (tmp_path / "models" / "monthly_model.sql" ).write_text ("""
2349+ MODEL (
2350+ name sqlmesh_example.monthly_model,
2351+ kind INCREMENTAL_BY_TIME_RANGE (
2352+ time_column event_date
2353+ ),
2354+ start '2020-01-01',
2355+ cron '@monthly'
2356+ );
2357+
2358+ select * from sqlmesh_example.incremental_model where event_date between @start_ds and @end_ds
2359+ """ )
2360+
2361+ context .load ()
2362+
2363+ # initial state - backfill from 2020-01-01 -> now() (2020-01-02 00:00:01) on new models
2364+ plan = context .plan (execution_time = current_time )
2365+
2366+ assert to_datetime (plan .start ) == to_datetime ("2020-01-01 00:00:00" )
2367+ assert to_datetime (plan .end ) == to_datetime ("2020-02-01 00:00:00" )
2368+ assert to_datetime (plan .execution_time ) == to_datetime ("2020-02-01 00:00:01" )
2369+
2370+ # check initial intervals - should be full time range between start and execution time
2371+ assert len (plan .missing_intervals ) == 3
2372+ assert (
2373+ plan .missing_intervals [0 ].snapshot_id
2374+ == context .get_snapshot ("sqlmesh_example.daily_model" , raise_if_missing = True ).snapshot_id
2375+ )
2376+ assert [
2377+ (to_datetime (s ), to_datetime (e )) for s , e in plan .missing_intervals [0 ].merged_intervals
2378+ ] == [(to_datetime ("2020-01-01 00:00:00" ), to_datetime ("2020-02-01 00:00:00" ))]
2379+ assert (
2380+ plan .missing_intervals [1 ].snapshot_id
2381+ == context .get_snapshot ("sqlmesh_example.monthly_model" , raise_if_missing = True ).snapshot_id
2382+ )
2383+ assert [
2384+ (to_datetime (s ), to_datetime (e )) for s , e in plan .missing_intervals [1 ].merged_intervals
2385+ ] == [(to_datetime ("2020-01-01 00:00:00" ), to_datetime ("2020-02-01 00:00:00" ))]
2386+ assert (
2387+ plan .missing_intervals [2 ].snapshot_id
2388+ == context .get_snapshot ("sqlmesh_example.weekly_model" , raise_if_missing = True ).snapshot_id
2389+ )
2390+ assert [
2391+ (to_datetime (s ), to_datetime (e )) for s , e in plan .missing_intervals [2 ].merged_intervals
2392+ ] == [
2393+ (
2394+ to_datetime ("2020-01-01 00:00:00" ),
2395+ to_datetime ("2020-01-26 00:00:00" ),
2396+ ) # last week in 2020-01 hasnt fully elapsed yet
2397+ ]
2398+
2399+ # now, create a dev env for "1 day ago"
2400+ plan = context .plan (
2401+ environment = "pr_env" ,
2402+ start = "1 day ago" ,
2403+ execution_time = current_time ,
2404+ relative_start_min_intervals = 1 ,
2405+ )
2406+
2407+ # this should pick up last day for daily model, last week for weekly model and last month for the monthly model
2408+ assert len (plan .missing_intervals ) == 3
2409+
2410+ assert (
2411+ plan .missing_intervals [0 ].snapshot_id
2412+ == context .get_snapshot ("sqlmesh_example.daily_model" , raise_if_missing = True ).snapshot_id
2413+ )
2414+ assert [
2415+ (to_datetime (s ), to_datetime (e )) for s , e in plan .missing_intervals [0 ].merged_intervals
2416+ ] == [(to_datetime ("2020-01-31 00:00:00" ), to_datetime ("2020-02-01 00:00:00" ))]
2417+ assert (
2418+ plan .missing_intervals [1 ].snapshot_id
2419+ == context .get_snapshot ("sqlmesh_example.monthly_model" , raise_if_missing = True ).snapshot_id
2420+ )
2421+ assert [
2422+ (to_datetime (s ), to_datetime (e )) for s , e in plan .missing_intervals [1 ].merged_intervals
2423+ ] == [
2424+ (
2425+ to_datetime ("2020-01-01 00:00:00" ), # last completed month
2426+ to_datetime ("2020-02-01 00:00:00" ),
2427+ )
2428+ ]
2429+ assert (
2430+ plan .missing_intervals [2 ].snapshot_id
2431+ == context .get_snapshot ("sqlmesh_example.weekly_model" , raise_if_missing = True ).snapshot_id
2432+ )
2433+ assert [
2434+ (to_datetime (s ), to_datetime (e )) for s , e in plan .missing_intervals [2 ].merged_intervals
2435+ ] == [
2436+ (
2437+ to_datetime ("2020-01-19 00:00:00" ), # last completed week
2438+ to_datetime ("2020-01-26 00:00:00" ),
2439+ )
2440+ ]
0 commit comments