sqlmesh 0.217.1.dev1__py3-none-any.whl → 0.227.2.dev4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. sqlmesh/__init__.py +12 -2
  2. sqlmesh/_version.py +2 -2
  3. sqlmesh/cli/project_init.py +10 -2
  4. sqlmesh/core/_typing.py +1 -0
  5. sqlmesh/core/audit/definition.py +8 -2
  6. sqlmesh/core/config/__init__.py +1 -1
  7. sqlmesh/core/config/connection.py +17 -5
  8. sqlmesh/core/config/dbt.py +13 -0
  9. sqlmesh/core/config/janitor.py +12 -0
  10. sqlmesh/core/config/loader.py +7 -0
  11. sqlmesh/core/config/model.py +2 -0
  12. sqlmesh/core/config/root.py +3 -0
  13. sqlmesh/core/console.py +80 -2
  14. sqlmesh/core/constants.py +1 -1
  15. sqlmesh/core/context.py +61 -25
  16. sqlmesh/core/dialect.py +3 -0
  17. sqlmesh/core/engine_adapter/_typing.py +2 -0
  18. sqlmesh/core/engine_adapter/base.py +322 -22
  19. sqlmesh/core/engine_adapter/base_postgres.py +17 -1
  20. sqlmesh/core/engine_adapter/bigquery.py +146 -7
  21. sqlmesh/core/engine_adapter/clickhouse.py +17 -13
  22. sqlmesh/core/engine_adapter/databricks.py +33 -2
  23. sqlmesh/core/engine_adapter/fabric.py +1 -29
  24. sqlmesh/core/engine_adapter/mixins.py +142 -48
  25. sqlmesh/core/engine_adapter/mssql.py +15 -4
  26. sqlmesh/core/engine_adapter/mysql.py +2 -2
  27. sqlmesh/core/engine_adapter/postgres.py +9 -3
  28. sqlmesh/core/engine_adapter/redshift.py +4 -0
  29. sqlmesh/core/engine_adapter/risingwave.py +1 -0
  30. sqlmesh/core/engine_adapter/shared.py +6 -0
  31. sqlmesh/core/engine_adapter/snowflake.py +82 -11
  32. sqlmesh/core/engine_adapter/spark.py +14 -10
  33. sqlmesh/core/engine_adapter/trino.py +4 -2
  34. sqlmesh/core/janitor.py +181 -0
  35. sqlmesh/core/lineage.py +1 -0
  36. sqlmesh/core/macros.py +35 -13
  37. sqlmesh/core/model/common.py +2 -0
  38. sqlmesh/core/model/definition.py +65 -4
  39. sqlmesh/core/model/kind.py +66 -2
  40. sqlmesh/core/model/meta.py +107 -2
  41. sqlmesh/core/node.py +101 -2
  42. sqlmesh/core/plan/builder.py +15 -10
  43. sqlmesh/core/plan/common.py +196 -2
  44. sqlmesh/core/plan/definition.py +21 -6
  45. sqlmesh/core/plan/evaluator.py +72 -113
  46. sqlmesh/core/plan/explainer.py +90 -8
  47. sqlmesh/core/plan/stages.py +42 -21
  48. sqlmesh/core/renderer.py +26 -18
  49. sqlmesh/core/scheduler.py +60 -19
  50. sqlmesh/core/selector.py +137 -9
  51. sqlmesh/core/signal.py +64 -1
  52. sqlmesh/core/snapshot/__init__.py +1 -0
  53. sqlmesh/core/snapshot/definition.py +109 -25
  54. sqlmesh/core/snapshot/evaluator.py +610 -50
  55. sqlmesh/core/state_sync/__init__.py +0 -1
  56. sqlmesh/core/state_sync/base.py +31 -27
  57. sqlmesh/core/state_sync/cache.py +12 -4
  58. sqlmesh/core/state_sync/common.py +216 -111
  59. sqlmesh/core/state_sync/db/facade.py +30 -15
  60. sqlmesh/core/state_sync/db/interval.py +27 -7
  61. sqlmesh/core/state_sync/db/migrator.py +14 -8
  62. sqlmesh/core/state_sync/db/snapshot.py +119 -87
  63. sqlmesh/core/table_diff.py +2 -2
  64. sqlmesh/core/test/definition.py +14 -9
  65. sqlmesh/dbt/adapter.py +20 -11
  66. sqlmesh/dbt/basemodel.py +52 -41
  67. sqlmesh/dbt/builtin.py +27 -11
  68. sqlmesh/dbt/column.py +17 -5
  69. sqlmesh/dbt/common.py +4 -2
  70. sqlmesh/dbt/context.py +14 -1
  71. sqlmesh/dbt/loader.py +60 -8
  72. sqlmesh/dbt/manifest.py +136 -8
  73. sqlmesh/dbt/model.py +105 -25
  74. sqlmesh/dbt/package.py +16 -1
  75. sqlmesh/dbt/profile.py +3 -3
  76. sqlmesh/dbt/project.py +12 -7
  77. sqlmesh/dbt/seed.py +1 -1
  78. sqlmesh/dbt/source.py +6 -1
  79. sqlmesh/dbt/target.py +25 -6
  80. sqlmesh/dbt/test.py +31 -1
  81. sqlmesh/migrations/v0000_baseline.py +3 -6
  82. sqlmesh/migrations/v0061_mysql_fix_blob_text_type.py +2 -5
  83. sqlmesh/migrations/v0062_add_model_gateway.py +2 -2
  84. sqlmesh/migrations/v0063_change_signals.py +2 -4
  85. sqlmesh/migrations/v0064_join_when_matched_strings.py +2 -4
  86. sqlmesh/migrations/v0065_add_model_optimize.py +2 -2
  87. sqlmesh/migrations/v0066_add_auto_restatements.py +2 -6
  88. sqlmesh/migrations/v0067_add_tsql_date_full_precision.py +2 -2
  89. sqlmesh/migrations/v0068_include_unrendered_query_in_metadata_hash.py +2 -2
  90. sqlmesh/migrations/v0069_update_dev_table_suffix.py +2 -4
  91. sqlmesh/migrations/v0070_include_grains_in_metadata_hash.py +2 -2
  92. sqlmesh/migrations/v0071_add_dev_version_to_intervals.py +2 -6
  93. sqlmesh/migrations/v0072_add_environment_statements.py +2 -4
  94. sqlmesh/migrations/v0073_remove_symbolic_disable_restatement.py +2 -4
  95. sqlmesh/migrations/v0074_add_partition_by_time_column_property.py +2 -2
  96. sqlmesh/migrations/v0075_remove_validate_query.py +2 -4
  97. sqlmesh/migrations/v0076_add_cron_tz.py +2 -2
  98. sqlmesh/migrations/v0077_fix_column_type_hash_calculation.py +2 -2
  99. sqlmesh/migrations/v0078_warn_if_non_migratable_python_env.py +2 -4
  100. sqlmesh/migrations/v0079_add_gateway_managed_property.py +7 -9
  101. sqlmesh/migrations/v0080_add_batch_size_to_scd_type_2_models.py +2 -2
  102. sqlmesh/migrations/v0081_update_partitioned_by.py +2 -4
  103. sqlmesh/migrations/v0082_warn_if_incorrectly_duplicated_statements.py +2 -4
  104. sqlmesh/migrations/v0083_use_sql_for_scd_time_data_type_data_hash.py +2 -2
  105. sqlmesh/migrations/v0084_normalize_quote_when_matched_and_merge_filter.py +2 -2
  106. sqlmesh/migrations/v0085_deterministic_repr.py +2 -4
  107. sqlmesh/migrations/v0086_check_deterministic_bug.py +2 -4
  108. sqlmesh/migrations/v0087_normalize_blueprint_variables.py +2 -4
  109. sqlmesh/migrations/v0088_warn_about_variable_python_env_diffs.py +2 -4
  110. sqlmesh/migrations/v0089_add_virtual_environment_mode.py +2 -2
  111. sqlmesh/migrations/v0090_add_forward_only_column.py +2 -6
  112. sqlmesh/migrations/v0091_on_additive_change.py +2 -2
  113. sqlmesh/migrations/v0092_warn_about_dbt_data_type_diff.py +2 -4
  114. sqlmesh/migrations/v0093_use_raw_sql_in_fingerprint.py +2 -2
  115. sqlmesh/migrations/v0094_add_dev_version_and_fingerprint_columns.py +2 -6
  116. sqlmesh/migrations/v0095_warn_about_dbt_raw_sql_diff.py +2 -4
  117. sqlmesh/migrations/v0096_remove_plan_dags_table.py +2 -4
  118. sqlmesh/migrations/v0097_add_dbt_name_in_node.py +2 -2
  119. sqlmesh/migrations/v0098_add_dbt_node_info_in_node.py +103 -0
  120. sqlmesh/migrations/v0099_add_last_altered_to_intervals.py +25 -0
  121. sqlmesh/migrations/v0100_add_grants_and_grants_target_layer.py +9 -0
  122. sqlmesh/utils/__init__.py +8 -1
  123. sqlmesh/utils/cache.py +5 -1
  124. sqlmesh/utils/date.py +1 -1
  125. sqlmesh/utils/errors.py +4 -0
  126. sqlmesh/utils/jinja.py +25 -2
  127. sqlmesh/utils/pydantic.py +6 -6
  128. sqlmesh/utils/windows.py +13 -3
  129. {sqlmesh-0.217.1.dev1.dist-info → sqlmesh-0.227.2.dev4.dist-info}/METADATA +5 -5
  130. {sqlmesh-0.217.1.dev1.dist-info → sqlmesh-0.227.2.dev4.dist-info}/RECORD +181 -176
  131. sqlmesh_dbt/cli.py +70 -7
  132. sqlmesh_dbt/console.py +14 -6
  133. sqlmesh_dbt/operations.py +103 -24
  134. sqlmesh_dbt/selectors.py +39 -1
  135. web/client/dist/assets/{Audits-Ucsx1GzF.js → Audits-CBiYyyx-.js} +1 -1
  136. web/client/dist/assets/{Banner-BWDzvavM.js → Banner-DSRbUlO5.js} +1 -1
  137. web/client/dist/assets/{ChevronDownIcon-D2VL13Ah.js → ChevronDownIcon-MK_nrjD_.js} +1 -1
  138. web/client/dist/assets/{ChevronRightIcon-DWGYbf1l.js → ChevronRightIcon-CLWtT22Q.js} +1 -1
  139. web/client/dist/assets/{Content-DdHDZM3I.js → Content-BNuGZN5l.js} +1 -1
  140. web/client/dist/assets/{Content-Bikfy8fh.js → Content-CSHJyW0n.js} +1 -1
  141. web/client/dist/assets/{Data-CzAJH7rW.js → Data-C1oRDbLx.js} +1 -1
  142. web/client/dist/assets/{DataCatalog-BJF11g8f.js → DataCatalog-HXyX2-_j.js} +1 -1
  143. web/client/dist/assets/{Editor-s0SBpV2y.js → Editor-BDyfpUuw.js} +1 -1
  144. web/client/dist/assets/{Editor-DgLhgKnm.js → Editor-D0jNItwC.js} +1 -1
  145. web/client/dist/assets/{Errors-D0m0O1d3.js → Errors-BfuFLcPi.js} +1 -1
  146. web/client/dist/assets/{FileExplorer-CEv0vXkt.js → FileExplorer-BR9IE3he.js} +1 -1
  147. web/client/dist/assets/{Footer-BwzXn8Ew.js → Footer-CgBEtiAh.js} +1 -1
  148. web/client/dist/assets/{Header-6heDkEqG.js → Header-DSqR6nSO.js} +1 -1
  149. web/client/dist/assets/{Input-obuJsD6k.js → Input-B-oZ6fGO.js} +1 -1
  150. web/client/dist/assets/Lineage-DYQVwDbD.js +1 -0
  151. web/client/dist/assets/{ListboxShow-HM9_qyrt.js → ListboxShow-BE5-xevs.js} +1 -1
  152. web/client/dist/assets/{ModelLineage-zWdKo0U2.js → ModelLineage-DkIFAYo4.js} +1 -1
  153. web/client/dist/assets/{Models-Bcu66SRz.js → Models-D5dWr8RB.js} +1 -1
  154. web/client/dist/assets/{Page-BWEEQfIt.js → Page-C-XfU5BR.js} +1 -1
  155. web/client/dist/assets/{Plan-C4gXCqlf.js → Plan-ZEuTINBq.js} +1 -1
  156. web/client/dist/assets/{PlusCircleIcon-CVDO651q.js → PlusCircleIcon-DVXAHG8_.js} +1 -1
  157. web/client/dist/assets/{ReportErrors-BT6xFwAr.js → ReportErrors-B7FEPzMB.js} +1 -1
  158. web/client/dist/assets/{Root-ryJoBK4h.js → Root-8aZyhPxF.js} +1 -1
  159. web/client/dist/assets/{SearchList-DB04sPb9.js → SearchList-W_iT2G82.js} +1 -1
  160. web/client/dist/assets/{SelectEnvironment-CUYcXUu6.js → SelectEnvironment-C65jALmO.js} +1 -1
  161. web/client/dist/assets/{SourceList-Doo_9ZGp.js → SourceList-DSLO6nVJ.js} +1 -1
  162. web/client/dist/assets/{SourceListItem-D5Mj7Dly.js → SourceListItem-BHt8d9-I.js} +1 -1
  163. web/client/dist/assets/{SplitPane-qHmkD1qy.js → SplitPane-CViaZmw6.js} +1 -1
  164. web/client/dist/assets/{Tests-DH1Z74ML.js → Tests-DhaVt5t1.js} +1 -1
  165. web/client/dist/assets/{Welcome-DqUJUNMF.js → Welcome-DvpjH-_4.js} +1 -1
  166. web/client/dist/assets/context-BctCsyGb.js +71 -0
  167. web/client/dist/assets/{context-Dr54UHLi.js → context-DFNeGsFF.js} +1 -1
  168. web/client/dist/assets/{editor-DYIP1yQ4.js → editor-CcO28cqd.js} +1 -1
  169. web/client/dist/assets/{file-DarlIDVi.js → file-CvJN3aZO.js} +1 -1
  170. web/client/dist/assets/{floating-ui.react-dom-BH3TFvkM.js → floating-ui.react-dom-CjE-JNW1.js} +1 -1
  171. web/client/dist/assets/{help-Bl8wqaQc.js → help-DuPhjipa.js} +1 -1
  172. web/client/dist/assets/{index-D1sR7wpN.js → index-C-dJH7yZ.js} +1 -1
  173. web/client/dist/assets/{index-O3mjYpnE.js → index-Dj0i1-CA.js} +2 -2
  174. web/client/dist/assets/{plan-CehRrJUG.js → plan-BTRSbjKn.js} +1 -1
  175. web/client/dist/assets/{popover-CqgMRE0G.js → popover-_Sf0yvOI.js} +1 -1
  176. web/client/dist/assets/{project-6gxepOhm.js → project-BvSOI8MY.js} +1 -1
  177. web/client/dist/index.html +1 -1
  178. web/client/dist/assets/Lineage-D0Hgdz2v.js +0 -1
  179. web/client/dist/assets/context-DgX0fp2E.js +0 -68
  180. {sqlmesh-0.217.1.dev1.dist-info → sqlmesh-0.227.2.dev4.dist-info}/WHEEL +0 -0
  181. {sqlmesh-0.217.1.dev1.dist-info → sqlmesh-0.227.2.dev4.dist-info}/entry_points.txt +0 -0
  182. {sqlmesh-0.217.1.dev1.dist-info → sqlmesh-0.227.2.dev4.dist-info}/licenses/LICENSE +0 -0
  183. {sqlmesh-0.217.1.dev1.dist-info → sqlmesh-0.227.2.dev4.dist-info}/top_level.txt +0 -0
@@ -185,6 +185,8 @@ class SnapshotIntervals(PydanticModel):
185
185
  intervals: Intervals = []
186
186
  dev_intervals: Intervals = []
187
187
  pending_restatement_intervals: Intervals = []
188
+ last_altered_ts: t.Optional[int] = None
189
+ dev_last_altered_ts: t.Optional[int] = None
188
190
 
189
191
  @property
190
192
  def snapshot_id(self) -> t.Optional[SnapshotId]:
@@ -205,6 +207,12 @@ class SnapshotIntervals(PydanticModel):
205
207
  def add_pending_restatement_interval(self, start: int, end: int) -> None:
206
208
  self._add_interval(start, end, "pending_restatement_intervals")
207
209
 
210
+ def update_last_altered_ts(self, last_altered_ts: t.Optional[int]) -> None:
211
+ self._update_last_altered_ts(last_altered_ts, "last_altered_ts")
212
+
213
+ def update_dev_last_altered_ts(self, last_altered_ts: t.Optional[int]) -> None:
214
+ self._update_last_altered_ts(last_altered_ts, "dev_last_altered_ts")
215
+
208
216
  def remove_interval(self, start: int, end: int) -> None:
209
217
  self._remove_interval(start, end, "intervals")
210
218
 
@@ -224,6 +232,13 @@ class SnapshotIntervals(PydanticModel):
224
232
  target_intervals = merge_intervals([*target_intervals, (start, end)])
225
233
  setattr(self, interval_attr, target_intervals)
226
234
 
235
+ def _update_last_altered_ts(
236
+ self, last_altered_ts: t.Optional[int], last_altered_attr: str
237
+ ) -> None:
238
+ if last_altered_ts:
239
+ existing_last_altered_ts = getattr(self, last_altered_attr)
240
+ setattr(self, last_altered_attr, max(existing_last_altered_ts or 0, last_altered_ts))
241
+
227
242
  def _remove_interval(self, start: int, end: int, interval_attr: str) -> None:
228
243
  target_intervals = getattr(self, interval_attr)
229
244
  target_intervals = remove_interval(target_intervals, start, end)
@@ -587,14 +602,26 @@ class SnapshotTableInfo(PydanticModel, SnapshotInfoMixin, frozen=True):
587
602
  """Returns the name and version of the snapshot."""
588
603
  return SnapshotNameVersion(name=self.name, version=self.version)
589
604
 
605
+ @property
606
+ def id_and_version(self) -> SnapshotIdAndVersion:
607
+ return SnapshotIdAndVersion(
608
+ name=self.name,
609
+ kind_name=self.kind_name,
610
+ identifier=self.identifier,
611
+ version=self.version,
612
+ dev_version=self.dev_version,
613
+ fingerprint=self.fingerprint,
614
+ )
590
615
 
591
- class SnapshotIdAndVersion(PydanticModel):
616
+
617
+ class SnapshotIdAndVersion(PydanticModel, ModelKindMixin):
592
618
  """A stripped down version of a snapshot that is used in situations where we want to fetch the main fields of the snapshots table
593
619
  without the overhead of parsing the full snapshot payload and fetching intervals.
594
620
  """
595
621
 
596
622
  name: str
597
623
  version: str
624
+ kind_name_: t.Optional[ModelKindName] = Field(default=None, alias="kind_name")
598
625
  dev_version_: t.Optional[str] = Field(alias="dev_version")
599
626
  identifier: str
600
627
  fingerprint_: t.Union[str, SnapshotFingerprint] = Field(alias="fingerprint")
@@ -603,6 +630,10 @@ class SnapshotIdAndVersion(PydanticModel):
603
630
  def snapshot_id(self) -> SnapshotId:
604
631
  return SnapshotId(name=self.name, identifier=self.identifier)
605
632
 
633
+ @property
634
+ def id_and_version(self) -> SnapshotIdAndVersion:
635
+ return self
636
+
606
637
  @property
607
638
  def name_version(self) -> SnapshotNameVersion:
608
639
  return SnapshotNameVersion(name=self.name, version=self.version)
@@ -618,6 +649,20 @@ class SnapshotIdAndVersion(PydanticModel):
618
649
  def dev_version(self) -> str:
619
650
  return self.dev_version_ or self.fingerprint.to_version()
620
651
 
652
+ @property
653
+ def model_kind_name(self) -> t.Optional[ModelKindName]:
654
+ return self.kind_name_
655
+
656
+ def display_name(
657
+ self,
658
+ environment_naming_info: EnvironmentNamingInfo,
659
+ default_catalog: t.Optional[str],
660
+ dialect: DialectType = None,
661
+ ) -> str:
662
+ return model_display_name(
663
+ self.name, environment_naming_info, default_catalog, dialect=dialect
664
+ )
665
+
621
666
 
622
667
  class Snapshot(PydanticModel, SnapshotInfoMixin):
623
668
  """A snapshot represents a node at a certain point in time.
@@ -683,6 +728,10 @@ class Snapshot(PydanticModel, SnapshotInfoMixin):
683
728
  dev_table_suffix: str = "dev"
684
729
  table_naming_convention: TableNamingConvention = TableNamingConvention.default
685
730
  forward_only: bool = False
731
+ # Physical table last modified timestamp, not to be confused with the "updated_ts" field
732
+ # which is for the snapshot record itself
733
+ last_altered_ts: t.Optional[int] = None
734
+ dev_last_altered_ts: t.Optional[int] = None
686
735
 
687
736
  @field_validator("ttl")
688
737
  @classmethod
@@ -721,6 +770,7 @@ class Snapshot(PydanticModel, SnapshotInfoMixin):
721
770
  )
722
771
  for interval in snapshot_intervals:
723
772
  snapshot.merge_intervals(interval)
773
+
724
774
  result.append(snapshot)
725
775
 
726
776
  return result
@@ -927,12 +977,20 @@ class Snapshot(PydanticModel, SnapshotInfoMixin):
927
977
  if not apply_effective_from or end <= effective_from_ts:
928
978
  self.add_interval(start, end)
929
979
 
980
+ if other.last_altered_ts:
981
+ self.last_altered_ts = max(self.last_altered_ts or 0, other.last_altered_ts)
982
+
930
983
  if self.dev_version == other.dev_version:
931
984
  # Merge dev intervals if the dev versions match which would mean
932
985
  # that this and the other snapshot are pointing to the same dev table.
933
986
  for start, end in other.dev_intervals:
934
987
  self.add_interval(start, end, is_dev=True)
935
988
 
989
+ if other.dev_last_altered_ts:
990
+ self.dev_last_altered_ts = max(
991
+ self.dev_last_altered_ts or 0, other.dev_last_altered_ts
992
+ )
993
+
936
994
  self.pending_restatement_intervals = merge_intervals(
937
995
  [*self.pending_restatement_intervals, *other.pending_restatement_intervals]
938
996
  )
@@ -1051,6 +1109,7 @@ class Snapshot(PydanticModel, SnapshotInfoMixin):
1051
1109
  python_env=signals.python_env,
1052
1110
  dialect=self.model.dialect,
1053
1111
  path=self.model._path,
1112
+ snapshot=self,
1054
1113
  kwargs=kwargs,
1055
1114
  )
1056
1115
  except SQLMeshError as e:
@@ -1424,6 +1483,10 @@ class Snapshot(PydanticModel, SnapshotInfoMixin):
1424
1483
  """Returns the name and version of the snapshot."""
1425
1484
  return SnapshotNameVersion(name=self.name, version=self.version)
1426
1485
 
1486
+ @property
1487
+ def id_and_version(self) -> SnapshotIdAndVersion:
1488
+ return self.table_info.id_and_version
1489
+
1427
1490
  @property
1428
1491
  def disable_restatement(self) -> bool:
1429
1492
  """Is restatement disabled for the node"""
@@ -1443,19 +1506,19 @@ class Snapshot(PydanticModel, SnapshotInfoMixin):
1443
1506
  check_categorical_relative_expression=False,
1444
1507
  )
1445
1508
 
1509
+ @property
1510
+ def supports_schema_migration_in_prod(self) -> bool:
1511
+ """Returns whether or not this snapshot supports schema migration when deployed to production."""
1512
+ return self.is_paused and self.is_model and not self.is_symbolic and not self.is_seed
1513
+
1446
1514
  @property
1447
1515
  def requires_schema_migration_in_prod(self) -> bool:
1448
1516
  """Returns whether or not this snapshot requires a schema migration when deployed to production."""
1449
- return (
1450
- self.is_paused
1451
- and self.is_model
1452
- and self.is_materialized
1453
- and (
1454
- (self.previous_version and self.previous_version.version == self.version)
1455
- or self.model.forward_only
1456
- or bool(self.model.physical_version)
1457
- or not self.virtual_environment_mode.is_full
1458
- )
1517
+ return self.supports_schema_migration_in_prod and (
1518
+ (self.previous_version and self.previous_version.version == self.version)
1519
+ or self.model.forward_only
1520
+ or bool(self.model.physical_version)
1521
+ or not self.virtual_environment_mode.is_full
1459
1522
  )
1460
1523
 
1461
1524
  @property
@@ -1494,7 +1557,8 @@ class SnapshotTableCleanupTask(PydanticModel):
1494
1557
  dev_table_only: bool
1495
1558
 
1496
1559
 
1497
- SnapshotIdLike = t.Union[SnapshotId, SnapshotTableInfo, SnapshotIdAndVersion, Snapshot]
1560
+ SnapshotIdLike = t.Union[SnapshotId, SnapshotIdAndVersion, SnapshotTableInfo, Snapshot]
1561
+ SnapshotIdAndVersionLike = t.Union[SnapshotIdAndVersion, SnapshotTableInfo, Snapshot]
1498
1562
  SnapshotInfoLike = t.Union[SnapshotTableInfo, Snapshot]
1499
1563
  SnapshotNameVersionLike = t.Union[
1500
1564
  SnapshotNameVersion, SnapshotTableInfo, SnapshotIdAndVersion, Snapshot
@@ -1763,7 +1827,19 @@ def display_name(
1763
1827
  """
1764
1828
  if snapshot_info_like.is_audit:
1765
1829
  return snapshot_info_like.name
1766
- view_name = exp.to_table(snapshot_info_like.name)
1830
+
1831
+ return model_display_name(
1832
+ snapshot_info_like.name, environment_naming_info, default_catalog, dialect
1833
+ )
1834
+
1835
+
1836
+ def model_display_name(
1837
+ node_name: str,
1838
+ environment_naming_info: EnvironmentNamingInfo,
1839
+ default_catalog: t.Optional[str],
1840
+ dialect: DialectType = None,
1841
+ ) -> str:
1842
+ view_name = exp.to_table(node_name)
1767
1843
 
1768
1844
  catalog = (
1769
1845
  None
@@ -2005,16 +2081,20 @@ def missing_intervals(
2005
2081
  continue
2006
2082
  snapshot_end_date = existing_interval_end
2007
2083
 
2084
+ snapshot_start_date = max(
2085
+ to_datetime(snapshot_start_date),
2086
+ to_datetime(start_date(snapshot, snapshots, cache, relative_to=snapshot_end_date)),
2087
+ )
2088
+ if snapshot_start_date > to_datetime(snapshot_end_date):
2089
+ continue
2090
+
2008
2091
  missing_interval_end_date = snapshot_end_date
2009
2092
  node_end_date = snapshot.node.end
2010
2093
  if node_end_date and (to_datetime(node_end_date) < to_datetime(snapshot_end_date)):
2011
2094
  missing_interval_end_date = node_end_date
2012
2095
 
2013
2096
  intervals = snapshot.missing_intervals(
2014
- max(
2015
- to_datetime(snapshot_start_date),
2016
- to_datetime(start_date(snapshot, snapshots, cache, relative_to=snapshot_end_date)),
2017
- ),
2097
+ snapshot_start_date,
2018
2098
  missing_interval_end_date,
2019
2099
  execution_time=execution_time,
2020
2100
  deployability_index=deployability_index,
@@ -2219,14 +2299,16 @@ def start_date(
2219
2299
  if not isinstance(snapshots, dict):
2220
2300
  snapshots = {snapshot.snapshot_id: snapshot for snapshot in snapshots}
2221
2301
 
2222
- earliest = snapshot.node.cron_prev(snapshot.node.cron_floor(relative_to or now()))
2223
-
2224
- for parent in snapshot.parents:
2225
- if parent in snapshots:
2226
- earliest = min(
2227
- earliest,
2228
- start_date(snapshots[parent], snapshots, cache=cache, relative_to=relative_to),
2229
- )
2302
+ parent_starts = [
2303
+ start_date(snapshots[parent], snapshots, cache=cache, relative_to=relative_to)
2304
+ for parent in snapshot.parents
2305
+ if parent in snapshots
2306
+ ]
2307
+ earliest = (
2308
+ min(parent_starts)
2309
+ if parent_starts
2310
+ else snapshot.node.cron_prev(snapshot.node.cron_floor(relative_to or now()))
2311
+ )
2230
2312
 
2231
2313
  cache[key] = earliest
2232
2314
  return earliest
@@ -2374,6 +2456,7 @@ def check_ready_intervals(
2374
2456
  python_env: t.Dict[str, Executable],
2375
2457
  dialect: DialectType = None,
2376
2458
  path: t.Optional[Path] = None,
2459
+ snapshot: t.Optional[Snapshot] = None,
2377
2460
  kwargs: t.Optional[t.Dict] = None,
2378
2461
  ) -> Intervals:
2379
2462
  checked_intervals: Intervals = []
@@ -2389,6 +2472,7 @@ def check_ready_intervals(
2389
2472
  provided_args=(batch,),
2390
2473
  provided_kwargs=(kwargs or {}),
2391
2474
  context=context,
2475
+ snapshot=snapshot,
2392
2476
  )
2393
2477
  except Exception as ex:
2394
2478
  raise SignalEvalError(format_evaluated_code_exception(ex, python_env))