pytrilogy 0.0.3.17__tar.gz → 0.0.3.19__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.
- {pytrilogy-0.0.3.17/pytrilogy.egg-info → pytrilogy-0.0.3.19}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19/pytrilogy.egg-info}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_show.py +3 -3
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/enums.py +1 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/ergonomics.py +0 -1
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/functions.py +21 -3
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/models/author.py +76 -1
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/models/environment.py +11 -2
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/statements/author.py +5 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/dialect/duckdb.py +2 -1
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/parsing/parse_engine.py +16 -21
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/parsing/trilogy.lark +5 -3
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/LICENSE.md +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/README.md +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/pyproject.toml +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/pytrilogy.egg-info/SOURCES.txt +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/setup.cfg +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/setup.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_enums.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_executor.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_functions.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_models.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_parse_engine.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_parsing.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_query_render.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_select.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_typing.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_user_functions.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/authoring/__init__.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/constants.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/models/__init__.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/models/build.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/models/build_environment.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/models/core.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/models/datasource.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/models/execute.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/optimizations/inline_constant.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/concept_strategies_v3.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/group_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/union_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/window_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/nodes/union_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/statements/__init__.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/statements/build.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/statements/common.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/statements/execute.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/dialect/base.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/dialect/common.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/dialect/dataframe.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/executor.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/parsing/common.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/parsing/render.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/render.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/utility.py +0 -0
|
@@ -52,6 +52,6 @@ def test_show_bigquery():
|
|
|
52
52
|
.execute_query(select)
|
|
53
53
|
.fetchall()
|
|
54
54
|
)
|
|
55
|
-
assert
|
|
56
|
-
0
|
|
57
|
-
]["__preql_internal_query_text"]
|
|
55
|
+
assert (
|
|
56
|
+
"FULL JOIN cheerful on 1=1" in query[0]["__preql_internal_query_text"]
|
|
57
|
+
), query[0]["__preql_internal_query_text"]
|
|
@@ -145,6 +145,9 @@ def get_date_trunc_output(
|
|
|
145
145
|
|
|
146
146
|
|
|
147
147
|
FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
148
|
+
FunctionType.ALIAS: FunctionConfig(
|
|
149
|
+
arg_count=1,
|
|
150
|
+
),
|
|
148
151
|
FunctionType.PARENTHETICAL: FunctionConfig(
|
|
149
152
|
arg_count=1,
|
|
150
153
|
),
|
|
@@ -375,6 +378,21 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
|
375
378
|
output_type=DataType.DATE,
|
|
376
379
|
arg_count=3,
|
|
377
380
|
),
|
|
381
|
+
FunctionType.DATE_SUB: FunctionConfig(
|
|
382
|
+
valid_inputs=[
|
|
383
|
+
{
|
|
384
|
+
DataType.DATE,
|
|
385
|
+
DataType.TIMESTAMP,
|
|
386
|
+
DataType.DATETIME,
|
|
387
|
+
DataType.STRING,
|
|
388
|
+
},
|
|
389
|
+
{DataType.DATE_PART},
|
|
390
|
+
{DataType.INTEGER},
|
|
391
|
+
],
|
|
392
|
+
output_purpose=Purpose.PROPERTY,
|
|
393
|
+
output_type=DataType.DATE,
|
|
394
|
+
arg_count=3,
|
|
395
|
+
),
|
|
378
396
|
FunctionType.DATE_DIFF: FunctionConfig(
|
|
379
397
|
valid_inputs=[
|
|
380
398
|
{
|
|
@@ -639,8 +657,6 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
|
639
657
|
|
|
640
658
|
EXCLUDED_FUNCTIONS = {
|
|
641
659
|
FunctionType.CUSTOM,
|
|
642
|
-
FunctionType.ALIAS,
|
|
643
|
-
# FunctionType.PARENTHETICAL,
|
|
644
660
|
# Temporary
|
|
645
661
|
FunctionType.DATE_LITERAL,
|
|
646
662
|
FunctionType.DATETIME_LITERAL,
|
|
@@ -649,7 +665,9 @@ EXCLUDED_FUNCTIONS = {
|
|
|
649
665
|
|
|
650
666
|
for k in FunctionType.__members__.values():
|
|
651
667
|
if k not in FUNCTION_REGISTRY and k not in EXCLUDED_FUNCTIONS:
|
|
652
|
-
raise InvalidSyntaxException(
|
|
668
|
+
raise InvalidSyntaxException(
|
|
669
|
+
f"Function enum value {k} not in creation registry"
|
|
670
|
+
)
|
|
653
671
|
|
|
654
672
|
|
|
655
673
|
class FunctionFactory:
|
|
@@ -318,6 +318,21 @@ class Conditional(Mergeable, ConceptArgs, Namespaced, BaseModel):
|
|
|
318
318
|
operator=self.operator,
|
|
319
319
|
)
|
|
320
320
|
|
|
321
|
+
def with_reference_replacement(self, source, target):
|
|
322
|
+
return self.__class__.model_construct(
|
|
323
|
+
left=(
|
|
324
|
+
self.left.with_reference_replacement(source, target)
|
|
325
|
+
if isinstance(self.left, Mergeable)
|
|
326
|
+
else self.left
|
|
327
|
+
),
|
|
328
|
+
right=(
|
|
329
|
+
self.right.with_reference_replacement(source, target)
|
|
330
|
+
if isinstance(self.right, Mergeable)
|
|
331
|
+
else self.right
|
|
332
|
+
),
|
|
333
|
+
operator=self.operator,
|
|
334
|
+
)
|
|
335
|
+
|
|
321
336
|
@property
|
|
322
337
|
def concept_arguments(self) -> Sequence[ConceptRef]:
|
|
323
338
|
"""Return concepts directly referenced in where clause"""
|
|
@@ -793,6 +808,10 @@ class Concept(Addressable, DataTyped, ConceptArgs, Mergeable, Namespaced, BaseMo
|
|
|
793
808
|
base = f"{self.address}@{self.grain}"
|
|
794
809
|
return base
|
|
795
810
|
|
|
811
|
+
@property
|
|
812
|
+
def is_internal(self) -> bool:
|
|
813
|
+
return self.namespace.startswith("_") or self.name.startswith("_")
|
|
814
|
+
|
|
796
815
|
@property
|
|
797
816
|
def reference(self) -> ConceptRef:
|
|
798
817
|
return ConceptRef.model_construct(
|
|
@@ -2131,6 +2150,52 @@ class AlignItem(Namespaced, BaseModel):
|
|
|
2131
2150
|
)
|
|
2132
2151
|
|
|
2133
2152
|
|
|
2153
|
+
class CustomFunctionFactory:
|
|
2154
|
+
def __init__(
|
|
2155
|
+
self, function: Expr, namespace: str, function_arguments: list[ArgBinding]
|
|
2156
|
+
):
|
|
2157
|
+
self.namespace = namespace
|
|
2158
|
+
self.function = function
|
|
2159
|
+
self.function_arguments = function_arguments
|
|
2160
|
+
|
|
2161
|
+
def with_namespace(self, namespace: str):
|
|
2162
|
+
self.namespace = namespace
|
|
2163
|
+
self.function = (
|
|
2164
|
+
self.function.with_namespace(namespace)
|
|
2165
|
+
if isinstance(self.function, Namespaced)
|
|
2166
|
+
else self.function
|
|
2167
|
+
)
|
|
2168
|
+
self.function_arguments = [
|
|
2169
|
+
x.with_namespace(namespace) for x in self.function_arguments
|
|
2170
|
+
]
|
|
2171
|
+
return self
|
|
2172
|
+
|
|
2173
|
+
def __call__(self, *creation_args: list[Expr]):
|
|
2174
|
+
nout = (
|
|
2175
|
+
self.function.model_copy(deep=True)
|
|
2176
|
+
if isinstance(self.function, BaseModel)
|
|
2177
|
+
else self.function
|
|
2178
|
+
)
|
|
2179
|
+
creation_arg_list: list[Expr] = list(creation_args)
|
|
2180
|
+
if len(creation_args) < len(self.function_arguments):
|
|
2181
|
+
for binding in self.function_arguments[len(creation_arg_list) :]:
|
|
2182
|
+
if binding.default is None:
|
|
2183
|
+
raise ValueError(f"Missing argument {binding.name}")
|
|
2184
|
+
creation_arg_list.append(binding.default)
|
|
2185
|
+
if isinstance(nout, Mergeable):
|
|
2186
|
+
for idx, x in enumerate(creation_arg_list):
|
|
2187
|
+
if self.namespace == DEFAULT_NAMESPACE:
|
|
2188
|
+
target = f"{DEFAULT_NAMESPACE}.{self.function_arguments[idx].name}"
|
|
2189
|
+
else:
|
|
2190
|
+
target = self.function_arguments[idx].name
|
|
2191
|
+
nout = (
|
|
2192
|
+
nout.with_reference_replacement(target, x)
|
|
2193
|
+
if isinstance(nout, Mergeable)
|
|
2194
|
+
else nout
|
|
2195
|
+
)
|
|
2196
|
+
return nout
|
|
2197
|
+
|
|
2198
|
+
|
|
2134
2199
|
class Metadata(BaseModel):
|
|
2135
2200
|
"""Metadata container object.
|
|
2136
2201
|
TODO: support arbitrary tags"""
|
|
@@ -2160,10 +2225,20 @@ class Comment(BaseModel):
|
|
|
2160
2225
|
text: str
|
|
2161
2226
|
|
|
2162
2227
|
|
|
2163
|
-
class ArgBinding(BaseModel):
|
|
2228
|
+
class ArgBinding(Namespaced, BaseModel):
|
|
2164
2229
|
name: str
|
|
2165
2230
|
default: Expr | None = None
|
|
2166
2231
|
|
|
2232
|
+
def with_namespace(self, namespace):
|
|
2233
|
+
return ArgBinding(
|
|
2234
|
+
name=address_with_namespace(self.name, namespace),
|
|
2235
|
+
default=(
|
|
2236
|
+
self.default.with_namespace(namespace)
|
|
2237
|
+
if isinstance(self.default, Namespaced)
|
|
2238
|
+
else self.default
|
|
2239
|
+
),
|
|
2240
|
+
)
|
|
2241
|
+
|
|
2167
2242
|
|
|
2168
2243
|
class CustomType(BaseModel):
|
|
2169
2244
|
name: str
|
|
@@ -9,7 +9,6 @@ from typing import (
|
|
|
9
9
|
TYPE_CHECKING,
|
|
10
10
|
Annotated,
|
|
11
11
|
Any,
|
|
12
|
-
Callable,
|
|
13
12
|
Dict,
|
|
14
13
|
ItemsView,
|
|
15
14
|
List,
|
|
@@ -40,6 +39,7 @@ from trilogy.core.exceptions import (
|
|
|
40
39
|
from trilogy.core.models.author import (
|
|
41
40
|
Concept,
|
|
42
41
|
ConceptRef,
|
|
42
|
+
CustomFunctionFactory,
|
|
43
43
|
CustomType,
|
|
44
44
|
Function,
|
|
45
45
|
SelectLineage,
|
|
@@ -58,6 +58,7 @@ if TYPE_CHECKING:
|
|
|
58
58
|
class Import:
|
|
59
59
|
alias: str
|
|
60
60
|
path: Path
|
|
61
|
+
input_path: str | None = None
|
|
61
62
|
|
|
62
63
|
|
|
63
64
|
class BaseImportResolver(BaseModel):
|
|
@@ -206,7 +207,7 @@ class Environment(BaseModel):
|
|
|
206
207
|
datasources: Annotated[
|
|
207
208
|
EnvironmentDatasourceDict, PlainValidator(validate_datasources)
|
|
208
209
|
] = Field(default_factory=EnvironmentDatasourceDict)
|
|
209
|
-
functions: Dict[str,
|
|
210
|
+
functions: Dict[str, CustomFunctionFactory] = Field(default_factory=dict)
|
|
210
211
|
data_types: Dict[str, CustomType] = Field(default_factory=dict)
|
|
211
212
|
named_statements: Dict[str, SelectLineage] = Field(default_factory=dict)
|
|
212
213
|
imports: Dict[str, list[Import]] = Field(
|
|
@@ -433,6 +434,14 @@ class Environment(BaseModel):
|
|
|
433
434
|
self.alias_origin_lookup[address_with_namespace(key, alias)] = (
|
|
434
435
|
val.with_namespace(alias)
|
|
435
436
|
)
|
|
437
|
+
|
|
438
|
+
for key, function in source.functions.items():
|
|
439
|
+
if same_namespace:
|
|
440
|
+
self.functions[key] = function
|
|
441
|
+
else:
|
|
442
|
+
self.functions[address_with_namespace(key, alias)] = (
|
|
443
|
+
function.with_namespace(alias)
|
|
444
|
+
)
|
|
436
445
|
return self
|
|
437
446
|
|
|
438
447
|
def add_file_import(
|
|
@@ -382,7 +382,12 @@ class MergeStatementV2(HasUUID, BaseModel):
|
|
|
382
382
|
|
|
383
383
|
|
|
384
384
|
class ImportStatement(HasUUID, BaseModel):
|
|
385
|
+
# import abc.def as bar
|
|
386
|
+
# the bit after 'as', eg bar
|
|
385
387
|
alias: str
|
|
388
|
+
# the bit after import, abc.def
|
|
389
|
+
input_path: str
|
|
390
|
+
# what it actually resolves to, typically a filepath
|
|
386
391
|
path: Path
|
|
387
392
|
|
|
388
393
|
|
|
@@ -8,6 +8,7 @@ from trilogy.dialect.base import BaseDialect
|
|
|
8
8
|
|
|
9
9
|
WINDOW_FUNCTION_MAP: Mapping[WindowType, Callable[[Any, Any, Any], str]] = {}
|
|
10
10
|
|
|
11
|
+
|
|
11
12
|
FUNCTION_MAP = {
|
|
12
13
|
FunctionType.COUNT: lambda args: f"count({args[0]})",
|
|
13
14
|
FunctionType.SUM: lambda args: f"sum({args[0]})",
|
|
@@ -27,7 +28,7 @@ FUNCTION_MAP = {
|
|
|
27
28
|
# datetime is aliased
|
|
28
29
|
FunctionType.CURRENT_DATETIME: lambda x: "cast(get_current_timestamp() as datetime)",
|
|
29
30
|
FunctionType.DATE_TRUNCATE: lambda x: f"date_trunc('{x[1]}', {x[0]})",
|
|
30
|
-
FunctionType.DATE_ADD: lambda x: f"date_add({x[0]},
|
|
31
|
+
FunctionType.DATE_ADD: lambda x: f"date_add({x[0]}, {x[2]} * INTERVAL 1 {x[1]})",
|
|
31
32
|
FunctionType.DATE_PART: lambda x: f"date_part('{x[1]}', {x[0]})",
|
|
32
33
|
FunctionType.DATE_DIFF: lambda x: f"date_diff('{x[2]}', {x[0]}, {x[1]})",
|
|
33
34
|
FunctionType.CONCAT: lambda x: f"({' || '.join(x)})",
|
|
@@ -57,13 +57,13 @@ from trilogy.core.models.author import (
|
|
|
57
57
|
Concept,
|
|
58
58
|
ConceptRef,
|
|
59
59
|
Conditional,
|
|
60
|
+
CustomFunctionFactory,
|
|
60
61
|
CustomType,
|
|
61
62
|
Expr,
|
|
62
63
|
FilterItem,
|
|
63
64
|
Function,
|
|
64
65
|
Grain,
|
|
65
66
|
HavingClause,
|
|
66
|
-
Mergeable,
|
|
67
67
|
Metadata,
|
|
68
68
|
OrderBy,
|
|
69
69
|
OrderItem,
|
|
@@ -951,7 +951,8 @@ class ParseToObjects(Transformer):
|
|
|
951
951
|
else:
|
|
952
952
|
alias = self.environment.namespace
|
|
953
953
|
cache_key = args[0]
|
|
954
|
-
|
|
954
|
+
input_path = args[0]
|
|
955
|
+
path = input_path.split(".")
|
|
955
956
|
|
|
956
957
|
if isinstance(
|
|
957
958
|
self.environment.config.import_resolver, FileSystemImportResolver
|
|
@@ -971,7 +972,9 @@ class ParseToObjects(Transformer):
|
|
|
971
972
|
|
|
972
973
|
# we don't iterate past the max parse depth
|
|
973
974
|
if len(key_path) > MAX_PARSE_DEPTH:
|
|
974
|
-
return ImportStatement(
|
|
975
|
+
return ImportStatement(
|
|
976
|
+
alias=alias, input_path=input_path, path=Path(target)
|
|
977
|
+
)
|
|
975
978
|
|
|
976
979
|
if token_lookup in self.tokens:
|
|
977
980
|
raw_tokens = self.tokens[token_lookup]
|
|
@@ -1015,7 +1018,7 @@ class ParseToObjects(Transformer):
|
|
|
1015
1018
|
) from e
|
|
1016
1019
|
|
|
1017
1020
|
parsed_path = Path(args[0])
|
|
1018
|
-
imps = ImportStatement(alias=alias, path=parsed_path)
|
|
1021
|
+
imps = ImportStatement(alias=alias, input_path=input_path, path=parsed_path)
|
|
1019
1022
|
|
|
1020
1023
|
self.environment.add_import(
|
|
1021
1024
|
alias, new_env, Import(alias=alias, path=parsed_path)
|
|
@@ -1195,23 +1198,11 @@ class ParseToObjects(Transformer):
|
|
|
1195
1198
|
function_arguments: list[ArgBinding] = args[1]
|
|
1196
1199
|
output = args[2]
|
|
1197
1200
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
if binding.default is None:
|
|
1204
|
-
raise ValueError(f"Missing argument {binding.name}")
|
|
1205
|
-
creation_arg_list.append(binding.default)
|
|
1206
|
-
if isinstance(nout, Mergeable):
|
|
1207
|
-
for idx, x in enumerate(creation_arg_list):
|
|
1208
|
-
# these will always be local namespace
|
|
1209
|
-
nout = nout.with_reference_replacement(
|
|
1210
|
-
f"{DEFAULT_NAMESPACE}.{function_arguments[idx].name}", x
|
|
1211
|
-
)
|
|
1212
|
-
return nout
|
|
1213
|
-
|
|
1214
|
-
self.environment.functions[identity] = function_factory
|
|
1201
|
+
self.environment.functions[identity] = CustomFunctionFactory(
|
|
1202
|
+
function=output,
|
|
1203
|
+
namespace=self.environment.namespace,
|
|
1204
|
+
function_arguments=function_arguments,
|
|
1205
|
+
)
|
|
1215
1206
|
return FunctionDeclaration(name=identity, args=function_arguments, expr=output)
|
|
1216
1207
|
|
|
1217
1208
|
def custom_function(self, args):
|
|
@@ -1582,6 +1573,10 @@ class ParseToObjects(Transformer):
|
|
|
1582
1573
|
def fdate_add(self, meta, args):
|
|
1583
1574
|
return self.function_factory.create_function(args, FunctionType.DATE_ADD, meta)
|
|
1584
1575
|
|
|
1576
|
+
@v_args(meta=True)
|
|
1577
|
+
def fdate_sub(self, meta, args):
|
|
1578
|
+
return self.function_factory.create_function(args, FunctionType.DATE_SUB, meta)
|
|
1579
|
+
|
|
1585
1580
|
@v_args(meta=True)
|
|
1586
1581
|
def fdate_diff(self, meta, args):
|
|
1587
1582
|
return self.function_factory.create_function(args, FunctionType.DATE_DIFF, meta)
|
|
@@ -293,11 +293,13 @@
|
|
|
293
293
|
_DATE_PART.1: "date_part("i
|
|
294
294
|
fdate_part: _DATE_PART expr "," DATE_PART ")"
|
|
295
295
|
_DATE_ADD.1: "date_add("i
|
|
296
|
-
fdate_add: _DATE_ADD expr "," DATE_PART ","
|
|
297
|
-
|
|
296
|
+
fdate_add: _DATE_ADD expr "," DATE_PART "," expr ")"
|
|
297
|
+
_DATE_SUB.1: "date_sub("i
|
|
298
|
+
fdate_sub: _DATE_SUB expr "," DATE_PART "," expr ")"
|
|
299
|
+
_DATE_DIFF.1: "date_diff("i
|
|
298
300
|
fdate_diff: _DATE_DIFF expr "," expr "," DATE_PART ")"
|
|
299
301
|
|
|
300
|
-
_date_functions: fdate | fdate_add | fdate_diff | fdatetime | ftimestamp | fsecond | fminute | fhour | fday | fday_of_week | fweek | fmonth | fquarter | fyear | fdate_part | fdate_trunc
|
|
302
|
+
_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
|
|
301
303
|
|
|
302
304
|
_static_functions: _string_functions | _math_functions | _generic_functions | _date_functions
|
|
303
305
|
|
|
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.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/__init__.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/basic_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/filter_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/group_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/group_to_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/node_merge_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/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.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/select_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/synonym_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/union_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/trilogy/core/processing/node_generators/unnest_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.17 → pytrilogy-0.0.3.19}/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
|