2121 from sqlmesh .core .snapshot import Node
2222
2323
24+ DEFAULT_SAMPLE_SIZE = 5
25+
26+
2427class IntervalUnit (str , Enum ):
2528 """IntervalUnit is the inferred granularity of an incremental node.
2629
@@ -33,17 +36,19 @@ class IntervalUnit(str, Enum):
3336 MONTH = "month"
3437 DAY = "day"
3538 HOUR = "hour"
36- MINUTE = "minute"
39+ HALF_HOUR = "half_hour"
40+ QUARTER_HOUR = "quarter_hour"
41+ FIVE_MINUTE = "five_minute"
3742
3843 @classmethod
39- def from_cron (klass , cron : str , sample_size : int = 10 ) -> IntervalUnit :
44+ def from_cron (klass , cron : str , sample_size : int = DEFAULT_SAMPLE_SIZE ) -> IntervalUnit :
4045 croniter = CroniterCache (cron )
4146 samples = [croniter .get_next () for _ in range (sample_size )]
4247 min_interval = min (b - a for a , b in zip (samples , samples [1 :]))
4348 for unit , seconds in sorted (INTERVAL_SECONDS .items (), key = lambda x : x [1 ], reverse = True ):
44- if seconds <= min_interval :
49+ if seconds <= min_interval . total_seconds () :
4550 return unit
46- raise ConfigError (f"Invalid cron '{ cron } ': must have a cadence of 1 minute or more." )
51+ raise ConfigError (f"Invalid cron '{ cron } ': must have a cadence of 5 minutes or more." )
4752
4853 @property
4954 def is_date_granularity (self ) -> bool :
@@ -67,12 +72,16 @@ def is_hour(self) -> bool:
6772
6873 @property
6974 def is_minute (self ) -> bool :
70- return self == IntervalUnit .MINUTE
75+ return self in ( IntervalUnit .FIVE_MINUTE , IntervalUnit . QUARTER_HOUR , IntervalUnit . HALF_HOUR )
7176
7277 @property
7378 def _cron_expr (self ) -> str :
74- if self == IntervalUnit .MINUTE :
75- return "* * * * *"
79+ if self == IntervalUnit .FIVE_MINUTE :
80+ return "*/5 * * * *"
81+ if self == IntervalUnit .QUARTER_HOUR :
82+ return "*/15 * * * *"
83+ if self == IntervalUnit .HALF_HOUR :
84+ return "*/30 * * * *"
7685 if self == IntervalUnit .HOUR :
7786 return "0 * * * *"
7887 if self == IntervalUnit .DAY :
@@ -132,7 +141,9 @@ def seconds(self) -> int:
132141 IntervalUnit .MONTH : 60 * 60 * 24 * 28 ,
133142 IntervalUnit .DAY : 60 * 60 * 24 ,
134143 IntervalUnit .HOUR : 60 * 60 ,
135- IntervalUnit .MINUTE : 60 ,
144+ IntervalUnit .HALF_HOUR : 60 * 30 ,
145+ IntervalUnit .QUARTER_HOUR : 60 * 15 ,
146+ IntervalUnit .FIVE_MINUTE : 60 * 5 ,
136147}
137148
138149
@@ -265,7 +276,7 @@ def croniter(self, value: TimeLike) -> CroniterCache:
265276 if self ._croniter is None :
266277 self ._croniter = CroniterCache (self .cron , value )
267278 else :
268- self ._croniter .curr = value
279+ self ._croniter .curr = to_datetime ( value )
269280 return self ._croniter
270281
271282 def cron_next (self , value : TimeLike ) -> TimeLike :
@@ -315,7 +326,7 @@ def text_diff(self, other: Node) -> str:
315326 """
316327 raise NotImplementedError
317328
318- def _inferred_interval_unit (self , sample_size : int = 10 ) -> IntervalUnit :
329+ def _inferred_interval_unit (self , sample_size : int = DEFAULT_SAMPLE_SIZE ) -> IntervalUnit :
319330 """Infers the interval unit from the cron expression.
320331
321332 The interval unit is used to determine the lag applied to start_date and end_date for node rendering and intervals.
0 commit comments