11"""Data model."""
22
3- from pydantic import BaseModel , Field
3+ from enum import Enum
4+
5+ from pydantic import BaseModel , Field , model_validator
6+
7+
8+ class OrderBy (str , Enum ):
9+ """CubeJS order by available options.
10+
11+ If the order property is not specified in the query, Cube sorts results by default:
12+ 1. First time dimension with granularity (ascending)
13+ 2. If no time dimension exists, first measure (descending)
14+ 3. If no measure exists, first dimension (ascending)
15+
16+ The order can be specified either as a dict mapping fields to ASC/DESC,
17+ or as an array of tuples for controlling the ordering sequence.
18+ """
19+
20+ ASC = "asc"
21+ DESC = "desc"
22+
23+
24+ class Granularity (str , Enum ):
25+ """CubeJS granularity available for time dimensions.
26+
27+ Time-based properties are modeled using dimensions of the time type. They allow
28+ grouping the result set by a unit of time (e.g., days, weeks, month, etc.), also
29+ known as the time dimension granularity.
30+
31+ The following granularities are available by default for any time dimension
32+ """
33+
34+ YEAR = "year"
35+ QUARTER = "quarter"
36+ MONTH = "month"
37+ WEEK = "week"
38+ DAY = "day"
39+ HOUR = "hour"
40+ MINUTE = "minute"
41+ SECOND = "second"
42+
43+
44+ class FilterOperators (str , Enum ):
45+ """CubeJS available filter operations.
46+
47+ Different operators are available depending on whether they're applied to measures
48+ or dimensions, and for dimensions, the available operators depend on the dimension
49+ type.
50+
51+ Operators for measures:
52+ - equals, notEquals: Exact match or its opposite. Supports multiple values.
53+ - gt, gte, lt, lte: Greater than, greater than or equal, less than,
54+ less than or equal.
55+ - set, notSet: Checks if value is not NULL or is NULL respectively.
56+ - measureFilter: Applies an existing measure's filters to the current query.
57+
58+ Operators for dimensions (availability depends on dimension type):
59+ - string: equals, notEquals, contains, notContains, startsWith, notStartsWith,
60+ endsWith, notEndsWith, set, notSet
61+ - number: equals, notEquals, gt, gte, lt, lte, set, notSet
62+ - time: equals, notEquals, inDateRange, notInDateRange, beforeDate, afterDate,
63+ set, notSet
64+ """
65+
66+ EQUALS = "equals"
67+ NOT_EQUALS = "notEquals"
68+ CONTAINS = "contains"
69+ NOT_CONTAINS = "notContains"
70+ STARTS_WITH = "startsWith"
71+ NOT_STARTS_WITH = "notStartsWith"
72+ ENDS_WITH = "endsWith"
73+ NOT_ENDS_WITH = "notEndsWith"
74+ GREATER_THAN = "gt"
75+ GREATER_THAN_OR_EQUAL = "gte"
76+ LESS_THAN = "lt"
77+ LESS_THAN_OR_EQUAL = "lte"
78+ SET = "set"
79+ NOT_SET = "notSet"
80+ IN_DATE_RANGE = "inDateRange"
81+ NOT_IN_DATE_RANGE = "notInDateRange"
82+ BEFORE_DATE = "beforeDate"
83+ AFTER_DATE = "afterDate"
84+ MEASURE_FILTER = "measureFilter"
485
586
687class TimeDimension (BaseModel ):
7- """Time dimension section of a cubejs request .
88+ """Time dimension filters and grouping .
889
9- Args:
10- dimension: column name to use as time reference.
11- granularity: granularity to transform the timestamp.
12- date_range: date range to filter the query.
90+ Provides a convenient shortcut to pass a dimension and filter as a TimeDimension.
1391
92+ Args:
93+ dimension: Time dimension name to use for filtering and/or grouping.
94+ granularity: A granularity for the time dimension. Can be one of the default
95+ granularities (e.g., year, week, day) or a custom granularity. If not
96+ provided, Cube will only filter by the time dimension without grouping.
97+ date_range: Date range for filtering. Can be:
98+ - An array of dates in YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss.SSS format
99+ - A single date (equivalent to passing two identical dates)
100+ - A string with a relative date range (e.g., "last quarter")
101+ Values should be local and in query timezone. YYYY-MM-DD dates are padded
102+ to start/end of day when used as range boundaries.
103+ compare_date_range: An array of date ranges to compare measure values across
104+ different time periods.
14105 """
15106
16107 dimension : str
17- granularity : str | None = None
108+ granularity : Granularity | None = None
18109 date_range : list [str ] | str | None = Field (
19110 default = None , serialization_alias = "dateRange"
20111 )
112+ compare_date_range : list [list [str ] | str ] | None = Field (
113+ default = None , serialization_alias = "compareDateRange"
114+ )
115+
116+ @model_validator (mode = "after" )
117+ def validate_date_ranges (self ) -> "TimeDimension" :
118+ """Validate date range configurations."""
119+ if self .date_range is not None and self .compare_date_range is not None :
120+ raise ValueError ("Cannot provide both date_range and compare_date_range" )
121+
122+ if self .compare_date_range is not None :
123+ for date_range in self .compare_date_range :
124+ if isinstance (date_range , list ) and len (date_range ) != 2 :
125+ raise ValueError (
126+ "Each compare_date_range entry must contain exactly 2 "
127+ "dates when provided"
128+ )
129+
130+ return self
21131
22132 class Config : # noqa: D106
23133 exclude_none = True
@@ -27,16 +137,52 @@ class Config: # noqa: D106
27137class Filter (BaseModel ):
28138 """Filter section of a cubejs request.
29139
30- Args:
31- member: member to filter by.
32- operator: operator to apply.
33- values: values to filter by.
140+ Filters can be applied to dimensions or measures:
141+ - When filtering dimensions, raw data is restricted before calculations
142+ - When filtering measures, results are restricted after measure calculation
34143
144+ Args:
145+ member: Dimension or measure to filter by (e.g., "stories.isDraft").
146+ operator: Operator to apply to the filter. Available operators depend on
147+ whether filtering a dimension or measure, and the type of dimension.
148+ See FilterOperators for available options.
149+ values: Array of values for the filter. Values must be strings.
150+ For dates, use YYYY-MM-DD format. Optional for some operators
151+ like 'set' and 'notSet'.
35152 """
36153
37154 member : str
38155 operator : str
39- values : list [str ]
156+ values : list [str ] | None = None
157+
158+
159+ class LogicalOperator (BaseModel ):
160+ """Logical operator for combining filters.
161+
162+ Allows combining multiple filters with boolean logic. You can use either 'or_' or
163+ 'and_' to create complex filter conditions.
164+
165+ Note:
166+ - You cannot mix dimension and measure filters in the same logical operator
167+ - Dimension filters apply to raw data (WHERE clause in SQL)
168+ - Measure filters apply to aggregated data (HAVING clause in SQL)
169+
170+ Args:
171+ or_: List of filters or other logical operators to combine with OR.
172+ and_: List of filters or other logical operators to combine with AND.
173+ """
174+
175+ or_ : list ["FilterOrLogical" ] | None = Field (default = None , serialization_alias = "or" )
176+ and_ : list ["FilterOrLogical" ] | None = Field (
177+ default = None , serialization_alias = "and"
178+ )
179+
180+ class Config : # noqa: D106
181+ exclude_none = True
182+ populate_by_name = True
183+
184+
185+ FilterOrLogical = Filter | LogicalOperator
40186
41187
42188class CubeJSRequest (BaseModel ):
@@ -47,21 +193,23 @@ class CubeJSRequest(BaseModel):
47193 time_dimensions: time dimensions to aggregate measures by.
48194 dimensions: dimensions to group by.
49195 segments: segments to filter by.
50- filters: other filters to apply.
196+ filters: other filters to apply (can include logical operators) .
51197 order: order records in response by.
52198 limit: limit the number of records in response.
199+ offset: number of records to skip in response.
53200
54201 """
55202
56- measures : list [str ]
203+ measures : list [str ] = Field ( default_factory = list )
57204 time_dimensions : list [TimeDimension ] | None = Field (
58205 serialization_alias = "timeDimensions" , default = None
59206 )
60207 dimensions : list [str ] | None = None
61208 segments : list [str ] | None = None
62- filters : list [Filter ] | None = None
63- order : dict [str , str ] | None = None
209+ filters : list [FilterOrLogical ] = Field ( default_factory = list )
210+ order : dict [str , OrderBy ] | None = None
64211 limit : int | None = None
212+ offset : int | None = None
65213
66214
67215class CubeJSAuth (BaseModel ):
0 commit comments