|
7 | 7 | from sqlglot import exp |
8 | 8 | from sqlmesh import Context |
9 | 9 | from sqlmesh.core.model import TimeColumn, IncrementalByTimeRangeKind |
| 10 | +from sqlmesh.core.model.kind import OnDestructiveChange, OnAdditiveChange |
10 | 11 | from sqlmesh.dbt.common import Dependencies |
11 | 12 | from sqlmesh.dbt.context import DbtContext |
12 | 13 | from sqlmesh.dbt.model import ModelConfig |
@@ -301,3 +302,145 @@ def test_load_microbatch_required_only( |
301 | 302 | ) |
302 | 303 | assert model.kind.batch_size == 1 |
303 | 304 | assert model.depends_on_self is False |
| 305 | + |
| 306 | + |
| 307 | +@pytest.mark.slow |
| 308 | +def test_load_incremental_time_range_strategy_required_only( |
| 309 | + tmp_path: Path, caplog, dbt_dummy_postgres_config: PostgresConfig, create_empty_project |
| 310 | +) -> None: |
| 311 | + project_dir, model_dir = create_empty_project() |
| 312 | + # add `tests` to model config since this is loaded by dbt and ignored and we shouldn't error when loading it |
| 313 | + incremental_time_range_contents = """ |
| 314 | + {{ |
| 315 | + config( |
| 316 | + materialized='incremental', |
| 317 | + incremental_strategy='incremental_by_time_range', |
| 318 | + time_column='ds', |
| 319 | + ) |
| 320 | + }} |
| 321 | +
|
| 322 | + SELECT 1 as cola, '2021-01-01' as ds |
| 323 | + """ |
| 324 | + incremental_time_range_model_file = model_dir / "incremental_time_range.sql" |
| 325 | + with open(incremental_time_range_model_file, "w", encoding="utf-8") as f: |
| 326 | + f.write(incremental_time_range_contents) |
| 327 | + |
| 328 | + snapshot_fqn = '"local"."main"."incremental_time_range"' |
| 329 | + context = Context(paths=project_dir) |
| 330 | + model = context.snapshots[snapshot_fqn].model |
| 331 | + # Validate model-level attributes |
| 332 | + assert model.start == "2025-01-01" |
| 333 | + assert model.interval_unit.is_day |
| 334 | + # Validate model kind attributes |
| 335 | + assert isinstance(model.kind, IncrementalByTimeRangeKind) |
| 336 | + assert model.kind.lookback == 1 |
| 337 | + assert model.kind.time_column == TimeColumn( |
| 338 | + column=exp.to_column("ds", quoted=True), format="%Y-%m-%d" |
| 339 | + ) |
| 340 | + assert model.kind.batch_size is None |
| 341 | + assert model.depends_on_self is False |
| 342 | + assert model.kind.auto_restatement_intervals is None |
| 343 | + assert model.kind.partition_by_time_column is True |
| 344 | + |
| 345 | + |
| 346 | +@pytest.mark.slow |
| 347 | +def test_load_incremental_time_range_strategy_all_defined( |
| 348 | + tmp_path: Path, caplog, dbt_dummy_postgres_config: PostgresConfig, create_empty_project |
| 349 | +) -> None: |
| 350 | + project_dir, model_dir = create_empty_project() |
| 351 | + # add `tests` to model config since this is loaded by dbt and ignored and we shouldn't error when loading it |
| 352 | + incremental_time_range_contents = """ |
| 353 | + {{ |
| 354 | + config( |
| 355 | + materialized='incremental', |
| 356 | + incremental_strategy='incremental_by_time_range', |
| 357 | + time_column='ds', |
| 358 | + auto_restatement_intervals=3, |
| 359 | + partition_by_time_column=false, |
| 360 | + lookback=5, |
| 361 | + batch_size=3, |
| 362 | + batch_concurrency=2, |
| 363 | + forward_only=true, |
| 364 | + disable_restatement=true, |
| 365 | + on_destructive_change='allow', |
| 366 | + on_additive_change='error', |
| 367 | + auto_restatement_cron='@hourly', |
| 368 | + on_schema_change='ignore' |
| 369 | + ) |
| 370 | + }} |
| 371 | +
|
| 372 | + SELECT 1 as cola, '2021-01-01' as ds |
| 373 | + """ |
| 374 | + incremental_time_range_model_file = model_dir / "incremental_time_range.sql" |
| 375 | + with open(incremental_time_range_model_file, "w", encoding="utf-8") as f: |
| 376 | + f.write(incremental_time_range_contents) |
| 377 | + |
| 378 | + snapshot_fqn = '"local"."main"."incremental_time_range"' |
| 379 | + context = Context(paths=project_dir) |
| 380 | + model = context.snapshots[snapshot_fqn].model |
| 381 | + # Validate model-level attributes |
| 382 | + assert model.start == "2025-01-01" |
| 383 | + assert model.interval_unit.is_day |
| 384 | + # Validate model kind attributes |
| 385 | + assert isinstance(model.kind, IncrementalByTimeRangeKind) |
| 386 | + # `on_schema_change` is ignored since the user explicitly overrode the values |
| 387 | + assert model.kind.on_destructive_change == OnDestructiveChange.ALLOW |
| 388 | + assert model.kind.on_additive_change == OnAdditiveChange.ERROR |
| 389 | + assert model.kind.forward_only is True |
| 390 | + assert model.kind.disable_restatement is True |
| 391 | + assert model.kind.auto_restatement_cron == "@hourly" |
| 392 | + assert model.kind.auto_restatement_intervals == 3 |
| 393 | + assert model.kind.partition_by_time_column is False |
| 394 | + assert model.kind.lookback == 5 |
| 395 | + assert model.kind.time_column == TimeColumn( |
| 396 | + column=exp.to_column("ds", quoted=True), format="%Y-%m-%d" |
| 397 | + ) |
| 398 | + assert model.kind.batch_size == 3 |
| 399 | + assert model.kind.batch_concurrency == 2 |
| 400 | + assert model.depends_on_self is False |
| 401 | + |
| 402 | + |
| 403 | +@pytest.mark.slow |
| 404 | +def test_load_deprecated_incremental_time_column( |
| 405 | + tmp_path: Path, caplog, dbt_dummy_postgres_config: PostgresConfig, create_empty_project |
| 406 | +) -> None: |
| 407 | + project_dir, model_dir = create_empty_project() |
| 408 | + # add `tests` to model config since this is loaded by dbt and ignored and we shouldn't error when loading it |
| 409 | + incremental_time_range_contents = """ |
| 410 | + {{ |
| 411 | + config( |
| 412 | + materialized='incremental', |
| 413 | + incremental_strategy='delete+insert', |
| 414 | + time_column='ds' |
| 415 | + ) |
| 416 | + }} |
| 417 | +
|
| 418 | + SELECT 1 as cola, '2021-01-01' as ds |
| 419 | + """ |
| 420 | + incremental_time_range_model_file = model_dir / "incremental_time_range.sql" |
| 421 | + with open(incremental_time_range_model_file, "w", encoding="utf-8") as f: |
| 422 | + f.write(incremental_time_range_contents) |
| 423 | + |
| 424 | + snapshot_fqn = '"local"."main"."incremental_time_range"' |
| 425 | + context = Context(paths=project_dir) |
| 426 | + model = context.snapshots[snapshot_fqn].model |
| 427 | + # Validate model-level attributes |
| 428 | + assert model.start == "2025-01-01" |
| 429 | + assert model.interval_unit.is_day |
| 430 | + # Validate model-level attributes |
| 431 | + assert model.start == "2025-01-01" |
| 432 | + assert model.interval_unit.is_day |
| 433 | + # Validate model kind attributes |
| 434 | + assert isinstance(model.kind, IncrementalByTimeRangeKind) |
| 435 | + assert model.kind.lookback == 1 |
| 436 | + assert model.kind.time_column == TimeColumn( |
| 437 | + column=exp.to_column("ds", quoted=True), format="%Y-%m-%d" |
| 438 | + ) |
| 439 | + assert model.kind.batch_size is None |
| 440 | + assert model.depends_on_self is False |
| 441 | + assert model.kind.auto_restatement_intervals is None |
| 442 | + assert model.kind.partition_by_time_column is True |
| 443 | + assert ( |
| 444 | + "Using `time_column` on a model with incremental_strategy 'delete+insert' has been deprecated. Please use `incremental_by_time_range` instead in model 'main.incremental_time_range'." |
| 445 | + in caplog.text |
| 446 | + ) |
0 commit comments