@@ -2156,6 +2156,118 @@ def _dates_in_table(table_name: str) -> t.List[str]:
21562156 ], f"Table { tbl } wasnt cleared"
21572157
21582158
2159+ def test_restatement_plan_respects_disable_restatements (tmp_path : Path ):
2160+ model_a = """
2161+ MODEL (
2162+ name test.a,
2163+ kind INCREMENTAL_BY_TIME_RANGE (
2164+ time_column "ts"
2165+ ),
2166+ start '2024-01-01',
2167+ cron '@daily'
2168+ );
2169+
2170+ select account_id, ts from test.external_table;
2171+ """
2172+
2173+ model_b = """
2174+ MODEL (
2175+ name test.b,
2176+ kind INCREMENTAL_BY_TIME_RANGE (
2177+ time_column "ts",
2178+ disable_restatement true,
2179+ ),
2180+ start '2024-01-01',
2181+ cron '@daily'
2182+ );
2183+
2184+ select account_id, ts from test.a;
2185+ """
2186+
2187+ models_dir = tmp_path / "models"
2188+ models_dir .mkdir ()
2189+
2190+ for path , defn in {"a.sql" : model_a , "b.sql" : model_b }.items ():
2191+ with open (models_dir / path , "w" ) as f :
2192+ f .write (defn )
2193+
2194+ config = Config (model_defaults = ModelDefaultsConfig (dialect = "duckdb" ))
2195+ ctx = Context (paths = [tmp_path ], config = config )
2196+
2197+ engine_adapter = ctx .engine_adapter
2198+ engine_adapter .create_schema ("test" )
2199+
2200+ # source data
2201+ df = pd .DataFrame (
2202+ {
2203+ "account_id" : [1001 , 1002 , 1003 , 1004 ],
2204+ "ts" : [
2205+ "2024-01-01 00:30:00" ,
2206+ "2024-01-01 01:30:00" ,
2207+ "2024-01-01 02:30:00" ,
2208+ "2024-01-02 00:30:00" ,
2209+ ],
2210+ }
2211+ )
2212+ columns_to_types = {
2213+ "account_id" : exp .DataType .build ("int" ),
2214+ "ts" : exp .DataType .build ("timestamp" ),
2215+ }
2216+ external_table = exp .table_ (table = "external_table" , db = "test" , quoted = True )
2217+ engine_adapter .create_table (table_name = external_table , columns_to_types = columns_to_types )
2218+ engine_adapter .insert_append (
2219+ table_name = external_table , query_or_df = df , columns_to_types = columns_to_types
2220+ )
2221+
2222+ # plan + apply
2223+ ctx .plan (auto_apply = True , no_prompts = True )
2224+
2225+ def _dates_in_table (table_name : str ) -> t .List [str ]:
2226+ return [
2227+ str (r [0 ]) for r in engine_adapter .fetchall (f"select ts from { table_name } order by ts" )
2228+ ]
2229+
2230+ def get_snapshot_intervals (snapshot_id ):
2231+ return list (ctx .state_sync .get_snapshots ([snapshot_id ]).values ())[0 ].intervals
2232+
2233+ # verify initial state
2234+ for tbl in ["test.a" , "test.b" ]:
2235+ assert _dates_in_table (tbl ) == [
2236+ "2024-01-01 00:30:00" ,
2237+ "2024-01-01 01:30:00" ,
2238+ "2024-01-01 02:30:00" ,
2239+ "2024-01-02 00:30:00" ,
2240+ ]
2241+
2242+ # restate A and expect b to be ignored
2243+ starting_b_intervals = get_snapshot_intervals (ctx .snapshots ['"memory"."test"."b"' ].snapshot_id )
2244+ engine_adapter .execute ("delete from test.external_table where ts = '2024-01-01 01:30:00'" )
2245+ ctx .plan (
2246+ restate_models = ["test.a" ],
2247+ start = "2024-01-01" ,
2248+ end = "2024-01-02" ,
2249+ auto_apply = True ,
2250+ no_prompts = True ,
2251+ )
2252+
2253+ # verify A was changed and not b
2254+ assert _dates_in_table ("test.a" ) == [
2255+ "2024-01-01 00:30:00" ,
2256+ "2024-01-01 02:30:00" ,
2257+ "2024-01-02 00:30:00" ,
2258+ ]
2259+ assert _dates_in_table ("test.b" ) == [
2260+ "2024-01-01 00:30:00" ,
2261+ "2024-01-01 01:30:00" ,
2262+ "2024-01-01 02:30:00" ,
2263+ "2024-01-02 00:30:00" ,
2264+ ]
2265+
2266+ # Verify B intervals were not touched
2267+ b_intervals = get_snapshot_intervals (ctx .snapshots ['"memory"."test"."b"' ].snapshot_id )
2268+ assert starting_b_intervals == b_intervals
2269+
2270+
21592271def test_restatement_plan_clears_correct_intervals_across_environments (tmp_path : Path ):
21602272 model1 = """
21612273 MODEL (
0 commit comments