pytrilogy 0.0.3.73__tar.gz → 0.0.3.75__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.73/pytrilogy.egg-info → pytrilogy-0.0.3.75}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75/pytrilogy.egg-info}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_functions.py +3 -3
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_parsing.py +20 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/authoring/__init__.py +2 -2
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/enums.py +8 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/functions.py +56 -9
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/models/author.py +20 -11
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/models/build.py +14 -5
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/models/core.py +13 -11
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/utility.py +2 -2
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/dialect/base.py +20 -6
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/dialect/duckdb.py +18 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/parsing/parse_engine.py +62 -9
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/parsing/render.py +2 -2
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/parsing/trilogy.lark +19 -4
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/LICENSE.md +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/README.md +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/pyproject.toml +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/pytrilogy.egg-info/SOURCES.txt +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/setup.cfg +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/setup.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_enums.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_execute_models.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_executor.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_failure.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_models.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_parse_engine.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_parsing_failures.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_query_render.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_select.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_show.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_typing.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_user_functions.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/constants.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/models/__init__.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/models/build_environment.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/models/datasource.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/models/environment.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/models/execute.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/concept_strategies_v3.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/discovery_loop.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/discovery_node_factory.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/discovery_utility.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/discovery_validation.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/group_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/recursive_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/union_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/node_generators/window_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/nodes/recursive_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/nodes/union_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/statements/__init__.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/statements/author.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/statements/build.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/statements/common.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/statements/execute.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/core/utility.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/dialect/common.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/dialect/dataframe.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/executor.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/parsing/common.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/render.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/std/__init__.py +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/std/date.preql +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/std/display.preql +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/std/geography.preql +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/std/money.preql +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/std/net.preql +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/std/ranking.preql +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/std/report.preql +0 -0
- {pytrilogy-0.0.3.73 → pytrilogy-0.0.3.75}/trilogy/utility.py +0 -0
|
@@ -8,7 +8,7 @@ from trilogy import Dialects
|
|
|
8
8
|
from trilogy.constants import logger
|
|
9
9
|
from trilogy.core.enums import Derivation, Purpose
|
|
10
10
|
from trilogy.core.exceptions import InvalidSyntaxException
|
|
11
|
-
from trilogy.core.models.core import
|
|
11
|
+
from trilogy.core.models.core import ArrayType, DataType
|
|
12
12
|
from trilogy.core.models.environment import Environment
|
|
13
13
|
from trilogy.core.query_processor import process_query
|
|
14
14
|
from trilogy.core.statements.author import SelectStatement
|
|
@@ -31,7 +31,7 @@ TEST_DIALECTS = [
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def test_typing():
|
|
34
|
-
x =
|
|
34
|
+
x = ArrayType(type=DataType.INTEGER)
|
|
35
35
|
|
|
36
36
|
assert x in set([x])
|
|
37
37
|
|
|
@@ -393,7 +393,7 @@ def test_unnest(test_environment):
|
|
|
393
393
|
x
|
|
394
394
|
;"""
|
|
395
395
|
env, parsed = parse(declarations, environment=test_environment)
|
|
396
|
-
assert env.concepts["int_list"].datatype ==
|
|
396
|
+
assert env.concepts["int_list"].datatype == ArrayType(type=DataType.INTEGER)
|
|
397
397
|
assert env.concepts["x"].datatype == DataType.INTEGER
|
|
398
398
|
|
|
399
399
|
|
|
@@ -524,6 +524,26 @@ address abcdef
|
|
|
524
524
|
;
|
|
525
525
|
|
|
526
526
|
|
|
527
|
+
select x;
|
|
528
|
+
"""
|
|
529
|
+
env, parsed = parse_text(text)
|
|
530
|
+
|
|
531
|
+
results = Dialects.DUCK_DB.default_executor().generate_sql(text)[0]
|
|
532
|
+
|
|
533
|
+
assert '"abcdef" as "test"' in results, results
|
|
534
|
+
|
|
535
|
+
text = """
|
|
536
|
+
key x int;
|
|
537
|
+
key y int;
|
|
538
|
+
|
|
539
|
+
datasource test (
|
|
540
|
+
x,
|
|
541
|
+
y)
|
|
542
|
+
grain(x)
|
|
543
|
+
address abcdef
|
|
544
|
+
;
|
|
545
|
+
|
|
546
|
+
|
|
527
547
|
select x;
|
|
528
548
|
"""
|
|
529
549
|
env, parsed = parse_text(text)
|
|
@@ -37,8 +37,8 @@ from trilogy.core.models.author import (
|
|
|
37
37
|
WindowType,
|
|
38
38
|
)
|
|
39
39
|
from trilogy.core.models.core import (
|
|
40
|
+
ArrayType,
|
|
40
41
|
DataType,
|
|
41
|
-
ListType,
|
|
42
42
|
ListWrapper,
|
|
43
43
|
MapType,
|
|
44
44
|
StructType,
|
|
@@ -77,7 +77,7 @@ __all__ = [
|
|
|
77
77
|
"WindowItemOver",
|
|
78
78
|
"DataType",
|
|
79
79
|
"StructType",
|
|
80
|
-
"
|
|
80
|
+
"ArrayType",
|
|
81
81
|
"Grain",
|
|
82
82
|
"RowsetDerivationStatement",
|
|
83
83
|
"MapType",
|
|
@@ -149,6 +149,12 @@ class FunctionType(Enum):
|
|
|
149
149
|
DATE_LITERAL = "date_literal"
|
|
150
150
|
DATETIME_LITERAL = "datetime_literal"
|
|
151
151
|
|
|
152
|
+
# ARRAY
|
|
153
|
+
ARRAY_DISTINCT = "array_distinct"
|
|
154
|
+
ARRAY_SUM = "array_sum"
|
|
155
|
+
ARRAY_SORT = "array_sort"
|
|
156
|
+
ARRAY_TRANSFORM = "array_transform"
|
|
157
|
+
|
|
152
158
|
# TEXT AND MAYBE MORE
|
|
153
159
|
SPLIT = "split"
|
|
154
160
|
LENGTH = "len"
|
|
@@ -177,6 +183,7 @@ class FunctionType(Enum):
|
|
|
177
183
|
MAX = "max"
|
|
178
184
|
MIN = "min"
|
|
179
185
|
AVG = "avg"
|
|
186
|
+
ARRAY_AGG = "array_agg"
|
|
180
187
|
|
|
181
188
|
# String
|
|
182
189
|
LIKE = "like"
|
|
@@ -228,6 +235,7 @@ class FunctionClass(Enum):
|
|
|
228
235
|
FunctionType.MIN,
|
|
229
236
|
FunctionType.SUM,
|
|
230
237
|
FunctionType.AVG,
|
|
238
|
+
FunctionType.ARRAY_AGG,
|
|
231
239
|
FunctionType.COUNT,
|
|
232
240
|
FunctionType.COUNT_DISTINCT,
|
|
233
241
|
]
|
|
@@ -25,8 +25,8 @@ from trilogy.core.models.author import (
|
|
|
25
25
|
)
|
|
26
26
|
from trilogy.core.models.core import (
|
|
27
27
|
CONCRETE_TYPES,
|
|
28
|
+
ArrayType,
|
|
28
29
|
DataType,
|
|
29
|
-
ListType,
|
|
30
30
|
MapType,
|
|
31
31
|
NumericType,
|
|
32
32
|
StructType,
|
|
@@ -45,14 +45,14 @@ class FunctionConfig:
|
|
|
45
45
|
valid_inputs: set[DataType] | list[set[DataType]] | None = None
|
|
46
46
|
output_purpose: Purpose | None = None
|
|
47
47
|
output_type: (
|
|
48
|
-
DataType |
|
|
48
|
+
DataType | ArrayType | MapType | StructType | NumericType | TraitDataType | None
|
|
49
49
|
) = None
|
|
50
50
|
output_type_function: Optional[Callable] = None
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
def get_unnest_output_type(args: list[Any]) -> CONCRETE_TYPES:
|
|
54
54
|
output = arg_to_datatype(args[0])
|
|
55
|
-
if isinstance(output, (
|
|
55
|
+
if isinstance(output, (ArrayType, MapType)):
|
|
56
56
|
output = output.value_data_type
|
|
57
57
|
else:
|
|
58
58
|
output = DataType.STRING
|
|
@@ -69,12 +69,16 @@ def get_coalesce_output_type(args: list[Any]) -> CONCRETE_TYPES:
|
|
|
69
69
|
return processed[0]
|
|
70
70
|
|
|
71
71
|
|
|
72
|
+
def get_transform_output_type(args: list[Any]) -> CONCRETE_TYPES:
|
|
73
|
+
return arg_to_datatype(args[2])
|
|
74
|
+
|
|
75
|
+
|
|
72
76
|
def get_index_output_type(
|
|
73
77
|
args: list[Any],
|
|
74
78
|
) -> CONCRETE_TYPES:
|
|
75
79
|
arg = args[0]
|
|
76
80
|
datatype = arg_to_datatype(arg)
|
|
77
|
-
if isinstance(datatype,
|
|
81
|
+
if isinstance(datatype, ArrayType):
|
|
78
82
|
return datatype.value_data_type
|
|
79
83
|
elif isinstance(datatype, MapType):
|
|
80
84
|
return datatype.value_data_type
|
|
@@ -184,7 +188,6 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
|
184
188
|
FunctionType.UNNEST: FunctionConfig(
|
|
185
189
|
valid_inputs={
|
|
186
190
|
DataType.ARRAY,
|
|
187
|
-
DataType.LIST,
|
|
188
191
|
},
|
|
189
192
|
output_purpose=Purpose.KEY,
|
|
190
193
|
output_type_function=get_unnest_output_type,
|
|
@@ -235,13 +238,12 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
|
235
238
|
FunctionType.SPLIT: FunctionConfig(
|
|
236
239
|
valid_inputs={DataType.STRING},
|
|
237
240
|
output_purpose=Purpose.PROPERTY,
|
|
238
|
-
output_type=
|
|
241
|
+
output_type=ArrayType(type=DataType.STRING),
|
|
239
242
|
arg_count=2,
|
|
240
243
|
),
|
|
241
244
|
FunctionType.INDEX_ACCESS: FunctionConfig(
|
|
242
245
|
valid_inputs=[
|
|
243
246
|
{
|
|
244
|
-
DataType.LIST,
|
|
245
247
|
DataType.ARRAY,
|
|
246
248
|
},
|
|
247
249
|
{
|
|
@@ -252,6 +254,43 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
|
252
254
|
output_type_function=get_index_output_type,
|
|
253
255
|
arg_count=2,
|
|
254
256
|
),
|
|
257
|
+
FunctionType.ARRAY_DISTINCT: FunctionConfig(
|
|
258
|
+
valid_inputs={
|
|
259
|
+
DataType.ARRAY,
|
|
260
|
+
},
|
|
261
|
+
output_purpose=Purpose.PROPERTY,
|
|
262
|
+
output_type_function=lambda args: get_output_type_at_index(args, 0),
|
|
263
|
+
arg_count=1,
|
|
264
|
+
),
|
|
265
|
+
FunctionType.ARRAY_SORT: FunctionConfig(
|
|
266
|
+
valid_inputs=[
|
|
267
|
+
{DataType.ARRAY},
|
|
268
|
+
{DataType.STRING},
|
|
269
|
+
],
|
|
270
|
+
output_purpose=Purpose.PROPERTY,
|
|
271
|
+
output_type_function=lambda args: get_output_type_at_index(args, 0),
|
|
272
|
+
arg_count=2,
|
|
273
|
+
),
|
|
274
|
+
FunctionType.ARRAY_TRANSFORM: FunctionConfig(
|
|
275
|
+
valid_inputs=[
|
|
276
|
+
{
|
|
277
|
+
DataType.ARRAY,
|
|
278
|
+
},
|
|
279
|
+
{*DataType},
|
|
280
|
+
{*DataType},
|
|
281
|
+
],
|
|
282
|
+
output_purpose=Purpose.PROPERTY,
|
|
283
|
+
output_type_function=get_transform_output_type,
|
|
284
|
+
arg_count=3,
|
|
285
|
+
),
|
|
286
|
+
FunctionType.ARRAY_SUM: FunctionConfig(
|
|
287
|
+
valid_inputs={
|
|
288
|
+
DataType.ARRAY,
|
|
289
|
+
},
|
|
290
|
+
output_purpose=Purpose.PROPERTY,
|
|
291
|
+
output_type_function=get_index_output_type,
|
|
292
|
+
arg_count=1,
|
|
293
|
+
),
|
|
255
294
|
FunctionType.MAP_ACCESS: FunctionConfig(
|
|
256
295
|
valid_inputs=[
|
|
257
296
|
{
|
|
@@ -722,7 +761,7 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
|
722
761
|
FunctionType.ARRAY: FunctionConfig(
|
|
723
762
|
output_purpose=Purpose.PROPERTY,
|
|
724
763
|
arg_count=InfiniteFunctionArgs,
|
|
725
|
-
output_type=
|
|
764
|
+
output_type=ArrayType(type=DataType.STRING),
|
|
726
765
|
),
|
|
727
766
|
FunctionType.LENGTH: FunctionConfig(
|
|
728
767
|
valid_inputs={DataType.STRING, DataType.ARRAY, DataType.MAP},
|
|
@@ -740,6 +779,14 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
|
740
779
|
output_purpose=Purpose.METRIC,
|
|
741
780
|
arg_count=1,
|
|
742
781
|
),
|
|
782
|
+
FunctionType.ARRAY_AGG: FunctionConfig(
|
|
783
|
+
valid_inputs={*DataType},
|
|
784
|
+
output_purpose=Purpose.METRIC,
|
|
785
|
+
output_type_function=lambda args: ArrayType(
|
|
786
|
+
type=merge_datatypes([arg_to_datatype(x) for x in args])
|
|
787
|
+
),
|
|
788
|
+
arg_count=1,
|
|
789
|
+
),
|
|
743
790
|
FunctionType.AVG: FunctionConfig(
|
|
744
791
|
valid_inputs={
|
|
745
792
|
DataType.INTEGER,
|
|
@@ -837,7 +884,7 @@ def create_function_derived_concept(
|
|
|
837
884
|
arguments: list[Concept],
|
|
838
885
|
environment: Environment,
|
|
839
886
|
output_type: Optional[
|
|
840
|
-
DataType |
|
|
887
|
+
DataType | ArrayType | StructType | MapType | NumericType | TraitDataType
|
|
841
888
|
] = None,
|
|
842
889
|
output_purpose: Optional[Purpose] = None,
|
|
843
890
|
) -> Concept:
|
|
@@ -48,9 +48,9 @@ from trilogy.core.enums import (
|
|
|
48
48
|
)
|
|
49
49
|
from trilogy.core.models.core import (
|
|
50
50
|
Addressable,
|
|
51
|
+
ArrayType,
|
|
51
52
|
DataType,
|
|
52
53
|
DataTyped,
|
|
53
|
-
ListType,
|
|
54
54
|
ListWrapper,
|
|
55
55
|
MapType,
|
|
56
56
|
MapWrapper,
|
|
@@ -104,7 +104,7 @@ class HasUUID(ABC):
|
|
|
104
104
|
class ConceptRef(Addressable, Namespaced, DataTyped, Mergeable, BaseModel):
|
|
105
105
|
address: str
|
|
106
106
|
datatype: (
|
|
107
|
-
DataType | TraitDataType |
|
|
107
|
+
DataType | TraitDataType | ArrayType | StructType | MapType | NumericType
|
|
108
108
|
) = DataType.UNKNOWN
|
|
109
109
|
metadata: Optional["Metadata"] = None
|
|
110
110
|
|
|
@@ -646,7 +646,7 @@ class Comparison(ConceptArgs, Mergeable, DataTyped, Namespaced, BaseModel):
|
|
|
646
646
|
)
|
|
647
647
|
elif self.operator in (ComparisonOperator.IN, ComparisonOperator.NOT_IN):
|
|
648
648
|
right_type = arg_to_datatype(self.right)
|
|
649
|
-
if isinstance(right_type,
|
|
649
|
+
if isinstance(right_type, ArrayType) and not is_compatible_datatype(
|
|
650
650
|
arg_to_datatype(self.left), right_type.value_data_type
|
|
651
651
|
):
|
|
652
652
|
raise SyntaxError(
|
|
@@ -802,7 +802,7 @@ class Concept(Addressable, DataTyped, ConceptArgs, Mergeable, Namespaced, BaseMo
|
|
|
802
802
|
extra="forbid",
|
|
803
803
|
)
|
|
804
804
|
name: str
|
|
805
|
-
datatype: DataType | TraitDataType |
|
|
805
|
+
datatype: DataType | TraitDataType | ArrayType | StructType | MapType | NumericType
|
|
806
806
|
purpose: Purpose
|
|
807
807
|
derivation: Derivation = Derivation.ROOT
|
|
808
808
|
granularity: Granularity = Granularity.MULTI_ROW
|
|
@@ -1277,7 +1277,7 @@ class UndefinedConceptFull(Concept, Mergeable, Namespaced):
|
|
|
1277
1277
|
name: str
|
|
1278
1278
|
line_no: int | None = None
|
|
1279
1279
|
datatype: (
|
|
1280
|
-
DataType | TraitDataType |
|
|
1280
|
+
DataType | TraitDataType | ArrayType | StructType | MapType | NumericType
|
|
1281
1281
|
) = DataType.UNKNOWN
|
|
1282
1282
|
purpose: Purpose = Purpose.UNKNOWN
|
|
1283
1283
|
|
|
@@ -1437,10 +1437,10 @@ class WindowItem(DataTyped, ConceptArgs, Mergeable, Namespaced, BaseModel):
|
|
|
1437
1437
|
|
|
1438
1438
|
|
|
1439
1439
|
def get_basic_type(
|
|
1440
|
-
type: DataType |
|
|
1440
|
+
type: DataType | ArrayType | StructType | MapType | NumericType | TraitDataType,
|
|
1441
1441
|
) -> DataType:
|
|
1442
|
-
if isinstance(type,
|
|
1443
|
-
return DataType.
|
|
1442
|
+
if isinstance(type, ArrayType):
|
|
1443
|
+
return DataType.ARRAY
|
|
1444
1444
|
if isinstance(type, StructType):
|
|
1445
1445
|
return DataType.STRUCT
|
|
1446
1446
|
if isinstance(type, MapType):
|
|
@@ -1609,7 +1609,7 @@ class Function(DataTyped, ConceptArgs, Mergeable, Namespaced, BaseModel):
|
|
|
1609
1609
|
operator: FunctionType
|
|
1610
1610
|
arg_count: int = Field(default=1)
|
|
1611
1611
|
output_datatype: (
|
|
1612
|
-
DataType |
|
|
1612
|
+
DataType | ArrayType | StructType | MapType | NumericType | TraitDataType
|
|
1613
1613
|
)
|
|
1614
1614
|
output_purpose: Purpose
|
|
1615
1615
|
valid_inputs: Optional[
|
|
@@ -2358,9 +2358,10 @@ class Comment(BaseModel):
|
|
|
2358
2358
|
text: str
|
|
2359
2359
|
|
|
2360
2360
|
|
|
2361
|
-
class ArgBinding(Namespaced, BaseModel):
|
|
2361
|
+
class ArgBinding(Namespaced, DataTyped, BaseModel):
|
|
2362
2362
|
name: str
|
|
2363
2363
|
default: Expr | None = None
|
|
2364
|
+
datatype: DataType = DataType.UNKNOWN
|
|
2364
2365
|
|
|
2365
2366
|
def with_namespace(self, namespace):
|
|
2366
2367
|
return ArgBinding(
|
|
@@ -2372,6 +2373,12 @@ class ArgBinding(Namespaced, BaseModel):
|
|
|
2372
2373
|
),
|
|
2373
2374
|
)
|
|
2374
2375
|
|
|
2376
|
+
@property
|
|
2377
|
+
def output_datatype(self):
|
|
2378
|
+
if self.default is not None:
|
|
2379
|
+
return arg_to_datatype(self.default)
|
|
2380
|
+
return self.datatype
|
|
2381
|
+
|
|
2375
2382
|
|
|
2376
2383
|
class CustomType(BaseModel):
|
|
2377
2384
|
name: str
|
|
@@ -2426,7 +2433,7 @@ FuncArgs = (
|
|
|
2426
2433
|
| MapWrapper[Any, Any]
|
|
2427
2434
|
| TraitDataType
|
|
2428
2435
|
| DataType
|
|
2429
|
-
|
|
|
2436
|
+
| ArrayType
|
|
2430
2437
|
| MapType
|
|
2431
2438
|
| NumericType
|
|
2432
2439
|
| ListWrapper[Any]
|
|
@@ -2434,4 +2441,6 @@ FuncArgs = (
|
|
|
2434
2441
|
| Comparison
|
|
2435
2442
|
| Conditional
|
|
2436
2443
|
| MagicConstants
|
|
2444
|
+
| ArgBinding
|
|
2445
|
+
| Ordering
|
|
2437
2446
|
)
|
|
@@ -45,6 +45,7 @@ from trilogy.core.models.author import (
|
|
|
45
45
|
AggregateWrapper,
|
|
46
46
|
AlignClause,
|
|
47
47
|
AlignItem,
|
|
48
|
+
ArgBinding,
|
|
48
49
|
CaseElse,
|
|
49
50
|
CaseWhen,
|
|
50
51
|
Comparison,
|
|
@@ -72,9 +73,9 @@ from trilogy.core.models.author import (
|
|
|
72
73
|
)
|
|
73
74
|
from trilogy.core.models.core import (
|
|
74
75
|
Addressable,
|
|
76
|
+
ArrayType,
|
|
75
77
|
DataType,
|
|
76
78
|
DataTyped,
|
|
77
|
-
ListType,
|
|
78
79
|
ListWrapper,
|
|
79
80
|
MapType,
|
|
80
81
|
MapWrapper,
|
|
@@ -791,7 +792,7 @@ class BuildSubselectComparison(BuildComparison):
|
|
|
791
792
|
class BuildConcept(Addressable, BuildConceptArgs, DataTyped, BaseModel):
|
|
792
793
|
model_config = ConfigDict(extra="forbid")
|
|
793
794
|
name: str
|
|
794
|
-
datatype: DataType |
|
|
795
|
+
datatype: DataType | ArrayType | StructType | MapType | NumericType
|
|
795
796
|
purpose: Purpose
|
|
796
797
|
build_is_aggregate: bool
|
|
797
798
|
derivation: Derivation = Derivation.ROOT
|
|
@@ -1083,7 +1084,7 @@ class BuildFunction(DataTyped, BuildConceptArgs, BaseModel):
|
|
|
1083
1084
|
operator: FunctionType
|
|
1084
1085
|
arg_count: int = Field(default=1)
|
|
1085
1086
|
output_datatype: (
|
|
1086
|
-
DataType |
|
|
1087
|
+
DataType | ArrayType | StructType | MapType | NumericType | TraitDataType
|
|
1087
1088
|
)
|
|
1088
1089
|
output_purpose: Purpose
|
|
1089
1090
|
valid_inputs: Optional[
|
|
@@ -1102,7 +1103,7 @@ class BuildFunction(DataTyped, BuildConceptArgs, BaseModel):
|
|
|
1102
1103
|
MapWrapper[Any, Any],
|
|
1103
1104
|
TraitDataType,
|
|
1104
1105
|
DataType,
|
|
1105
|
-
|
|
1106
|
+
ArrayType,
|
|
1106
1107
|
MapType,
|
|
1107
1108
|
NumericType,
|
|
1108
1109
|
DatePart,
|
|
@@ -2075,7 +2076,7 @@ class Factory:
|
|
|
2075
2076
|
return base
|
|
2076
2077
|
|
|
2077
2078
|
@build.register
|
|
2078
|
-
def _(self, base:
|
|
2079
|
+
def _(self, base: ArrayType):
|
|
2079
2080
|
return base
|
|
2080
2081
|
|
|
2081
2082
|
@build.register
|
|
@@ -2086,6 +2087,14 @@ class Factory:
|
|
|
2086
2087
|
def _(self, base: MapType):
|
|
2087
2088
|
return base
|
|
2088
2089
|
|
|
2090
|
+
@build.register
|
|
2091
|
+
def _(self, base: ArgBinding):
|
|
2092
|
+
return base
|
|
2093
|
+
|
|
2094
|
+
@build.register
|
|
2095
|
+
def _(self, base: Ordering):
|
|
2096
|
+
return base
|
|
2097
|
+
|
|
2089
2098
|
@build.register
|
|
2090
2099
|
def _(self, base: Datasource):
|
|
2091
2100
|
local_cache: dict[str, BuildConcept] = {}
|
|
@@ -27,6 +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
31
|
|
|
31
32
|
|
|
32
33
|
class DataTyped(ABC):
|
|
@@ -53,7 +54,7 @@ class Addressable(ABC):
|
|
|
53
54
|
TYPEDEF_TYPES = Union[
|
|
54
55
|
"DataType",
|
|
55
56
|
"MapType",
|
|
56
|
-
"
|
|
57
|
+
"ArrayType",
|
|
57
58
|
"NumericType",
|
|
58
59
|
"StructType",
|
|
59
60
|
"DataTyped",
|
|
@@ -63,7 +64,7 @@ TYPEDEF_TYPES = Union[
|
|
|
63
64
|
CONCRETE_TYPES = Union[
|
|
64
65
|
"DataType",
|
|
65
66
|
"MapType",
|
|
66
|
-
"
|
|
67
|
+
"ArrayType",
|
|
67
68
|
"NumericType",
|
|
68
69
|
"StructType",
|
|
69
70
|
"TraitDataType",
|
|
@@ -79,7 +80,6 @@ class DataType(Enum):
|
|
|
79
80
|
STRING = "string"
|
|
80
81
|
BOOL = "bool"
|
|
81
82
|
MAP = "map"
|
|
82
|
-
LIST = "list"
|
|
83
83
|
NUMBER = "number"
|
|
84
84
|
FLOAT = "float"
|
|
85
85
|
NUMERIC = "numeric"
|
|
@@ -105,7 +105,7 @@ class DataType(Enum):
|
|
|
105
105
|
|
|
106
106
|
|
|
107
107
|
class TraitDataType(BaseModel):
|
|
108
|
-
type: DataType | NumericType | StructType |
|
|
108
|
+
type: DataType | NumericType | StructType | ArrayType | MapType
|
|
109
109
|
traits: list[str]
|
|
110
110
|
|
|
111
111
|
def __hash__(self):
|
|
@@ -146,7 +146,7 @@ class NumericType(BaseModel):
|
|
|
146
146
|
return self.data_type.value
|
|
147
147
|
|
|
148
148
|
|
|
149
|
-
class
|
|
149
|
+
class ArrayType(BaseModel):
|
|
150
150
|
model_config = ConfigDict(frozen=True)
|
|
151
151
|
type: TYPEDEF_TYPES
|
|
152
152
|
|
|
@@ -159,7 +159,7 @@ class ListType(BaseModel):
|
|
|
159
159
|
|
|
160
160
|
@property
|
|
161
161
|
def data_type(self):
|
|
162
|
-
return DataType.
|
|
162
|
+
return DataType.ARRAY
|
|
163
163
|
|
|
164
164
|
@property
|
|
165
165
|
def value(self):
|
|
@@ -340,9 +340,9 @@ def dict_to_map_wrapper(arg):
|
|
|
340
340
|
|
|
341
341
|
def merge_datatypes(
|
|
342
342
|
inputs: list[
|
|
343
|
-
DataType |
|
|
343
|
+
DataType | ArrayType | StructType | MapType | NumericType | TraitDataType
|
|
344
344
|
],
|
|
345
|
-
) -> DataType |
|
|
345
|
+
) -> DataType | ArrayType | StructType | MapType | NumericType | TraitDataType:
|
|
346
346
|
"""This is a temporary hack for doing between
|
|
347
347
|
allowable datatype transformation matrix"""
|
|
348
348
|
if len(inputs) == 1:
|
|
@@ -393,6 +393,8 @@ def arg_to_datatype(arg) -> CONCRETE_TYPES:
|
|
|
393
393
|
raise ValueError(f"Cannot parse arg datatype for arg of type {arg}")
|
|
394
394
|
elif isinstance(arg, bool):
|
|
395
395
|
return DataType.BOOL
|
|
396
|
+
elif isinstance(arg, Ordering):
|
|
397
|
+
return DataType.STRING # TODO: revisit
|
|
396
398
|
elif isinstance(arg, int):
|
|
397
399
|
return DataType.INTEGER
|
|
398
400
|
elif isinstance(arg, str):
|
|
@@ -404,14 +406,14 @@ def arg_to_datatype(arg) -> CONCRETE_TYPES:
|
|
|
404
406
|
elif isinstance(arg, TraitDataType):
|
|
405
407
|
return arg
|
|
406
408
|
elif isinstance(arg, ListWrapper):
|
|
407
|
-
return
|
|
409
|
+
return ArrayType(type=arg.type)
|
|
408
410
|
elif isinstance(arg, DataTyped):
|
|
409
411
|
return arg.output_datatype
|
|
410
412
|
elif isinstance(arg, TupleWrapper):
|
|
411
|
-
return
|
|
413
|
+
return ArrayType(type=arg.type)
|
|
412
414
|
elif isinstance(arg, list):
|
|
413
415
|
wrapper = list_to_wrapper(arg)
|
|
414
|
-
return
|
|
416
|
+
return ArrayType(type=wrapper.type)
|
|
415
417
|
elif isinstance(arg, MapWrapper):
|
|
416
418
|
return MapType(key_type=arg.key_type, value_type=arg.value_type)
|
|
417
419
|
elif isinstance(arg, datetime):
|
|
@@ -33,8 +33,8 @@ from trilogy.core.models.build import (
|
|
|
33
33
|
)
|
|
34
34
|
from trilogy.core.models.build_environment import BuildEnvironment
|
|
35
35
|
from trilogy.core.models.core import (
|
|
36
|
+
ArrayType,
|
|
36
37
|
DataType,
|
|
37
|
-
ListType,
|
|
38
38
|
ListWrapper,
|
|
39
39
|
MapType,
|
|
40
40
|
MapWrapper,
|
|
@@ -471,7 +471,7 @@ def is_scalar_condition(
|
|
|
471
471
|
| TraitDataType
|
|
472
472
|
| DataType
|
|
473
473
|
| MapWrapper[Any, Any]
|
|
474
|
-
|
|
|
474
|
+
| ArrayType
|
|
475
475
|
| MapType
|
|
476
476
|
| NumericType
|
|
477
477
|
| DatePart
|
|
@@ -15,10 +15,12 @@ from trilogy.core.enums import (
|
|
|
15
15
|
ComparisonOperator,
|
|
16
16
|
DatePart,
|
|
17
17
|
FunctionType,
|
|
18
|
+
Ordering,
|
|
18
19
|
UnnestMode,
|
|
19
20
|
WindowType,
|
|
20
21
|
)
|
|
21
22
|
from trilogy.core.internal import DEFAULT_CONCEPTS
|
|
23
|
+
from trilogy.core.models.author import ArgBinding
|
|
22
24
|
from trilogy.core.models.build import (
|
|
23
25
|
BuildAggregateWrapper,
|
|
24
26
|
BuildCaseElse,
|
|
@@ -37,8 +39,8 @@ from trilogy.core.models.build import (
|
|
|
37
39
|
BuildWindowItem,
|
|
38
40
|
)
|
|
39
41
|
from trilogy.core.models.core import (
|
|
42
|
+
ArrayType,
|
|
40
43
|
DataType,
|
|
41
|
-
ListType,
|
|
42
44
|
ListWrapper,
|
|
43
45
|
MapType,
|
|
44
46
|
MapWrapper,
|
|
@@ -142,11 +144,11 @@ DATATYPE_MAP: dict[DataType, str] = {
|
|
|
142
144
|
DataType.MAP: "map",
|
|
143
145
|
DataType.DATE: "date",
|
|
144
146
|
DataType.DATETIME: "datetime",
|
|
145
|
-
DataType.
|
|
147
|
+
DataType.ARRAY: "list",
|
|
146
148
|
}
|
|
147
149
|
|
|
148
150
|
COMPLEX_DATATYPE_MAP = {
|
|
149
|
-
DataType.
|
|
151
|
+
DataType.ARRAY: lambda x: f"{x}[]",
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
|
|
@@ -182,6 +184,13 @@ FUNCTION_MAP = {
|
|
|
182
184
|
FunctionType.ARRAY: lambda x: f"[{', '.join(x)}]",
|
|
183
185
|
FunctionType.DATE_LITERAL: lambda x: f"date '{x}'",
|
|
184
186
|
FunctionType.DATETIME_LITERAL: lambda x: f"datetime '{x}'",
|
|
187
|
+
# ARRAY
|
|
188
|
+
FunctionType.ARRAY_SUM: lambda x: f"array_sum({x[0]})",
|
|
189
|
+
FunctionType.ARRAY_DISTINCT: lambda x: f"array_distinct({x[0]})",
|
|
190
|
+
FunctionType.ARRAY_SORT: lambda x: f"array_sort({x[0]})",
|
|
191
|
+
FunctionType.ARRAY_TRANSFORM: lambda args: (
|
|
192
|
+
f"array_transform({args[0]}, {args[1]} -> {args[2]})"
|
|
193
|
+
),
|
|
185
194
|
# math
|
|
186
195
|
FunctionType.ADD: lambda x: " + ".join(x),
|
|
187
196
|
FunctionType.ABS: lambda x: f"abs({x[0]})",
|
|
@@ -198,6 +207,7 @@ FUNCTION_MAP = {
|
|
|
198
207
|
FunctionType.COUNT_DISTINCT: lambda x: f"count(distinct {x[0]})",
|
|
199
208
|
FunctionType.COUNT: lambda x: f"count({x[0]})",
|
|
200
209
|
FunctionType.SUM: lambda x: f"sum({x[0]})",
|
|
210
|
+
FunctionType.ARRAY_AGG: lambda x: f"array_agg({x[0]})",
|
|
201
211
|
FunctionType.LENGTH: lambda x: f"length({x[0]})",
|
|
202
212
|
FunctionType.AVG: lambda x: f"avg({x[0]})",
|
|
203
213
|
FunctionType.MAX: lambda x: f"max({x[0]})",
|
|
@@ -569,7 +579,7 @@ class BaseDialect:
|
|
|
569
579
|
MapType,
|
|
570
580
|
NumericType,
|
|
571
581
|
StructType,
|
|
572
|
-
|
|
582
|
+
ArrayType,
|
|
573
583
|
ListWrapper[Any],
|
|
574
584
|
TupleWrapper[Any],
|
|
575
585
|
DatePart,
|
|
@@ -749,8 +759,12 @@ class BaseDialect:
|
|
|
749
759
|
return self.FUNCTION_MAP[FunctionType.DATETIME_LITERAL](e)
|
|
750
760
|
elif isinstance(e, TraitDataType):
|
|
751
761
|
return self.render_expr(e.type, cte=cte, cte_map=cte_map)
|
|
752
|
-
elif isinstance(e,
|
|
753
|
-
return
|
|
762
|
+
elif isinstance(e, ArgBinding):
|
|
763
|
+
return e.name
|
|
764
|
+
elif isinstance(e, Ordering):
|
|
765
|
+
return str(e.value)
|
|
766
|
+
elif isinstance(e, ArrayType):
|
|
767
|
+
return f"{self.COMPLEX_DATATYPE_MAP[DataType.ARRAY](self.render_expr(e.value_data_type, cte=cte, cte_map=cte_map))}"
|
|
754
768
|
elif isinstance(e, BuildParamaterizedConceptReference):
|
|
755
769
|
if self.rendering.parameters:
|
|
756
770
|
if e.concept.namespace == DEFAULT_NAMESPACE:
|
|
@@ -23,6 +23,16 @@ def generate_regex_extract(x: list[str]) -> str:
|
|
|
23
23
|
return f"REGEXP_EXTRACT({x[0]},{x[1]},{x[2]})"
|
|
24
24
|
|
|
25
25
|
|
|
26
|
+
def render_sort(args):
|
|
27
|
+
if len(args) == 1:
|
|
28
|
+
return f"list_sort({args[0]})"
|
|
29
|
+
order = args[1].split(" ", 1)
|
|
30
|
+
if len(order) == 1:
|
|
31
|
+
return f"list_sort({args[0]}, '{order[0]}')"
|
|
32
|
+
elif len(order) == 2:
|
|
33
|
+
return f"list_sort({args[0]}, '{order[0]}', '{order[1]}')"
|
|
34
|
+
|
|
35
|
+
|
|
26
36
|
FUNCTION_MAP = {
|
|
27
37
|
FunctionType.COUNT: lambda args: f"count({args[0]})",
|
|
28
38
|
FunctionType.SUM: lambda args: f"sum({args[0]})",
|
|
@@ -39,6 +49,14 @@ FUNCTION_MAP = {
|
|
|
39
49
|
),
|
|
40
50
|
## Duckdb indexes from 1, not 0
|
|
41
51
|
FunctionType.INDEX_ACCESS: lambda args: (f"{args[0]}[{args[1]}]"),
|
|
52
|
+
## Duckdb uses list for array
|
|
53
|
+
FunctionType.ARRAY_DISTINCT: lambda args: f"list_distinct({args[0]})",
|
|
54
|
+
FunctionType.ARRAY_SUM: lambda args: f"list_sum({args[0]})",
|
|
55
|
+
FunctionType.ARRAY_SORT: render_sort,
|
|
56
|
+
FunctionType.ARRAY_TRANSFORM: lambda args: (
|
|
57
|
+
f"list_transform({args[0]}, {args[1]} -> {args[2]})"
|
|
58
|
+
),
|
|
59
|
+
FunctionType.ARRAY_AGG: lambda args: f"array_agg({args[0]})",
|
|
42
60
|
# datetime is aliased
|
|
43
61
|
FunctionType.CURRENT_DATETIME: lambda x: "cast(get_current_timestamp() as datetime)",
|
|
44
62
|
FunctionType.DATE: lambda x: f"cast({x[0]} as date)",
|