pytrilogy 0.0.3.86__tar.gz → 0.0.3.88__tar.gz
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.
Potentially problematic release.
This version of pytrilogy might be problematic. Click here for more details.
- {pytrilogy-0.0.3.86/pytrilogy.egg-info → pytrilogy-0.0.3.88}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88/pytrilogy.egg-info}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/enums.py +9 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/functions.py +31 -1
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/models/author.py +15 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/models/build.py +5 -2
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/models/core.py +20 -3
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/models/execute.py +5 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/dialect/base.py +33 -14
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/dialect/presto.py +2 -1
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/parsing/parse_engine.py +36 -6
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/parsing/trilogy.lark +13 -4
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/LICENSE.md +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/README.md +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/pyproject.toml +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/pytrilogy.egg-info/SOURCES.txt +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/setup.cfg +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/setup.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_enums.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_execute_models.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_executor.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_failure.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_functions.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_models.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_parse_engine.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_parsing.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_parsing_failures.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_query_render.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_select.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_show.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_typing.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_user_functions.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/authoring/__init__.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/constants.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/models/__init__.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/models/build_environment.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/models/datasource.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/models/environment.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/concept_strategies_v3.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/discovery_loop.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/discovery_node_factory.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/discovery_utility.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/discovery_validation.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/constant_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/group_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/recursive_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/union_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/window_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/nodes/recursive_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/nodes/union_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/statements/__init__.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/statements/author.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/statements/build.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/statements/common.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/statements/execute.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/utility.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/dialect/common.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/dialect/dataframe.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/dialect/duckdb.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/executor.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/parsing/common.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/parsing/render.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/render.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/std/__init__.py +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/std/date.preql +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/std/display.preql +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/std/geography.preql +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/std/money.preql +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/std/net.preql +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/std/ranking.preql +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/std/report.preql +0 -0
- {pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/utility.py +0 -0
|
@@ -13,6 +13,11 @@ class UnnestMode(Enum):
|
|
|
13
13
|
SNOWFLAKE = "snowflake"
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
class GroupMode(Enum):
|
|
17
|
+
AUTO = "auto"
|
|
18
|
+
BY_INDEX = "by_index"
|
|
19
|
+
|
|
20
|
+
|
|
16
21
|
class ConceptSource(Enum):
|
|
17
22
|
MANUAL = "manual"
|
|
18
23
|
CTE = "cte"
|
|
@@ -156,6 +161,10 @@ class FunctionType(Enum):
|
|
|
156
161
|
ARRAY_TRANSFORM = "array_transform"
|
|
157
162
|
ARRAY_TO_STRING = "array_to_string"
|
|
158
163
|
|
|
164
|
+
# MAP
|
|
165
|
+
MAP_KEYS = "map_keys"
|
|
166
|
+
MAP_VALUES = "map_values"
|
|
167
|
+
|
|
159
168
|
# TEXT AND MAYBE MORE
|
|
160
169
|
SPLIT = "split"
|
|
161
170
|
LENGTH = "len"
|
|
@@ -70,7 +70,7 @@ def get_coalesce_output_type(args: list[Any]) -> CONCRETE_TYPES:
|
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
def get_transform_output_type(args: list[Any]) -> CONCRETE_TYPES:
|
|
73
|
-
return arg_to_datatype(args[2])
|
|
73
|
+
return ArrayType(type=arg_to_datatype(args[2]))
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
def get_index_output_type(
|
|
@@ -178,6 +178,20 @@ def get_date_trunc_output(
|
|
|
178
178
|
raise InvalidSyntaxException(f"Date truncation not supported for {target}")
|
|
179
179
|
|
|
180
180
|
|
|
181
|
+
def get_map_key_type(arg):
|
|
182
|
+
arg_datatype = arg_to_datatype(arg)
|
|
183
|
+
if isinstance(arg_datatype, MapType):
|
|
184
|
+
return ArrayType(type=arg_datatype.key_data_type)
|
|
185
|
+
return ArrayType(type=DataType.STRING)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def get_map_value_type(arg):
|
|
189
|
+
arg_datatype = arg_to_datatype(arg)
|
|
190
|
+
if isinstance(arg_datatype, MapType):
|
|
191
|
+
return ArrayType(type=arg_datatype.value_data_type)
|
|
192
|
+
return ArrayType(type=DataType.STRING)
|
|
193
|
+
|
|
194
|
+
|
|
181
195
|
FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
182
196
|
FunctionType.ALIAS: FunctionConfig(
|
|
183
197
|
arg_count=1,
|
|
@@ -254,6 +268,22 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
|
254
268
|
output_type_function=get_index_output_type,
|
|
255
269
|
arg_count=2,
|
|
256
270
|
),
|
|
271
|
+
FunctionType.MAP_KEYS: FunctionConfig(
|
|
272
|
+
valid_inputs={
|
|
273
|
+
DataType.MAP,
|
|
274
|
+
},
|
|
275
|
+
output_purpose=Purpose.PROPERTY,
|
|
276
|
+
output_type_function=lambda args: get_map_key_type(args[0]),
|
|
277
|
+
arg_count=1,
|
|
278
|
+
),
|
|
279
|
+
FunctionType.MAP_VALUES: FunctionConfig(
|
|
280
|
+
valid_inputs={
|
|
281
|
+
DataType.MAP,
|
|
282
|
+
},
|
|
283
|
+
output_purpose=Purpose.PROPERTY,
|
|
284
|
+
output_type_function=lambda args: get_map_value_type(args[0]),
|
|
285
|
+
arg_count=1,
|
|
286
|
+
),
|
|
257
287
|
FunctionType.ARRAY_DISTINCT: FunctionConfig(
|
|
258
288
|
valid_inputs={
|
|
259
289
|
DataType.ARRAY,
|
|
@@ -164,6 +164,21 @@ class ConceptRef(Addressable, Namespaced, DataTyped, Mergeable, BaseModel):
|
|
|
164
164
|
def with_reference_replacement(self, source: str, target: Expr | ArgBinding):
|
|
165
165
|
if self.address == source:
|
|
166
166
|
return target
|
|
167
|
+
|
|
168
|
+
# a reference might be to an attribute of a struct that is bound late
|
|
169
|
+
# if the replacement is a parent in the access path; replace reference
|
|
170
|
+
# with an attribute access call
|
|
171
|
+
candidates = [f"local.{self.address}", self.address]
|
|
172
|
+
for candidate in candidates:
|
|
173
|
+
if not candidate.startswith(f"{source}."):
|
|
174
|
+
continue
|
|
175
|
+
return Function(
|
|
176
|
+
arguments=[target, self.address.rsplit(".", 1)[1]],
|
|
177
|
+
operator=FunctionType.ATTR_ACCESS,
|
|
178
|
+
arg_count=2,
|
|
179
|
+
output_datatype=arg_to_datatype(target),
|
|
180
|
+
output_purpose=Purpose.PROPERTY,
|
|
181
|
+
)
|
|
167
182
|
return self
|
|
168
183
|
|
|
169
184
|
|
|
@@ -1649,8 +1649,11 @@ class Factory:
|
|
|
1649
1649
|
full = self.local_concepts[base.address]
|
|
1650
1650
|
if isinstance(full, BuildConcept):
|
|
1651
1651
|
return full
|
|
1652
|
-
|
|
1653
|
-
|
|
1652
|
+
if base.address in self.environment.concepts:
|
|
1653
|
+
raw = self.environment.concepts[base.address]
|
|
1654
|
+
return self.build(raw)
|
|
1655
|
+
# this will error by design - TODO - more helpful message?
|
|
1656
|
+
return self.build(self.environment.concepts[base.address])
|
|
1654
1657
|
|
|
1655
1658
|
@build.register
|
|
1656
1659
|
def _(self, base: CaseWhen) -> BuildCaseWhen:
|
|
@@ -27,7 +27,7 @@ from pydantic_core import core_schema
|
|
|
27
27
|
from trilogy.constants import (
|
|
28
28
|
MagicConstants,
|
|
29
29
|
)
|
|
30
|
-
from trilogy.core.enums import Ordering
|
|
30
|
+
from trilogy.core.enums import Modifier, Ordering
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class DataTyped(ABC):
|
|
@@ -211,9 +211,19 @@ class MapType(BaseModel):
|
|
|
211
211
|
return self.key_type
|
|
212
212
|
|
|
213
213
|
|
|
214
|
+
class StructComponent(BaseModel):
|
|
215
|
+
name: str
|
|
216
|
+
type: TYPEDEF_TYPES
|
|
217
|
+
modifiers: list[Modifier] = []
|
|
218
|
+
|
|
219
|
+
@field_validator("type", mode="plain")
|
|
220
|
+
def validate_Type(cls, v):
|
|
221
|
+
return v
|
|
222
|
+
|
|
223
|
+
|
|
214
224
|
class StructType(BaseModel):
|
|
215
|
-
fields: Sequence[TYPEDEF_TYPES]
|
|
216
|
-
fields_map: Dict[str, DataTyped | int | float | str]
|
|
225
|
+
fields: Sequence[StructComponent | TYPEDEF_TYPES]
|
|
226
|
+
fields_map: Dict[str, DataTyped | int | float | str | StructComponent]
|
|
217
227
|
|
|
218
228
|
@field_validator("fields", mode="plain")
|
|
219
229
|
def validate_type(cls, v):
|
|
@@ -234,6 +244,9 @@ class StructType(BaseModel):
|
|
|
234
244
|
def value(self):
|
|
235
245
|
return self.data_type.value
|
|
236
246
|
|
|
247
|
+
def __hash__(self):
|
|
248
|
+
return hash(str(self))
|
|
249
|
+
|
|
237
250
|
|
|
238
251
|
class ListWrapper(Generic[VT], UserList):
|
|
239
252
|
"""Used to distinguish parsed list objects from other lists"""
|
|
@@ -401,6 +414,8 @@ def arg_to_datatype(arg) -> CONCRETE_TYPES:
|
|
|
401
414
|
return DataType.STRING
|
|
402
415
|
elif isinstance(arg, float):
|
|
403
416
|
return DataType.FLOAT
|
|
417
|
+
elif isinstance(arg, DataType):
|
|
418
|
+
return arg
|
|
404
419
|
elif isinstance(arg, NumericType):
|
|
405
420
|
return arg
|
|
406
421
|
elif isinstance(arg, TraitDataType):
|
|
@@ -420,6 +435,8 @@ def arg_to_datatype(arg) -> CONCRETE_TYPES:
|
|
|
420
435
|
return DataType.DATETIME
|
|
421
436
|
elif isinstance(arg, date):
|
|
422
437
|
return DataType.DATE
|
|
438
|
+
elif isinstance(arg, StructComponent):
|
|
439
|
+
return arg_to_datatype(arg.type)
|
|
423
440
|
else:
|
|
424
441
|
raise ValueError(
|
|
425
442
|
f"Cannot parse arg datatype for arg of raw type {type(arg)} value {arg}"
|
|
@@ -1076,6 +1076,11 @@ class UnionCTE(BaseModel):
|
|
|
1076
1076
|
def group_to_grain(self) -> bool:
|
|
1077
1077
|
return False
|
|
1078
1078
|
|
|
1079
|
+
@property
|
|
1080
|
+
def group_concepts(self) -> List[BuildConcept]:
|
|
1081
|
+
# unions should always be on unique sets
|
|
1082
|
+
return []
|
|
1083
|
+
|
|
1079
1084
|
def __add__(self, other):
|
|
1080
1085
|
if not isinstance(other, UnionCTE) or not other.name == self.name:
|
|
1081
1086
|
raise SyntaxError("Cannot merge union CTEs")
|
|
@@ -15,6 +15,7 @@ from trilogy.core.enums import (
|
|
|
15
15
|
ComparisonOperator,
|
|
16
16
|
DatePart,
|
|
17
17
|
FunctionType,
|
|
18
|
+
GroupMode,
|
|
18
19
|
Ordering,
|
|
19
20
|
ShowCategory,
|
|
20
21
|
UnnestMode,
|
|
@@ -186,6 +187,9 @@ FUNCTION_MAP = {
|
|
|
186
187
|
FunctionType.ARRAY: lambda x: f"[{', '.join(x)}]",
|
|
187
188
|
FunctionType.DATE_LITERAL: lambda x: f"date '{x}'",
|
|
188
189
|
FunctionType.DATETIME_LITERAL: lambda x: f"datetime '{x}'",
|
|
190
|
+
# MAP
|
|
191
|
+
FunctionType.MAP_KEYS: lambda x: f"map_keys({x[0]})",
|
|
192
|
+
FunctionType.MAP_VALUES: lambda x: f"map_values({x[0]})",
|
|
189
193
|
# ARRAY
|
|
190
194
|
FunctionType.ARRAY_SUM: lambda x: f"array_sum({x[0]})",
|
|
191
195
|
FunctionType.ARRAY_DISTINCT: lambda x: f"array_distinct({x[0]})",
|
|
@@ -338,6 +342,7 @@ class BaseDialect:
|
|
|
338
342
|
DATATYPE_MAP = DATATYPE_MAP
|
|
339
343
|
COMPLEX_DATATYPE_MAP = COMPLEX_DATATYPE_MAP
|
|
340
344
|
UNNEST_MODE = UnnestMode.CROSS_APPLY
|
|
345
|
+
GROUP_MODE = GroupMode.AUTO
|
|
341
346
|
|
|
342
347
|
def __init__(self, rendering: Rendering | None = None):
|
|
343
348
|
self.rendering = rendering or CONFIG.rendering
|
|
@@ -775,6 +780,33 @@ class BaseDialect:
|
|
|
775
780
|
else:
|
|
776
781
|
raise ValueError(f"Unable to render type {type(e)} {e}")
|
|
777
782
|
|
|
783
|
+
def render_cte_group_by(
|
|
784
|
+
self, cte: CTE | UnionCTE, select_columns
|
|
785
|
+
) -> Optional[list[str]]:
|
|
786
|
+
|
|
787
|
+
if not cte.group_to_grain:
|
|
788
|
+
return None
|
|
789
|
+
base = set(
|
|
790
|
+
[self.render_concept_sql(c, cte, alias=False) for c in cte.group_concepts]
|
|
791
|
+
)
|
|
792
|
+
if self.GROUP_MODE == GroupMode.AUTO:
|
|
793
|
+
return sorted(list(base))
|
|
794
|
+
|
|
795
|
+
else:
|
|
796
|
+
# find the index of each column in the select columns
|
|
797
|
+
final = []
|
|
798
|
+
found = []
|
|
799
|
+
for idx, c in enumerate(select_columns):
|
|
800
|
+
pre_alias = c.split(" as ")[0]
|
|
801
|
+
if pre_alias in base:
|
|
802
|
+
final.append(str(idx + 1))
|
|
803
|
+
found.append(pre_alias)
|
|
804
|
+
if not all(c in found for c in base):
|
|
805
|
+
raise ValueError(
|
|
806
|
+
f"Group by columns {base} not found in select columns {select_columns}"
|
|
807
|
+
)
|
|
808
|
+
return final
|
|
809
|
+
|
|
778
810
|
def render_cte(self, cte: CTE | UnionCTE, auto_sort: bool = True) -> CompiledCTE:
|
|
779
811
|
if isinstance(cte, UnionCTE):
|
|
780
812
|
base_statement = f"\n{cte.operator}\n".join(
|
|
@@ -926,20 +958,7 @@ class BaseDialect:
|
|
|
926
958
|
if cte.order_by
|
|
927
959
|
else None
|
|
928
960
|
),
|
|
929
|
-
group_by=(
|
|
930
|
-
sorted(
|
|
931
|
-
list(
|
|
932
|
-
set(
|
|
933
|
-
[
|
|
934
|
-
self.render_concept_sql(c, cte, alias=False)
|
|
935
|
-
for c in cte.group_concepts
|
|
936
|
-
]
|
|
937
|
-
)
|
|
938
|
-
)
|
|
939
|
-
)
|
|
940
|
-
if cte.group_to_grain
|
|
941
|
-
else None
|
|
942
|
-
),
|
|
961
|
+
group_by=self.render_cte_group_by(cte, select_columns),
|
|
943
962
|
),
|
|
944
963
|
)
|
|
945
964
|
|
|
@@ -2,7 +2,7 @@ from typing import Any, Callable, Mapping
|
|
|
2
2
|
|
|
3
3
|
from jinja2 import Template
|
|
4
4
|
|
|
5
|
-
from trilogy.core.enums import FunctionType, UnnestMode, WindowType
|
|
5
|
+
from trilogy.core.enums import FunctionType, GroupMode, UnnestMode, WindowType
|
|
6
6
|
from trilogy.core.models.core import DataType
|
|
7
7
|
from trilogy.dialect.base import BaseDialect
|
|
8
8
|
|
|
@@ -94,6 +94,7 @@ class PrestoDialect(BaseDialect):
|
|
|
94
94
|
DataType.STRING: "VARCHAR",
|
|
95
95
|
}
|
|
96
96
|
UNNEST_MODE = UnnestMode.PRESTO
|
|
97
|
+
GROUP_MODE = GroupMode.BY_INDEX
|
|
97
98
|
|
|
98
99
|
|
|
99
100
|
class TrinoDialect(PrestoDialect):
|
|
@@ -89,6 +89,7 @@ from trilogy.core.models.core import (
|
|
|
89
89
|
MapType,
|
|
90
90
|
MapWrapper,
|
|
91
91
|
NumericType,
|
|
92
|
+
StructComponent,
|
|
92
93
|
StructType,
|
|
93
94
|
TraitDataType,
|
|
94
95
|
TupleWrapper,
|
|
@@ -443,20 +444,39 @@ class ParseToObjects(Transformer):
|
|
|
443
444
|
def MINUS(self, args) -> str:
|
|
444
445
|
return "-"
|
|
445
446
|
|
|
447
|
+
@v_args(meta=True)
|
|
448
|
+
def struct_component(self, meta: Meta, args) -> StructComponent:
|
|
449
|
+
modifiers = []
|
|
450
|
+
for arg in args:
|
|
451
|
+
if isinstance(arg, Modifier):
|
|
452
|
+
modifiers.append(arg)
|
|
453
|
+
return StructComponent(name=args[0], type=args[1], modifiers=modifiers)
|
|
454
|
+
|
|
446
455
|
@v_args(meta=True)
|
|
447
456
|
def struct_type(self, meta: Meta, args) -> StructType:
|
|
448
457
|
final: list[
|
|
449
|
-
DataType
|
|
458
|
+
DataType
|
|
459
|
+
| MapType
|
|
460
|
+
| ArrayType
|
|
461
|
+
| NumericType
|
|
462
|
+
| StructType
|
|
463
|
+
| StructComponent
|
|
464
|
+
| Concept
|
|
450
465
|
] = []
|
|
451
466
|
for arg in args:
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
467
|
+
if isinstance(arg, StructComponent):
|
|
468
|
+
final.append(arg)
|
|
469
|
+
else:
|
|
470
|
+
new = self.environment.concepts.__getitem__( # type: ignore
|
|
471
|
+
key=arg, line_no=meta.line
|
|
472
|
+
)
|
|
473
|
+
final.append(new)
|
|
456
474
|
|
|
457
475
|
return StructType(
|
|
458
476
|
fields=final,
|
|
459
|
-
fields_map={
|
|
477
|
+
fields_map={
|
|
478
|
+
x.name: x for x in final if isinstance(x, (Concept, StructComponent))
|
|
479
|
+
},
|
|
460
480
|
)
|
|
461
481
|
|
|
462
482
|
def list_type(self, args) -> ArrayType:
|
|
@@ -2026,6 +2046,16 @@ class ParseToObjects(Transformer):
|
|
|
2026
2046
|
def fbool(self, meta, args):
|
|
2027
2047
|
return self.function_factory.create_function(args, FunctionType.BOOL, meta)
|
|
2028
2048
|
|
|
2049
|
+
@v_args(meta=True)
|
|
2050
|
+
def fmap_keys(self, meta, args):
|
|
2051
|
+
return self.function_factory.create_function(args, FunctionType.MAP_KEYS, meta)
|
|
2052
|
+
|
|
2053
|
+
@v_args(meta=True)
|
|
2054
|
+
def fmap_values(self, meta, args):
|
|
2055
|
+
return self.function_factory.create_function(
|
|
2056
|
+
args, FunctionType.MAP_VALUES, meta
|
|
2057
|
+
)
|
|
2058
|
+
|
|
2029
2059
|
@v_args(meta=True)
|
|
2030
2060
|
def farray_sum(self, meta, args):
|
|
2031
2061
|
return self.function_factory.create_function(args, FunctionType.ARRAY_SUM, meta)
|
|
@@ -181,7 +181,8 @@
|
|
|
181
181
|
//indexing into an expression is a function
|
|
182
182
|
index_access: atom "[" int_lit "]"
|
|
183
183
|
map_key_access: atom "[" string_lit "]"
|
|
184
|
-
|
|
184
|
+
_ATTR_ACCESS.1 : "getattr("i
|
|
185
|
+
attr_access: ( _ATTR_ACCESS atom "," string_lit ")") | (atom "." string_lit)
|
|
185
186
|
|
|
186
187
|
?expr: comparison_root | between_root
|
|
187
188
|
|
|
@@ -309,6 +310,14 @@
|
|
|
309
310
|
farray_transform: _ARRAY_TRANSFORM expr "," transform_lambda ")"
|
|
310
311
|
|
|
311
312
|
_array_functions: farray_sum | farray_distinct | farray_sort | farray_transform | farray_to_string
|
|
313
|
+
|
|
314
|
+
//map_functions
|
|
315
|
+
_MAP_KEYS.1: "map_keys("i
|
|
316
|
+
fmap_keys: _MAP_KEYS expr ")"
|
|
317
|
+
_MAP_VALUES.1: "map_values("i
|
|
318
|
+
fmap_values: _MAP_VALUES expr ")"
|
|
319
|
+
|
|
320
|
+
_map_functions: fmap_keys | fmap_values
|
|
312
321
|
|
|
313
322
|
// special aggregate
|
|
314
323
|
_GROUP.1: "group("i
|
|
@@ -380,7 +389,7 @@
|
|
|
380
389
|
|
|
381
390
|
_date_functions: fdate | fdate_add | fdate_sub | fdate_diff | fdatetime | ftimestamp | fsecond | fminute | fhour | fday | fday_of_week | fweek | fmonth | fquarter | fyear | fdate_part | fdate_trunc
|
|
382
391
|
|
|
383
|
-
_static_functions: _string_functions | _math_functions | _array_functions
|
|
392
|
+
_static_functions: _string_functions | _math_functions | _array_functions | _map_functions
|
|
384
393
|
|
|
385
394
|
custom_function: "@" IDENTIFIER "(" (expr ",")* expr ")"
|
|
386
395
|
|
|
@@ -424,8 +433,8 @@
|
|
|
424
433
|
MODIFIER: /OPTIONAL|PARTIAL|NULLABLE/i
|
|
425
434
|
|
|
426
435
|
SHORTHAND_MODIFIER: /~|\?/
|
|
427
|
-
|
|
428
|
-
struct_type: "struct"i "<" ((
|
|
436
|
+
struct_component: IDENTIFIER ":" data_type concept_nullable_modifier? metadata?
|
|
437
|
+
struct_type: "struct"i "<" ((struct_component | IDENTIFIER) ",")* (struct_component | IDENTIFIER) ","? ">"
|
|
429
438
|
|
|
430
439
|
list_type: ("list"i | "array"i) "<" (data_type | IDENTIFIER) ">"
|
|
431
440
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/__init__.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/basic_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/constant_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/filter_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/group_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/group_to_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/node_merge_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/recursive_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/rowset_node.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/select_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/synonym_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/union_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/unnest_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.86 → pytrilogy-0.0.3.88}/trilogy/core/processing/node_generators/window_node.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|