pytrilogy 0.3.148__cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.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 (206) hide show
  1. LICENSE.md +19 -0
  2. _preql_import_resolver/__init__.py +5 -0
  3. _preql_import_resolver/_preql_import_resolver.cpython-312-aarch64-linux-gnu.so +0 -0
  4. pytrilogy-0.3.148.dist-info/METADATA +555 -0
  5. pytrilogy-0.3.148.dist-info/RECORD +206 -0
  6. pytrilogy-0.3.148.dist-info/WHEEL +5 -0
  7. pytrilogy-0.3.148.dist-info/entry_points.txt +2 -0
  8. pytrilogy-0.3.148.dist-info/licenses/LICENSE.md +19 -0
  9. trilogy/__init__.py +27 -0
  10. trilogy/ai/README.md +10 -0
  11. trilogy/ai/__init__.py +19 -0
  12. trilogy/ai/constants.py +92 -0
  13. trilogy/ai/conversation.py +107 -0
  14. trilogy/ai/enums.py +7 -0
  15. trilogy/ai/execute.py +50 -0
  16. trilogy/ai/models.py +34 -0
  17. trilogy/ai/prompts.py +100 -0
  18. trilogy/ai/providers/__init__.py +0 -0
  19. trilogy/ai/providers/anthropic.py +106 -0
  20. trilogy/ai/providers/base.py +24 -0
  21. trilogy/ai/providers/google.py +146 -0
  22. trilogy/ai/providers/openai.py +89 -0
  23. trilogy/ai/providers/utils.py +68 -0
  24. trilogy/authoring/README.md +3 -0
  25. trilogy/authoring/__init__.py +148 -0
  26. trilogy/constants.py +119 -0
  27. trilogy/core/README.md +52 -0
  28. trilogy/core/__init__.py +0 -0
  29. trilogy/core/constants.py +6 -0
  30. trilogy/core/enums.py +454 -0
  31. trilogy/core/env_processor.py +239 -0
  32. trilogy/core/environment_helpers.py +320 -0
  33. trilogy/core/ergonomics.py +193 -0
  34. trilogy/core/exceptions.py +123 -0
  35. trilogy/core/functions.py +1240 -0
  36. trilogy/core/graph_models.py +142 -0
  37. trilogy/core/internal.py +85 -0
  38. trilogy/core/models/__init__.py +0 -0
  39. trilogy/core/models/author.py +2662 -0
  40. trilogy/core/models/build.py +2603 -0
  41. trilogy/core/models/build_environment.py +165 -0
  42. trilogy/core/models/core.py +506 -0
  43. trilogy/core/models/datasource.py +434 -0
  44. trilogy/core/models/environment.py +756 -0
  45. trilogy/core/models/execute.py +1213 -0
  46. trilogy/core/optimization.py +251 -0
  47. trilogy/core/optimizations/__init__.py +12 -0
  48. trilogy/core/optimizations/base_optimization.py +17 -0
  49. trilogy/core/optimizations/hide_unused_concept.py +47 -0
  50. trilogy/core/optimizations/inline_datasource.py +102 -0
  51. trilogy/core/optimizations/predicate_pushdown.py +245 -0
  52. trilogy/core/processing/README.md +94 -0
  53. trilogy/core/processing/READMEv2.md +121 -0
  54. trilogy/core/processing/VIRTUAL_UNNEST.md +30 -0
  55. trilogy/core/processing/__init__.py +0 -0
  56. trilogy/core/processing/concept_strategies_v3.py +508 -0
  57. trilogy/core/processing/constants.py +15 -0
  58. trilogy/core/processing/discovery_node_factory.py +451 -0
  59. trilogy/core/processing/discovery_utility.py +548 -0
  60. trilogy/core/processing/discovery_validation.py +167 -0
  61. trilogy/core/processing/graph_utils.py +43 -0
  62. trilogy/core/processing/node_generators/README.md +9 -0
  63. trilogy/core/processing/node_generators/__init__.py +31 -0
  64. trilogy/core/processing/node_generators/basic_node.py +160 -0
  65. trilogy/core/processing/node_generators/common.py +270 -0
  66. trilogy/core/processing/node_generators/constant_node.py +38 -0
  67. trilogy/core/processing/node_generators/filter_node.py +315 -0
  68. trilogy/core/processing/node_generators/group_node.py +213 -0
  69. trilogy/core/processing/node_generators/group_to_node.py +117 -0
  70. trilogy/core/processing/node_generators/multiselect_node.py +207 -0
  71. trilogy/core/processing/node_generators/node_merge_node.py +695 -0
  72. trilogy/core/processing/node_generators/recursive_node.py +88 -0
  73. trilogy/core/processing/node_generators/rowset_node.py +165 -0
  74. trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
  75. trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +261 -0
  76. trilogy/core/processing/node_generators/select_merge_node.py +786 -0
  77. trilogy/core/processing/node_generators/select_node.py +95 -0
  78. trilogy/core/processing/node_generators/synonym_node.py +98 -0
  79. trilogy/core/processing/node_generators/union_node.py +91 -0
  80. trilogy/core/processing/node_generators/unnest_node.py +182 -0
  81. trilogy/core/processing/node_generators/window_node.py +201 -0
  82. trilogy/core/processing/nodes/README.md +28 -0
  83. trilogy/core/processing/nodes/__init__.py +179 -0
  84. trilogy/core/processing/nodes/base_node.py +522 -0
  85. trilogy/core/processing/nodes/filter_node.py +75 -0
  86. trilogy/core/processing/nodes/group_node.py +194 -0
  87. trilogy/core/processing/nodes/merge_node.py +420 -0
  88. trilogy/core/processing/nodes/recursive_node.py +46 -0
  89. trilogy/core/processing/nodes/select_node_v2.py +242 -0
  90. trilogy/core/processing/nodes/union_node.py +53 -0
  91. trilogy/core/processing/nodes/unnest_node.py +62 -0
  92. trilogy/core/processing/nodes/window_node.py +56 -0
  93. trilogy/core/processing/utility.py +823 -0
  94. trilogy/core/query_processor.py +604 -0
  95. trilogy/core/statements/README.md +35 -0
  96. trilogy/core/statements/__init__.py +0 -0
  97. trilogy/core/statements/author.py +536 -0
  98. trilogy/core/statements/build.py +0 -0
  99. trilogy/core/statements/common.py +20 -0
  100. trilogy/core/statements/execute.py +155 -0
  101. trilogy/core/table_processor.py +66 -0
  102. trilogy/core/utility.py +8 -0
  103. trilogy/core/validation/README.md +46 -0
  104. trilogy/core/validation/__init__.py +0 -0
  105. trilogy/core/validation/common.py +161 -0
  106. trilogy/core/validation/concept.py +146 -0
  107. trilogy/core/validation/datasource.py +227 -0
  108. trilogy/core/validation/environment.py +73 -0
  109. trilogy/core/validation/fix.py +256 -0
  110. trilogy/dialect/__init__.py +32 -0
  111. trilogy/dialect/base.py +1431 -0
  112. trilogy/dialect/bigquery.py +314 -0
  113. trilogy/dialect/common.py +147 -0
  114. trilogy/dialect/config.py +159 -0
  115. trilogy/dialect/dataframe.py +50 -0
  116. trilogy/dialect/duckdb.py +376 -0
  117. trilogy/dialect/enums.py +149 -0
  118. trilogy/dialect/metadata.py +173 -0
  119. trilogy/dialect/mock.py +190 -0
  120. trilogy/dialect/postgres.py +117 -0
  121. trilogy/dialect/presto.py +110 -0
  122. trilogy/dialect/results.py +89 -0
  123. trilogy/dialect/snowflake.py +129 -0
  124. trilogy/dialect/sql_server.py +137 -0
  125. trilogy/engine.py +48 -0
  126. trilogy/execution/__init__.py +17 -0
  127. trilogy/execution/config.py +119 -0
  128. trilogy/execution/state/__init__.py +0 -0
  129. trilogy/execution/state/file_state_store.py +0 -0
  130. trilogy/execution/state/sqllite_state_store.py +0 -0
  131. trilogy/execution/state/state_store.py +301 -0
  132. trilogy/executor.py +656 -0
  133. trilogy/hooks/__init__.py +4 -0
  134. trilogy/hooks/base_hook.py +40 -0
  135. trilogy/hooks/graph_hook.py +135 -0
  136. trilogy/hooks/query_debugger.py +166 -0
  137. trilogy/metadata/__init__.py +0 -0
  138. trilogy/parser.py +10 -0
  139. trilogy/parsing/README.md +21 -0
  140. trilogy/parsing/__init__.py +0 -0
  141. trilogy/parsing/common.py +1069 -0
  142. trilogy/parsing/config.py +5 -0
  143. trilogy/parsing/exceptions.py +8 -0
  144. trilogy/parsing/helpers.py +1 -0
  145. trilogy/parsing/parse_engine.py +2863 -0
  146. trilogy/parsing/render.py +773 -0
  147. trilogy/parsing/trilogy.lark +544 -0
  148. trilogy/py.typed +0 -0
  149. trilogy/render.py +45 -0
  150. trilogy/scripts/README.md +9 -0
  151. trilogy/scripts/__init__.py +0 -0
  152. trilogy/scripts/agent.py +41 -0
  153. trilogy/scripts/agent_info.py +306 -0
  154. trilogy/scripts/common.py +430 -0
  155. trilogy/scripts/dependency/Cargo.lock +617 -0
  156. trilogy/scripts/dependency/Cargo.toml +39 -0
  157. trilogy/scripts/dependency/README.md +131 -0
  158. trilogy/scripts/dependency/build.sh +25 -0
  159. trilogy/scripts/dependency/src/directory_resolver.rs +387 -0
  160. trilogy/scripts/dependency/src/lib.rs +16 -0
  161. trilogy/scripts/dependency/src/main.rs +770 -0
  162. trilogy/scripts/dependency/src/parser.rs +435 -0
  163. trilogy/scripts/dependency/src/preql.pest +208 -0
  164. trilogy/scripts/dependency/src/python_bindings.rs +311 -0
  165. trilogy/scripts/dependency/src/resolver.rs +716 -0
  166. trilogy/scripts/dependency/tests/base.preql +3 -0
  167. trilogy/scripts/dependency/tests/cli_integration.rs +377 -0
  168. trilogy/scripts/dependency/tests/customer.preql +6 -0
  169. trilogy/scripts/dependency/tests/main.preql +9 -0
  170. trilogy/scripts/dependency/tests/orders.preql +7 -0
  171. trilogy/scripts/dependency/tests/test_data/base.preql +9 -0
  172. trilogy/scripts/dependency/tests/test_data/consumer.preql +1 -0
  173. trilogy/scripts/dependency.py +323 -0
  174. trilogy/scripts/display.py +555 -0
  175. trilogy/scripts/environment.py +59 -0
  176. trilogy/scripts/fmt.py +32 -0
  177. trilogy/scripts/ingest.py +472 -0
  178. trilogy/scripts/ingest_helpers/__init__.py +1 -0
  179. trilogy/scripts/ingest_helpers/foreign_keys.py +123 -0
  180. trilogy/scripts/ingest_helpers/formatting.py +93 -0
  181. trilogy/scripts/ingest_helpers/typing.py +161 -0
  182. trilogy/scripts/init.py +105 -0
  183. trilogy/scripts/parallel_execution.py +748 -0
  184. trilogy/scripts/plan.py +189 -0
  185. trilogy/scripts/refresh.py +106 -0
  186. trilogy/scripts/run.py +79 -0
  187. trilogy/scripts/serve.py +202 -0
  188. trilogy/scripts/serve_helpers/__init__.py +41 -0
  189. trilogy/scripts/serve_helpers/file_discovery.py +142 -0
  190. trilogy/scripts/serve_helpers/index_generation.py +206 -0
  191. trilogy/scripts/serve_helpers/models.py +38 -0
  192. trilogy/scripts/single_execution.py +131 -0
  193. trilogy/scripts/testing.py +129 -0
  194. trilogy/scripts/trilogy.py +75 -0
  195. trilogy/std/__init__.py +0 -0
  196. trilogy/std/color.preql +3 -0
  197. trilogy/std/date.preql +13 -0
  198. trilogy/std/display.preql +18 -0
  199. trilogy/std/geography.preql +22 -0
  200. trilogy/std/metric.preql +15 -0
  201. trilogy/std/money.preql +67 -0
  202. trilogy/std/net.preql +14 -0
  203. trilogy/std/ranking.preql +7 -0
  204. trilogy/std/report.preql +5 -0
  205. trilogy/std/semantic.preql +6 -0
  206. trilogy/utility.py +34 -0
trilogy/constants.py ADDED
@@ -0,0 +1,119 @@
1
+ import random
2
+ from contextlib import contextmanager
3
+ from dataclasses import dataclass, field
4
+ from enum import Enum
5
+ from logging import getLogger
6
+ from typing import Any
7
+
8
+ logger = getLogger("trilogy")
9
+
10
+ DEFAULT_NAMESPACE = "local"
11
+
12
+ RECURSIVE_GATING_CONCEPT = "_terminal"
13
+
14
+ VIRTUAL_CONCEPT_PREFIX = "_virt"
15
+
16
+ ENV_CACHE_NAME = ".preql_cache.json"
17
+
18
+
19
+ class MagicConstants(Enum):
20
+ NULL = "null"
21
+ LINE_SEPARATOR = "\n"
22
+
23
+
24
+ NULL_VALUE = MagicConstants.NULL
25
+
26
+
27
+ @dataclass
28
+ class Optimizations:
29
+ predicate_pushdown: bool = True
30
+ datasource_inlining: bool = True
31
+ constant_inlining: bool = True
32
+ constant_inline_cutoff: int = 10
33
+ direct_return: bool = True
34
+ hide_unused_concepts: bool = True
35
+
36
+
37
+ @dataclass
38
+ class Generation:
39
+ datasource_build_cache: bool = True
40
+
41
+
42
+ @dataclass
43
+ class Comments:
44
+ """Control what is placed in CTE comments"""
45
+
46
+ show: bool = False
47
+ basic: bool = True
48
+ joins: bool = False
49
+ nullable: bool = False
50
+ partial: bool = False
51
+ source_map: bool = False
52
+
53
+
54
+ @dataclass
55
+ class Rendering:
56
+ """Control how the SQL is rendered"""
57
+
58
+ parameters: bool = True
59
+ concise: bool = False
60
+
61
+ @contextmanager
62
+ def temporary(self, **kwargs: Any):
63
+ """
64
+ Context manager to temporarily set attributes and revert them afterwards.
65
+
66
+ Usage:
67
+ r = Rendering()
68
+ with r.temporary(parameters=False, concise=True):
69
+ # parameters is False, concise is True here
70
+ do_something()
71
+ # parameters and concise are back to their original values
72
+ """
73
+ # Store original values
74
+ original_values = {key: getattr(self, key) for key in kwargs}
75
+
76
+ # Set new values
77
+ for key, value in kwargs.items():
78
+ setattr(self, key, value)
79
+
80
+ try:
81
+ yield self
82
+ finally:
83
+ # Restore original values
84
+ for key, value in original_values.items():
85
+ setattr(self, key, value)
86
+
87
+
88
+ @dataclass
89
+ class Parsing:
90
+ """Control Parsing"""
91
+
92
+ strict_name_shadow_enforcement: bool = False
93
+ select_as_definition: bool = True
94
+
95
+
96
+ # TODO: support loading from environments
97
+ @dataclass
98
+ class Config:
99
+ strict_mode: bool = True
100
+ human_identifiers: bool = True
101
+ randomize_cte_names: bool = False
102
+ validate_missing: bool = True
103
+ comments: Comments = field(default_factory=Comments)
104
+ optimizations: Optimizations = field(default_factory=Optimizations)
105
+ rendering: Rendering = field(default_factory=Rendering)
106
+ parsing: Parsing = field(default_factory=Parsing)
107
+ generation: Generation = field(default_factory=Generation)
108
+
109
+ @property
110
+ def show_comments(self) -> bool:
111
+ return self.comments.show
112
+
113
+ def set_random_seed(self, seed: int):
114
+ random.seed(seed)
115
+
116
+
117
+ CONFIG = Config()
118
+
119
+ CONFIG.set_random_seed(42)
trilogy/core/README.md ADDED
@@ -0,0 +1,52 @@
1
+
2
+
3
+
4
+ ### Implicit Filtering Design
5
+
6
+ An implicit filter is any case where the where clause of a statement references more fields than are in the output of a select.
7
+
8
+ In those cases, those concepts are "promoted" up into a virtual CTE before the final output is returned.
9
+
10
+ THe `wrinkle` is aggregates - aggregates must have the implicit filter pushed "inside" the aggregate via the select_context
11
+ to ensure that they aggregate appropriately. Applying the condition after creating the aggregate would result in an incorrect
12
+ aggregation result.
13
+
14
+ ### Case 1 - Basic Scalar Filtering
15
+
16
+ SELECT
17
+ abc,
18
+ def
19
+ where
20
+ gde = 1
21
+
22
+
23
+ We should source
24
+ ABC,
25
+ DEF,
26
+ GDE
27
+
28
+ filter on GDE = 1;
29
+
30
+ return results with optional grouping.
31
+
32
+
33
+ ### Case 2 - Aggregate Filtering
34
+
35
+ SELECT
36
+ sum(abc)
37
+ WHERE
38
+ gde = 1
39
+
40
+ We should source
41
+
42
+ abc | gde =1
43
+
44
+ ;
45
+
46
+ ### Case 3 - Mixed filter
47
+
48
+ SELECT
49
+ sum(abc) by def,
50
+ def,
51
+ gde
52
+
File without changes
@@ -0,0 +1,6 @@
1
+ CONSTANT_DATASET: str = "preql_internal_constant_dataset"
2
+ ALL_ROWS_CONCEPT = "all_rows"
3
+ INTERNAL_NAMESPACE = "__preql_internal"
4
+ PERSISTED_CONCEPT_PREFIX = "__pre_persist"
5
+ UNNEST_NAME = "_unnest_alias"
6
+ WORKING_PATH_CONCEPT = "_env_working_path"
trilogy/core/enums.py ADDED
@@ -0,0 +1,454 @@
1
+ from enum import Enum
2
+
3
+ InfiniteFunctionArgs = -1
4
+
5
+
6
+ class DatasourceState(Enum):
7
+ PUBLISHED = "published"
8
+ UNPUBLISHED = "unpublished"
9
+
10
+
11
+ class CreateMode(Enum):
12
+ CREATE = "create"
13
+ CREATE_IF_NOT_EXISTS = "create_if_not_exists"
14
+ CREATE_OR_REPLACE = "create_or_replace"
15
+
16
+
17
+ class UnnestMode(Enum):
18
+ DIRECT = "direct"
19
+ CROSS_APPLY = "cross_apply"
20
+ CROSS_JOIN = "cross_join"
21
+ CROSS_JOIN_UNNEST = "cross_join_unnest"
22
+ CROSS_JOIN_ALIAS = "cross_join_alias"
23
+ PRESTO = "presto"
24
+ SNOWFLAKE = "snowflake"
25
+
26
+
27
+ class GroupMode(Enum):
28
+ AUTO = "auto"
29
+ BY_INDEX = "by_index"
30
+
31
+
32
+ class ConceptSource(Enum):
33
+ MANUAL = "manual"
34
+ CTE = "cte"
35
+ SELECT = "select"
36
+ PERSIST_STATEMENT = "persist_statement"
37
+ AUTO_DERIVED = "auto_derived"
38
+
39
+
40
+ class StatementType(Enum):
41
+ QUERY = "query"
42
+
43
+
44
+ class Purpose(Enum):
45
+ CONSTANT = "const"
46
+ KEY = "key"
47
+ PROPERTY = "property"
48
+ UNIQUE_PROPERTY = "unique_property"
49
+ METRIC = "metric"
50
+ ROWSET = "rowset"
51
+ AUTO = "auto"
52
+ PARAMETER = "parameter"
53
+ UNKNOWN = "unknown"
54
+
55
+ @classmethod
56
+ def _missing_(cls, value):
57
+ if value.lower() == "constant":
58
+ return Purpose.CONSTANT
59
+ if value.lower() == "param":
60
+ return Purpose.PARAMETER
61
+ return super()._missing_(value)
62
+
63
+
64
+ class Derivation(Enum):
65
+ BASIC = "basic"
66
+ GROUP_TO = "group_to"
67
+ WINDOW = "window"
68
+ AGGREGATE = "aggregate"
69
+ FILTER = "filter"
70
+ CONSTANT = "constant"
71
+ UNNEST = "unnest"
72
+ UNION = "union"
73
+ ROOT = "root"
74
+ ROWSET = "rowset"
75
+ MULTISELECT = "multiselect"
76
+ RECURSIVE = "recursive"
77
+
78
+
79
+ class Granularity(Enum):
80
+ SINGLE_ROW = "single_row"
81
+ MULTI_ROW = "multi_row"
82
+
83
+
84
+ class PersistMode(Enum):
85
+ OVERWRITE = "overwrite"
86
+ APPEND = "append"
87
+
88
+
89
+ class PublishAction(Enum):
90
+ PUBLISH = "publish"
91
+ UNPUBLISH = "unpublish"
92
+
93
+
94
+ class AddressType(Enum):
95
+ TABLE = "table"
96
+ QUERY = "query"
97
+ PYTHON_SCRIPT = "python_script"
98
+ CSV = "csv"
99
+ TSV = "tsv"
100
+ PARQUET = "parquet"
101
+ SQL = "sql"
102
+
103
+
104
+ class Modifier(Enum):
105
+ PARTIAL = "Partial"
106
+ OPTIONAL = "Optional"
107
+ HIDDEN = "Hidden"
108
+ NULLABLE = "Nullable"
109
+
110
+ @classmethod
111
+ def _missing_(cls, value):
112
+ strval = str(value)
113
+ if strval == "~":
114
+ return Modifier.PARTIAL
115
+ elif strval == "?":
116
+ return Modifier.NULLABLE
117
+ return super()._missing_(value=strval.capitalize())
118
+
119
+ def __lt__(self, other):
120
+ order = [
121
+ Modifier.HIDDEN,
122
+ Modifier.PARTIAL,
123
+ Modifier.NULLABLE,
124
+ Modifier.OPTIONAL,
125
+ ]
126
+ return order.index(self) < order.index(other)
127
+
128
+
129
+ class JoinType(Enum):
130
+ INNER = "inner"
131
+ LEFT_OUTER = "left outer"
132
+ FULL = "full"
133
+ RIGHT_OUTER = "right outer"
134
+ CROSS = "cross"
135
+
136
+
137
+ class Ordering(Enum):
138
+ ASCENDING = "asc"
139
+ DESCENDING = "desc"
140
+ ASC_NULLS_AUTO = "asc nulls auto"
141
+ ASC_NULLS_FIRST = "asc nulls first"
142
+ ASC_NULLS_LAST = "asc nulls last"
143
+ DESC_NULLS_FIRST = "desc nulls first"
144
+ DESC_NULLS_LAST = "desc nulls last"
145
+ DESC_NULLS_AUTO = "desc nulls auto"
146
+
147
+
148
+ class WindowType(Enum):
149
+ ROW_NUMBER = "row_number"
150
+ RANK = "rank"
151
+ LAG = "lag"
152
+ LEAD = "lead"
153
+ SUM = "sum"
154
+ MAX = "max"
155
+ MIN = "min"
156
+ AVG = "avg"
157
+ COUNT = "count"
158
+ COUNT_DISTINCT = "count_distinct"
159
+
160
+
161
+ class WindowOrder(Enum):
162
+ ASCENDING = "top"
163
+ DESCENDING = "bottom"
164
+
165
+
166
+ class FunctionType(Enum):
167
+ # custom
168
+ CUSTOM = "custom"
169
+
170
+ # structural
171
+ UNNEST = "unnest"
172
+ RECURSE_EDGE = "recurse_edge"
173
+
174
+ UNION = "union"
175
+
176
+ ALIAS = "alias"
177
+
178
+ PARENTHETICAL = "parenthetical"
179
+
180
+ # Generic
181
+ CASE = "case"
182
+ CAST = "cast"
183
+ CONCAT = "concat"
184
+ CONSTANT = "constant"
185
+ TYPED_CONSTANT = "typed_constant"
186
+ COALESCE = "coalesce"
187
+ IS_NULL = "isnull"
188
+ NULLIF = "nullif"
189
+ BOOL = "bool"
190
+
191
+ # COMPLEX
192
+ INDEX_ACCESS = "index_access"
193
+ MAP_ACCESS = "map_access"
194
+ ATTR_ACCESS = "attr_access"
195
+ STRUCT = "struct"
196
+ ARRAY = "array"
197
+ DATE_LITERAL = "date_literal"
198
+ DATETIME_LITERAL = "datetime_literal"
199
+
200
+ # ARRAY
201
+ ARRAY_DISTINCT = "array_distinct"
202
+ ARRAY_SUM = "array_sum"
203
+ ARRAY_SORT = "array_sort"
204
+ ARRAY_TRANSFORM = "array_transform"
205
+ ARRAY_TO_STRING = "array_to_string"
206
+ ARRAY_FILTER = "array_filter"
207
+ GENERATE_ARRAY = "generate_array"
208
+
209
+ # MAP
210
+ MAP_KEYS = "map_keys"
211
+ MAP_VALUES = "map_values"
212
+
213
+ # TEXT AND MAYBE MORE
214
+ SPLIT = "split"
215
+ LENGTH = "len"
216
+
217
+ # Maths
218
+ DIVIDE = "divide"
219
+ MULTIPLY = "multiply"
220
+ ADD = "add"
221
+ SUBTRACT = "subtract"
222
+ MOD = "mod"
223
+ ROUND = "round"
224
+ ABS = "abs"
225
+ SQRT = "sqrt"
226
+ RANDOM = "random"
227
+ FLOOR = "floor"
228
+ CEIL = "ceil"
229
+ LOG = "log"
230
+ POWER = "power"
231
+
232
+ # Aggregates
233
+ ## group is not a real aggregate - it just means group by this + some other set of fields
234
+ ## but is here as syntax is identical
235
+ GROUP = "group"
236
+
237
+ COUNT = "count"
238
+ COUNT_DISTINCT = "count_distinct"
239
+ SUM = "sum"
240
+ MAX = "max"
241
+ MIN = "min"
242
+ AVG = "avg"
243
+ ARRAY_AGG = "array_agg"
244
+ BOOL_OR = "bool_or"
245
+ BOOL_AND = "bool_and"
246
+ ANY = "any"
247
+
248
+ # String
249
+ LIKE = "like"
250
+ ILIKE = "ilike"
251
+ LOWER = "lower"
252
+ UPPER = "upper"
253
+ SUBSTRING = "substring"
254
+ STRPOS = "strpos"
255
+ CONTAINS = "contains"
256
+ TRIM = "trim"
257
+ REPLACE = "replace"
258
+ HASH = "hash"
259
+
260
+ # STRING REGEX
261
+ REGEXP_CONTAINS = "regexp_contains"
262
+ REGEXP_EXTRACT = "regexp_extract"
263
+ REGEXP_REPLACE = "regexp_replace"
264
+
265
+ # Dates
266
+ DATE = "date"
267
+ DATETIME = "datetime"
268
+ TIMESTAMP = "timestamp"
269
+
270
+ # time
271
+ SECOND = "second"
272
+ MINUTE = "minute"
273
+ HOUR = "hour"
274
+ DAY = "day"
275
+ DAY_OF_WEEK = "day_of_week"
276
+ WEEK = "week"
277
+ MONTH = "month"
278
+ QUARTER = "quarter"
279
+ YEAR = "year"
280
+ MONTH_NAME = "month_name"
281
+ DAY_NAME = "day_name"
282
+
283
+ DATE_PART = "date_part"
284
+ DATE_TRUNCATE = "date_truncate"
285
+ DATE_ADD = "date_add"
286
+ DATE_SUB = "date_sub"
287
+ DATE_DIFF = "date_diff"
288
+ DATE_SPINE = "date_spine"
289
+
290
+ # Geography
291
+ GEO_POINT = "geo_point"
292
+ GEO_DISTANCE = "geo_distance"
293
+
294
+ # UNIX
295
+ UNIX_TO_TIMESTAMP = "unix_to_timestamp"
296
+
297
+ # CONSTANTS
298
+ CURRENT_DATE = "current_date"
299
+ CURRENT_DATETIME = "current_datetime"
300
+ CURRENT_TIMESTAMP = "current_timestamp"
301
+
302
+
303
+ class FunctionClass(Enum):
304
+ AGGREGATE_FUNCTIONS = [
305
+ FunctionType.MAX,
306
+ FunctionType.MIN,
307
+ FunctionType.SUM,
308
+ FunctionType.AVG,
309
+ FunctionType.ARRAY_AGG,
310
+ FunctionType.COUNT,
311
+ FunctionType.COUNT_DISTINCT,
312
+ FunctionType.ANY,
313
+ FunctionType.BOOL_OR,
314
+ FunctionType.BOOL_AND,
315
+ ]
316
+ SINGLE_ROW = [
317
+ FunctionType.CONSTANT,
318
+ FunctionType.CURRENT_DATE,
319
+ FunctionType.CURRENT_DATETIME,
320
+ ]
321
+
322
+ ONE_TO_MANY = [FunctionType.UNNEST, FunctionType.DATE_SPINE]
323
+
324
+ RECURSIVE = [FunctionType.RECURSE_EDGE]
325
+
326
+
327
+ class Boolean(Enum):
328
+ TRUE = "true"
329
+ FALSE = "false"
330
+
331
+ @classmethod
332
+ def _missing_(cls, value):
333
+ if value is True:
334
+ return Boolean.TRUE
335
+ elif value is False:
336
+ return Boolean.FALSE
337
+ strval = str(value)
338
+ if strval.lower() != strval:
339
+ return Boolean(strval.lower())
340
+
341
+
342
+ class BooleanOperator(Enum):
343
+ AND = "and"
344
+ OR = "or"
345
+
346
+ @classmethod
347
+ def _missing_(cls, value):
348
+ strval = str(value)
349
+ if strval.lower() != strval:
350
+ return BooleanOperator(strval.lower())
351
+ return None
352
+
353
+
354
+ class ComparisonOperator(Enum):
355
+ LT = "<"
356
+ GT = ">"
357
+ EQ = "="
358
+ IS = "is"
359
+ IS_NOT = "is not"
360
+ GTE = ">="
361
+ LTE = "<="
362
+ NE = "!="
363
+ IN = "in"
364
+ NOT_IN = "not in"
365
+ # TODO: deprecate for contains?
366
+ LIKE = "like"
367
+ ILIKE = "ilike"
368
+ CONTAINS = "contains"
369
+ ELSE = "else"
370
+
371
+ def __eq__(self, other):
372
+ if isinstance(other, str):
373
+ return self.value == other
374
+ if not isinstance(other, ComparisonOperator):
375
+ return False
376
+ return self.value == other.value
377
+
378
+ @classmethod
379
+ def _missing_(cls, value):
380
+ if not isinstance(value, list) and " " in str(value):
381
+ value = str(value).split()
382
+ if isinstance(value, list):
383
+ processed = [str(v).lower() for v in value]
384
+ if processed == ["not", "in"]:
385
+ return ComparisonOperator.NOT_IN
386
+ if processed == ["is", "not"]:
387
+ return ComparisonOperator.IS_NOT
388
+ if value == ["in"]:
389
+ return ComparisonOperator.IN
390
+ if str(value).lower() != str(value):
391
+ return ComparisonOperator(str(value).lower())
392
+ return super()._missing_(str(value).lower())
393
+
394
+
395
+ class DatePart(Enum):
396
+ MONTH = "month"
397
+ YEAR = "year"
398
+ WEEK = "week"
399
+ DAY = "day"
400
+ QUARTER = "quarter"
401
+ HOUR = "hour"
402
+ MINUTE = "minute"
403
+ SECOND = "second"
404
+ DAY_OF_WEEK = "day_of_week"
405
+
406
+ @classmethod
407
+ def _missing_(cls, value):
408
+ if isinstance(value, str) and value.lower() != value:
409
+ return DatePart(value.lower())
410
+ return super()._missing_(value)
411
+
412
+
413
+ class SourceType(Enum):
414
+ FILTER = "filter"
415
+ SELECT = "select"
416
+ ABSTRACT = "abstract"
417
+ DIRECT_SELECT = "direct_select"
418
+ GROUP = "group"
419
+ WINDOW = "window"
420
+ UNNEST = "unnest"
421
+ CONSTANT = "constant"
422
+ ROWSET = "rowset"
423
+ MERGE = "merge"
424
+ BASIC = "basic"
425
+ UNION = "union"
426
+ RECURSIVE = "recursive"
427
+
428
+
429
+ class ShowCategory(Enum):
430
+ DATASOURCES = "datasources"
431
+ CONCEPTS = "concepts"
432
+
433
+
434
+ class IOType(Enum):
435
+ CSV = "csv"
436
+ PARQUET = "parquet"
437
+
438
+ @classmethod
439
+ def _missing_(cls, value):
440
+ if isinstance(value, str) and value.lower() != value:
441
+ return IOType(value.lower())
442
+ return super()._missing_(value)
443
+
444
+
445
+ class ValidationScope(Enum):
446
+ ALL = "all"
447
+ CONCEPTS = "concepts"
448
+ DATASOURCES = "datasources"
449
+
450
+ @classmethod
451
+ def _missing_(cls, value):
452
+ if isinstance(value, str) and value.lower() != value:
453
+ return ValidationScope(value.lower())
454
+ return super()._missing_(value)