@@ -2088,6 +2088,7 @@ def test_plan_audit_intervals(tmp_path: pathlib.Path, caplog):
20882088 plan = ctx .plan (
20892089 environment = "dev" , auto_apply = True , no_prompts = True , start = "2025-02-01" , end = "2025-02-01"
20902090 )
2091+ assert plan .missing_intervals
20912092
20922093 date_snapshot = next (s for s in plan .new_snapshots if "date_example" in s .name )
20932094 timestamp_snapshot = next (s for s in plan .new_snapshots if "timestamp_example" in s .name )
@@ -2218,3 +2219,136 @@ def test_plan_explain_skips_tests(sushi_context: Context, mocker: MockerFixture)
22182219 spy = mocker .spy (sushi_context , "_run_plan_tests" )
22192220 sushi_context .plan (environment = "dev" , explain = True , no_prompts = True , include_unmodified = True )
22202221 spy .assert_called_once_with (skip_tests = True )
2222+
2223+
2224+ def test_plan_relative_start_min_intervals (tmp_path : Path ):
2225+ init_example_project (tmp_path , dialect = "duckdb" )
2226+
2227+ context = Context (
2228+ paths = tmp_path , config = Config (model_defaults = ModelDefaultsConfig (dialect = "duckdb" ))
2229+ )
2230+
2231+ current_time = to_datetime ("2020-02-01 00:00:01" )
2232+
2233+ # initial state of example project
2234+ context .plan (auto_apply = True , execution_time = current_time )
2235+
2236+ (tmp_path / "models" / "daily_model.sql" ).write_text ("""
2237+ MODEL (
2238+ name sqlmesh_example.daily_model,
2239+ kind INCREMENTAL_BY_TIME_RANGE (
2240+ time_column event_date
2241+ ),
2242+ start '2020-01-01',
2243+ cron '@daily'
2244+ );
2245+
2246+ select * from sqlmesh_example.incremental_model where event_date between @start_ds and @end_ds
2247+ """ )
2248+
2249+ (tmp_path / "models" / "weekly_model.sql" ).write_text ("""
2250+ MODEL (
2251+ name sqlmesh_example.weekly_model,
2252+ kind INCREMENTAL_BY_TIME_RANGE (
2253+ time_column event_date
2254+ ),
2255+ start '2020-01-01',
2256+ cron '@weekly'
2257+ );
2258+
2259+ select * from sqlmesh_example.incremental_model where event_date between @start_ds and @end_ds
2260+ """ )
2261+
2262+ (tmp_path / "models" / "monthly_model.sql" ).write_text ("""
2263+ MODEL (
2264+ name sqlmesh_example.monthly_model,
2265+ kind INCREMENTAL_BY_TIME_RANGE (
2266+ time_column event_date
2267+ ),
2268+ start '2020-01-01',
2269+ cron '@monthly'
2270+ );
2271+
2272+ select * from sqlmesh_example.incremental_model where event_date between @start_ds and @end_ds
2273+ """ )
2274+
2275+ context .load ()
2276+
2277+ # initial state - backfill from 2020-01-01 -> now() (2020-01-02 00:00:01) on new models
2278+ plan = context .plan (execution_time = current_time )
2279+
2280+ assert to_datetime (plan .start ) == to_datetime ("2020-01-01 00:00:00" )
2281+ assert to_datetime (plan .end ) == to_datetime ("2020-02-01 00:00:00" )
2282+ assert to_datetime (plan .execution_time ) == to_datetime ("2020-02-01 00:00:01" )
2283+
2284+ # check initial intervals - should be full time range between start and execution time
2285+ assert len (plan .missing_intervals ) == 3
2286+ assert (
2287+ plan .missing_intervals [0 ].snapshot_id
2288+ == context .get_snapshot ("sqlmesh_example.daily_model" , raise_if_missing = True ).snapshot_id
2289+ )
2290+ assert [
2291+ (to_datetime (s ), to_datetime (e )) for s , e in plan .missing_intervals [0 ].merged_intervals
2292+ ] == [(to_datetime ("2020-01-01 00:00:00" ), to_datetime ("2020-02-01 00:00:00" ))]
2293+ assert (
2294+ plan .missing_intervals [1 ].snapshot_id
2295+ == context .get_snapshot ("sqlmesh_example.monthly_model" , raise_if_missing = True ).snapshot_id
2296+ )
2297+ assert [
2298+ (to_datetime (s ), to_datetime (e )) for s , e in plan .missing_intervals [1 ].merged_intervals
2299+ ] == [(to_datetime ("2020-01-01 00:00:00" ), to_datetime ("2020-02-01 00:00:00" ))]
2300+ assert (
2301+ plan .missing_intervals [2 ].snapshot_id
2302+ == context .get_snapshot ("sqlmesh_example.weekly_model" , raise_if_missing = True ).snapshot_id
2303+ )
2304+ assert [
2305+ (to_datetime (s ), to_datetime (e )) for s , e in plan .missing_intervals [2 ].merged_intervals
2306+ ] == [
2307+ (
2308+ to_datetime ("2020-01-01 00:00:00" ),
2309+ to_datetime ("2020-01-26 00:00:00" ),
2310+ ) # last week in 2020-01 hasnt fully elapsed yet
2311+ ]
2312+
2313+ # now, create a dev env for "1 day ago"
2314+ plan = context .plan (
2315+ environment = "pr_env" ,
2316+ start = "1 day ago" ,
2317+ execution_time = current_time ,
2318+ relative_start_min_intervals = 1 ,
2319+ )
2320+
2321+ # this should pick up last day for daily model, last week for weekly model and last month for the monthly model
2322+ assert len (plan .missing_intervals ) == 3
2323+
2324+ assert (
2325+ plan .missing_intervals [0 ].snapshot_id
2326+ == context .get_snapshot ("sqlmesh_example.daily_model" , raise_if_missing = True ).snapshot_id
2327+ )
2328+ assert [
2329+ (to_datetime (s ), to_datetime (e )) for s , e in plan .missing_intervals [0 ].merged_intervals
2330+ ] == [(to_datetime ("2020-01-31 00:00:00" ), to_datetime ("2020-02-01 00:00:00" ))]
2331+ assert (
2332+ plan .missing_intervals [1 ].snapshot_id
2333+ == context .get_snapshot ("sqlmesh_example.monthly_model" , raise_if_missing = True ).snapshot_id
2334+ )
2335+ assert [
2336+ (to_datetime (s ), to_datetime (e )) for s , e in plan .missing_intervals [1 ].merged_intervals
2337+ ] == [
2338+ (
2339+ to_datetime ("2020-01-01 00:00:00" ), # last completed month
2340+ to_datetime ("2020-02-01 00:00:00" ),
2341+ )
2342+ ]
2343+ assert (
2344+ plan .missing_intervals [2 ].snapshot_id
2345+ == context .get_snapshot ("sqlmesh_example.weekly_model" , raise_if_missing = True ).snapshot_id
2346+ )
2347+ assert [
2348+ (to_datetime (s ), to_datetime (e )) for s , e in plan .missing_intervals [2 ].merged_intervals
2349+ ] == [
2350+ (
2351+ to_datetime ("2020-01-19 00:00:00" ), # last completed week
2352+ to_datetime ("2020-01-26 00:00:00" ),
2353+ )
2354+ ]
0 commit comments