pytrilogy 0.0.3.43__tar.gz → 0.0.3.45__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.43/pytrilogy.egg-info → pytrilogy-0.0.3.45}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45/pytrilogy.egg-info}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_models.py +0 -3
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_parsing_failures.py +2 -1
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/models/author.py +12 -14
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/models/build.py +52 -47
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/concept_strategies_v3.py +2 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/common.py +1 -1
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/window_node.py +10 -4
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/nodes/__init__.py +23 -19
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/parsing/common.py +40 -25
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/parsing/parse_engine.py +83 -13
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/parsing/trilogy.lark +44 -34
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/LICENSE.md +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/README.md +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/pyproject.toml +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/pytrilogy.egg-info/SOURCES.txt +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/setup.cfg +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/setup.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_enums.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_executor.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_failure.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_functions.py +1 -1
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_parse_engine.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_parsing.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_query_render.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_select.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_show.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_typing.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_user_functions.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/authoring/__init__.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/constants.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/enums.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/functions.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/models/__init__.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/models/build_environment.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/models/core.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/models/datasource.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/models/environment.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/models/execute.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/optimizations/inline_constant.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/group_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/union_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/nodes/union_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/statements/__init__.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/statements/author.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/statements/build.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/statements/common.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/statements/execute.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/dialect/base.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/dialect/common.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/dialect/dataframe.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/dialect/duckdb.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/executor.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/parsing/render.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/render.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/std/__init__.py +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/std/date.preql +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/std/display.preql +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/std/geography.preql +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/std/money.preql +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/std/report.preql +0 -0
- {pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/utility.py +0 -0
|
@@ -213,9 +213,6 @@ def test_comparison():
|
|
|
213
213
|
with raises(SyntaxError):
|
|
214
214
|
Comparison(left=1, right="abc", operator=ComparisonOperator.EQ)
|
|
215
215
|
|
|
216
|
-
with raises(SyntaxError):
|
|
217
|
-
Comparison(left=1, right=1, operator=ComparisonOperator.IN)
|
|
218
|
-
|
|
219
216
|
# this should not error
|
|
220
217
|
Comparison(left=1, right=[1, 2, 3], operator=ComparisonOperator.IN)
|
|
221
218
|
|
|
@@ -77,10 +77,11 @@ SELECT
|
|
|
77
77
|
1+2->scalar
|
|
78
78
|
;
|
|
79
79
|
"""
|
|
80
|
-
with raises(ParseError):
|
|
80
|
+
with raises(ParseError) as e:
|
|
81
81
|
env, parsed = parse_text(
|
|
82
82
|
x, parse_config=Parsing(strict_name_shadow_enforcement=True)
|
|
83
83
|
)
|
|
84
|
+
assert "abc" in str(e)
|
|
84
85
|
x = """
|
|
85
86
|
key scalar int;
|
|
86
87
|
property scalar.int_array list<int>;
|
|
@@ -629,18 +629,8 @@ class Comparison(ConceptArgs, Mergeable, DataTyped, Namespaced, BaseModel):
|
|
|
629
629
|
)
|
|
630
630
|
elif self.operator in (ComparisonOperator.IN, ComparisonOperator.NOT_IN):
|
|
631
631
|
right_type = arg_to_datatype(self.right)
|
|
632
|
-
if not any(
|
|
633
|
-
[
|
|
634
|
-
isinstance(self.right, ConceptRef),
|
|
635
|
-
right_type in (DataType.LIST,),
|
|
636
|
-
isinstance(right_type, (ListType, ListWrapper, TupleWrapper)),
|
|
637
|
-
]
|
|
638
|
-
):
|
|
639
|
-
raise SyntaxError(
|
|
640
|
-
f"Cannot use {self.operator.value} with non-list, non-tuple, non-concept object {self.right} in {str(self)}"
|
|
641
|
-
)
|
|
642
632
|
|
|
643
|
-
|
|
633
|
+
if isinstance(right_type, ListType) and not is_compatible_datatype(
|
|
644
634
|
arg_to_datatype(self.left), right_type.value_data_type
|
|
645
635
|
):
|
|
646
636
|
raise SyntaxError(
|
|
@@ -1916,7 +1906,7 @@ class AggregateWrapper(Mergeable, DataTyped, ConceptArgs, Namespaced, BaseModel)
|
|
|
1916
1906
|
|
|
1917
1907
|
|
|
1918
1908
|
class FilterItem(DataTyped, Namespaced, ConceptArgs, BaseModel):
|
|
1919
|
-
content:
|
|
1909
|
+
content: FuncArgs
|
|
1920
1910
|
where: "WhereClause"
|
|
1921
1911
|
|
|
1922
1912
|
@field_validator("content", mode="before")
|
|
@@ -1932,13 +1922,21 @@ class FilterItem(DataTyped, Namespaced, ConceptArgs, BaseModel):
|
|
|
1932
1922
|
self, source: Concept, target: Concept, modifiers: List[Modifier]
|
|
1933
1923
|
) -> "FilterItem":
|
|
1934
1924
|
return FilterItem.model_construct(
|
|
1935
|
-
content=
|
|
1925
|
+
content=(
|
|
1926
|
+
self.content.with_merge(source, target, modifiers)
|
|
1927
|
+
if isinstance(self.content, Mergeable)
|
|
1928
|
+
else self.content
|
|
1929
|
+
),
|
|
1936
1930
|
where=self.where.with_merge(source, target, modifiers),
|
|
1937
1931
|
)
|
|
1938
1932
|
|
|
1939
1933
|
def with_namespace(self, namespace: str) -> "FilterItem":
|
|
1940
1934
|
return FilterItem.model_construct(
|
|
1941
|
-
content=
|
|
1935
|
+
content=(
|
|
1936
|
+
self.content.with_namespace(namespace)
|
|
1937
|
+
if isinstance(self.content, Namespaced)
|
|
1938
|
+
else self.content
|
|
1939
|
+
),
|
|
1942
1940
|
where=self.where.with_namespace(namespace),
|
|
1943
1941
|
)
|
|
1944
1942
|
|
|
@@ -1496,22 +1496,43 @@ class Factory:
|
|
|
1496
1496
|
):
|
|
1497
1497
|
return base
|
|
1498
1498
|
|
|
1499
|
+
def instantiate_concept(
|
|
1500
|
+
self,
|
|
1501
|
+
arg: (
|
|
1502
|
+
AggregateWrapper
|
|
1503
|
+
| FunctionCallWrapper
|
|
1504
|
+
| WindowItem
|
|
1505
|
+
| FilterItem
|
|
1506
|
+
| Function
|
|
1507
|
+
| ListWrapper[Any]
|
|
1508
|
+
| MapWrapper[Any, Any]
|
|
1509
|
+
| int
|
|
1510
|
+
| float
|
|
1511
|
+
| str
|
|
1512
|
+
),
|
|
1513
|
+
) -> tuple[Concept, BuildConcept]:
|
|
1514
|
+
from trilogy.parsing.common import arbitrary_to_concept
|
|
1515
|
+
|
|
1516
|
+
new = arbitrary_to_concept(
|
|
1517
|
+
arg,
|
|
1518
|
+
environment=self.environment,
|
|
1519
|
+
)
|
|
1520
|
+
built = self.build(new)
|
|
1521
|
+
self.local_concepts[new.address] = built
|
|
1522
|
+
return new, built
|
|
1523
|
+
|
|
1499
1524
|
@build.register
|
|
1500
1525
|
def _(self, base: None) -> None:
|
|
1501
1526
|
return base
|
|
1502
1527
|
|
|
1503
1528
|
@build.register
|
|
1504
1529
|
def _(self, base: Function) -> BuildFunction | BuildAggregateWrapper:
|
|
1505
|
-
from trilogy.parsing.common import arbitrary_to_concept
|
|
1506
1530
|
|
|
1507
1531
|
raw_args: list[Concept | FuncArgs] = []
|
|
1508
1532
|
for arg in base.arguments:
|
|
1509
1533
|
# to do proper discovery, we need to inject virtual intermediate ocncepts
|
|
1510
1534
|
if isinstance(arg, (AggregateWrapper, FilterItem, WindowItem)):
|
|
1511
|
-
narg =
|
|
1512
|
-
arg,
|
|
1513
|
-
environment=self.environment,
|
|
1514
|
-
)
|
|
1535
|
+
narg, _ = self.instantiate_concept(arg)
|
|
1515
1536
|
raw_args.append(narg)
|
|
1516
1537
|
else:
|
|
1517
1538
|
raw_args.append(arg)
|
|
@@ -1532,24 +1553,16 @@ class Factory:
|
|
|
1532
1553
|
for x in arguments:
|
|
1533
1554
|
if isinstance(x, (ConceptRef, Concept)):
|
|
1534
1555
|
final_args.append(x)
|
|
1535
|
-
elif isinstance(x, (AggregateWrapper, FilterItem, WindowItem)):
|
|
1536
|
-
newx = arbitrary_to_concept(
|
|
1537
|
-
x,
|
|
1538
|
-
environment=self.environment,
|
|
1539
|
-
)
|
|
1540
|
-
final_args.append(newx)
|
|
1541
1556
|
else:
|
|
1542
1557
|
# constants, etc, can be ignored for group
|
|
1543
1558
|
continue
|
|
1544
|
-
|
|
1559
|
+
_, rval = self.instantiate_concept(
|
|
1545
1560
|
AggregateWrapper(
|
|
1546
1561
|
function=group_base.lineage.function,
|
|
1547
1562
|
by=final_args,
|
|
1548
|
-
)
|
|
1549
|
-
environment=self.environment,
|
|
1563
|
+
)
|
|
1550
1564
|
)
|
|
1551
1565
|
|
|
1552
|
-
rval = self.build(group_base)
|
|
1553
1566
|
return BuildFunction.model_construct(
|
|
1554
1567
|
operator=base.operator,
|
|
1555
1568
|
arguments=[rval, *[self.build(c) for c in raw_args[1:]]],
|
|
@@ -1580,20 +1593,13 @@ class Factory:
|
|
|
1580
1593
|
|
|
1581
1594
|
@build.register
|
|
1582
1595
|
def _(self, base: CaseWhen) -> BuildCaseWhen:
|
|
1583
|
-
from trilogy.parsing.common import arbitrary_to_concept
|
|
1584
1596
|
|
|
1585
1597
|
comparison = base.comparison
|
|
1586
1598
|
if isinstance(comparison, (AggregateWrapper, FilterItem, WindowItem)):
|
|
1587
|
-
comparison =
|
|
1588
|
-
comparison,
|
|
1589
|
-
environment=self.environment,
|
|
1590
|
-
)
|
|
1599
|
+
comparison, _ = self.instantiate_concept(comparison)
|
|
1591
1600
|
expr: Concept | FuncArgs = base.expr
|
|
1592
1601
|
if isinstance(expr, (AggregateWrapper, FilterItem, WindowItem)):
|
|
1593
|
-
expr =
|
|
1594
|
-
expr,
|
|
1595
|
-
environment=self.environment,
|
|
1596
|
-
)
|
|
1602
|
+
expr, _ = self.instantiate_concept(expr)
|
|
1597
1603
|
return BuildCaseWhen.model_construct(
|
|
1598
1604
|
comparison=self.build(comparison),
|
|
1599
1605
|
expr=self.build(expr),
|
|
@@ -1615,6 +1621,7 @@ class Factory:
|
|
|
1615
1621
|
else:
|
|
1616
1622
|
build_lineage = None
|
|
1617
1623
|
derivation = Concept.calculate_derivation(build_lineage, base.purpose)
|
|
1624
|
+
|
|
1618
1625
|
granularity = Concept.calculate_granularity(
|
|
1619
1626
|
derivation, final_grain, build_lineage
|
|
1620
1627
|
)
|
|
@@ -1675,16 +1682,12 @@ class Factory:
|
|
|
1675
1682
|
|
|
1676
1683
|
@build.register
|
|
1677
1684
|
def _(self, base: OrderItem) -> BuildOrderItem:
|
|
1678
|
-
from trilogy.parsing.common import arbitrary_to_concept
|
|
1679
1685
|
|
|
1680
1686
|
bexpr: Any
|
|
1681
1687
|
if isinstance(base.expr, (AggregateWrapper, WindowItem, FilterItem)) or (
|
|
1682
1688
|
isinstance(base.expr, Function) and base.expr.operator == FunctionType.GROUP
|
|
1683
1689
|
):
|
|
1684
|
-
bexpr =
|
|
1685
|
-
base.expr,
|
|
1686
|
-
environment=self.environment,
|
|
1687
|
-
)
|
|
1690
|
+
bexpr, _ = self.instantiate_concept(base.expr)
|
|
1688
1691
|
else:
|
|
1689
1692
|
bexpr = base.expr
|
|
1690
1693
|
return BuildOrderItem.model_construct(
|
|
@@ -1707,15 +1710,10 @@ class Factory:
|
|
|
1707
1710
|
|
|
1708
1711
|
@build.register
|
|
1709
1712
|
def _(self, base: WindowItem) -> BuildWindowItem:
|
|
1710
|
-
# to do proper discovery, we need to inject virtual intermediate ocncepts
|
|
1711
|
-
from trilogy.parsing.common import arbitrary_to_concept
|
|
1712
1713
|
|
|
1713
1714
|
content: Concept | FuncArgs = base.content
|
|
1714
1715
|
if isinstance(content, (AggregateWrapper, FilterItem, WindowItem)):
|
|
1715
|
-
content =
|
|
1716
|
-
content,
|
|
1717
|
-
environment=self.environment,
|
|
1718
|
-
)
|
|
1716
|
+
content, _ = self.instantiate_concept(content)
|
|
1719
1717
|
final_by = []
|
|
1720
1718
|
for x in base.order_by:
|
|
1721
1719
|
if (
|
|
@@ -1743,30 +1741,26 @@ class Factory:
|
|
|
1743
1741
|
|
|
1744
1742
|
@build.register
|
|
1745
1743
|
def _(self, base: SubselectComparison) -> BuildSubselectComparison:
|
|
1744
|
+
right: Any = base.right
|
|
1745
|
+
if isinstance(base.right, (AggregateWrapper, WindowItem, FilterItem, Function)):
|
|
1746
|
+
right_c, _ = self.instantiate_concept(base.right)
|
|
1747
|
+
right = right_c
|
|
1746
1748
|
return BuildSubselectComparison.model_construct(
|
|
1747
|
-
left=
|
|
1748
|
-
right=
|
|
1749
|
+
left=self.build(base.left),
|
|
1750
|
+
right=self.build(right),
|
|
1749
1751
|
operator=base.operator,
|
|
1750
1752
|
)
|
|
1751
1753
|
|
|
1752
1754
|
@build.register
|
|
1753
1755
|
def _(self, base: Comparison) -> BuildComparison:
|
|
1754
|
-
from trilogy.parsing.common import arbitrary_to_concept
|
|
1755
1756
|
|
|
1756
1757
|
left = base.left
|
|
1757
1758
|
if isinstance(left, (AggregateWrapper, WindowItem, FilterItem)):
|
|
1758
|
-
left_c =
|
|
1759
|
-
left,
|
|
1760
|
-
environment=self.environment,
|
|
1761
|
-
)
|
|
1759
|
+
left_c, _ = self.instantiate_concept(left)
|
|
1762
1760
|
left = left_c # type: ignore
|
|
1763
1761
|
right = base.right
|
|
1764
1762
|
if isinstance(right, (AggregateWrapper, WindowItem, FilterItem)):
|
|
1765
|
-
right_c =
|
|
1766
|
-
right,
|
|
1767
|
-
environment=self.environment,
|
|
1768
|
-
)
|
|
1769
|
-
|
|
1763
|
+
right_c, _ = self.instantiate_concept(right)
|
|
1770
1764
|
right = right_c # type: ignore
|
|
1771
1765
|
return BuildComparison.model_construct(
|
|
1772
1766
|
left=(self.build(left)),
|
|
@@ -1826,6 +1820,13 @@ class Factory:
|
|
|
1826
1820
|
|
|
1827
1821
|
@build.register
|
|
1828
1822
|
def _(self, base: FilterItem) -> BuildFilterItem:
|
|
1823
|
+
if isinstance(
|
|
1824
|
+
base.content, (Function, AggregateWrapper, WindowItem, FilterItem)
|
|
1825
|
+
):
|
|
1826
|
+
_, built = self.instantiate_concept(base.content)
|
|
1827
|
+
return BuildFilterItem.model_construct(
|
|
1828
|
+
content=built, where=self.build(base.where)
|
|
1829
|
+
)
|
|
1829
1830
|
return BuildFilterItem.model_construct(
|
|
1830
1831
|
content=self.build(base.content), where=self.build(base.where)
|
|
1831
1832
|
)
|
|
@@ -1969,6 +1970,10 @@ class Factory:
|
|
|
1969
1970
|
new.datasources[k] = self.build(d)
|
|
1970
1971
|
for k, a in base.alias_origin_lookup.items():
|
|
1971
1972
|
new.alias_origin_lookup[k] = self.build(a)
|
|
1973
|
+
# add in anything that was built as a side-effect
|
|
1974
|
+
for bk, bv in self.local_concepts.items():
|
|
1975
|
+
if bk not in new.concepts:
|
|
1976
|
+
new.concepts[bk] = bv
|
|
1972
1977
|
new.gen_concept_list_caches()
|
|
1973
1978
|
return new
|
|
1974
1979
|
|
|
@@ -748,6 +748,7 @@ def search_concepts(
|
|
|
748
748
|
accept_partial: bool = False,
|
|
749
749
|
conditions: BuildWhereClause | None = None,
|
|
750
750
|
) -> StrategyNode | None:
|
|
751
|
+
logger.error(f"starting search for {mandatory_list}")
|
|
751
752
|
hist = history.get_history(
|
|
752
753
|
search=mandatory_list, accept_partial=accept_partial, conditions=conditions
|
|
753
754
|
)
|
|
@@ -1094,6 +1095,7 @@ def _search_concepts(
|
|
|
1094
1095
|
logger.error(
|
|
1095
1096
|
f"{depth_to_prefix(depth)}{LOGGER_PREFIX} Could not resolve concepts {[c.address for c in mandatory_list]}, network outcome was {complete}, missing {all_mandatory - found},"
|
|
1096
1097
|
)
|
|
1098
|
+
|
|
1097
1099
|
return None
|
|
1098
1100
|
|
|
1099
1101
|
|
|
@@ -178,7 +178,7 @@ def gen_enrichment_node(
|
|
|
178
178
|
for x in extra_required
|
|
179
179
|
):
|
|
180
180
|
log_lambda(
|
|
181
|
-
f"{str(type(base_node).__name__)} returning property optimized enrichment node"
|
|
181
|
+
f"{str(type(base_node).__name__)} returning property optimized enrichment node for {extra_required[0].keys}"
|
|
182
182
|
)
|
|
183
183
|
return gen_property_enrichment_node(
|
|
184
184
|
base_node,
|
{pytrilogy-0.0.3.43 → pytrilogy-0.0.3.45}/trilogy/core/processing/node_generators/window_node.py
RENAMED
|
@@ -32,7 +32,9 @@ def resolve_window_parent_concepts(
|
|
|
32
32
|
if concept.lineage.order_by:
|
|
33
33
|
for item in concept.lineage.order_by:
|
|
34
34
|
base += item.concept_arguments
|
|
35
|
-
|
|
35
|
+
if concept.grain:
|
|
36
|
+
for gitem in concept.grain.components:
|
|
37
|
+
base.append(environment.concepts[gitem])
|
|
36
38
|
return concept.lineage.content, unique(base, "address")
|
|
37
39
|
|
|
38
40
|
|
|
@@ -131,20 +133,24 @@ def gen_window_node(
|
|
|
131
133
|
)
|
|
132
134
|
_window_node.rebuild_cache()
|
|
133
135
|
_window_node.resolve()
|
|
136
|
+
|
|
134
137
|
window_node = StrategyNode(
|
|
135
138
|
input_concepts=[concept] + additional_outputs + parent_concepts + targets,
|
|
136
139
|
output_concepts=[concept] + additional_outputs + parent_concepts + targets,
|
|
137
140
|
environment=environment,
|
|
138
141
|
parents=[_window_node],
|
|
139
142
|
preexisting_conditions=conditions.conditional if conditions else None,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
+
grain=BuildGrain.from_concepts(
|
|
144
|
+
concepts=[concept] + additional_outputs + parent_concepts + targets,
|
|
145
|
+
environment=environment,
|
|
146
|
+
),
|
|
143
147
|
)
|
|
144
148
|
if not non_equivalent_optional:
|
|
145
149
|
logger.info(
|
|
146
150
|
f"{padding(depth)}{LOGGER_PREFIX} no optional concepts, returning window node"
|
|
147
151
|
)
|
|
152
|
+
# prune outputs if we don't need join keys
|
|
153
|
+
window_node.set_output_concepts([concept] + additional_outputs + targets)
|
|
148
154
|
return window_node
|
|
149
155
|
|
|
150
156
|
missing_optional = [
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from pydantic import BaseModel, ConfigDict, Field
|
|
2
2
|
|
|
3
|
+
from trilogy.core.exceptions import UnresolvableQueryException
|
|
3
4
|
from trilogy.core.models.build import BuildConcept, BuildWhereClause
|
|
4
5
|
from trilogy.core.models.build_environment import BuildEnvironment
|
|
5
6
|
from trilogy.core.models.environment import Environment
|
|
@@ -18,7 +19,7 @@ class History(BaseModel):
|
|
|
18
19
|
base_environment: Environment
|
|
19
20
|
history: dict[str, StrategyNode | None] = Field(default_factory=dict)
|
|
20
21
|
select_history: dict[str, StrategyNode | None] = Field(default_factory=dict)
|
|
21
|
-
started:
|
|
22
|
+
started: dict[str, int] = Field(default_factory=dict)
|
|
22
23
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
23
24
|
|
|
24
25
|
def _concepts_to_lookup(
|
|
@@ -27,13 +28,10 @@ class History(BaseModel):
|
|
|
27
28
|
accept_partial: bool,
|
|
28
29
|
conditions: BuildWhereClause | None = None,
|
|
29
30
|
) -> str:
|
|
31
|
+
base = sorted([c.address for c in search])
|
|
30
32
|
if conditions:
|
|
31
|
-
return (
|
|
32
|
-
|
|
33
|
-
+ str(accept_partial)
|
|
34
|
-
+ str(conditions)
|
|
35
|
-
)
|
|
36
|
-
return "-".join([c.address for c in search]) + str(accept_partial)
|
|
33
|
+
return "-".join(base) + str(accept_partial) + str(conditions)
|
|
34
|
+
return "-".join(base) + str(accept_partial)
|
|
37
35
|
|
|
38
36
|
def search_to_history(
|
|
39
37
|
self,
|
|
@@ -80,13 +78,19 @@ class History(BaseModel):
|
|
|
80
78
|
accept_partial: bool = False,
|
|
81
79
|
conditions: BuildWhereClause | None = None,
|
|
82
80
|
):
|
|
83
|
-
self.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
conditions=conditions,
|
|
88
|
-
)
|
|
81
|
+
key = self._concepts_to_lookup(
|
|
82
|
+
search,
|
|
83
|
+
accept_partial=accept_partial,
|
|
84
|
+
conditions=conditions,
|
|
89
85
|
)
|
|
86
|
+
if key in self.started:
|
|
87
|
+
self.started[key] += 1
|
|
88
|
+
else:
|
|
89
|
+
self.started[key] = 1
|
|
90
|
+
if self.started[key] > 5:
|
|
91
|
+
raise UnresolvableQueryException(
|
|
92
|
+
f"Was unable to resolve datasources to serve this query from model; unresolvable set was {search}. You may be querying unrelated concepts."
|
|
93
|
+
)
|
|
90
94
|
|
|
91
95
|
def log_end(
|
|
92
96
|
self,
|
|
@@ -94,13 +98,13 @@ class History(BaseModel):
|
|
|
94
98
|
accept_partial: bool = False,
|
|
95
99
|
conditions: BuildWhereClause | None = None,
|
|
96
100
|
):
|
|
97
|
-
self.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
conditions=conditions,
|
|
102
|
-
)
|
|
101
|
+
key = self._concepts_to_lookup(
|
|
102
|
+
search,
|
|
103
|
+
accept_partial=accept_partial,
|
|
104
|
+
conditions=conditions,
|
|
103
105
|
)
|
|
106
|
+
if key in self.started:
|
|
107
|
+
del self.started[key]
|
|
104
108
|
|
|
105
109
|
def check_started(
|
|
106
110
|
self,
|
|
@@ -458,7 +458,25 @@ def filter_item_to_concept(
|
|
|
458
458
|
metadata: Metadata | None = None,
|
|
459
459
|
) -> Concept:
|
|
460
460
|
fmetadata = metadata or Metadata()
|
|
461
|
-
|
|
461
|
+
if isinstance(parent.content, ConceptRef):
|
|
462
|
+
cparent = environment.concepts[parent.content.address]
|
|
463
|
+
elif isinstance(
|
|
464
|
+
parent.content,
|
|
465
|
+
(
|
|
466
|
+
FilterItem,
|
|
467
|
+
AggregateWrapper,
|
|
468
|
+
FunctionCallWrapper,
|
|
469
|
+
WindowItem,
|
|
470
|
+
Function,
|
|
471
|
+
ListWrapper,
|
|
472
|
+
MapWrapper,
|
|
473
|
+
),
|
|
474
|
+
):
|
|
475
|
+
cparent = arbitrary_to_concept(parent.content, environment, namespace=namespace)
|
|
476
|
+
else:
|
|
477
|
+
raise NotImplementedError(
|
|
478
|
+
f"Filter item with non ref content {parent.content} not yet supported"
|
|
479
|
+
)
|
|
462
480
|
modifiers = get_upstream_modifiers(
|
|
463
481
|
cparent.concept_arguments, environment=environment
|
|
464
482
|
)
|
|
@@ -494,24 +512,6 @@ def window_item_to_concept(
|
|
|
494
512
|
metadata: Metadata | None = None,
|
|
495
513
|
) -> Concept:
|
|
496
514
|
fmetadata = metadata or Metadata()
|
|
497
|
-
# if isinstance(
|
|
498
|
-
# parent.content,
|
|
499
|
-
# (
|
|
500
|
-
# AggregateWrapper
|
|
501
|
-
# | FunctionCallWrapper
|
|
502
|
-
# | WindowItem
|
|
503
|
-
# | FilterItem
|
|
504
|
-
# | Function
|
|
505
|
-
# | ListWrapper
|
|
506
|
-
# | MapWrapper
|
|
507
|
-
# ),
|
|
508
|
-
# ):
|
|
509
|
-
# new_parent = arbitrary_to_concept(
|
|
510
|
-
# parent.content, environment=environment, namespace=namespace
|
|
511
|
-
# )
|
|
512
|
-
# environment.add_concept(new_parent)
|
|
513
|
-
# parent = parent.model_copy(update={"content": new_parent.reference})
|
|
514
|
-
|
|
515
515
|
if not isinstance(parent.content, ConceptRef):
|
|
516
516
|
raise NotImplementedError(
|
|
517
517
|
f"Window function wiht non ref content {parent.content} not yet supported"
|
|
@@ -523,16 +523,26 @@ def window_item_to_concept(
|
|
|
523
523
|
local_purpose, keys = get_purpose_and_keys(None, (bcontent,), environment)
|
|
524
524
|
else:
|
|
525
525
|
local_purpose = Purpose.PROPERTY
|
|
526
|
-
keys =
|
|
527
|
-
bcontent.address,
|
|
528
|
-
|
|
526
|
+
keys = Grain.from_concepts(
|
|
527
|
+
[bcontent.address] + [y.address for y in parent.over], environment
|
|
528
|
+
).components
|
|
529
529
|
|
|
530
|
+
# when including the order by in discovery grain
|
|
530
531
|
if parent.order_by:
|
|
531
532
|
grain_components = parent.over + [bcontent.output]
|
|
532
533
|
for item in parent.order_by:
|
|
533
|
-
|
|
534
|
+
# confirm that it's not just an aggregate at the grain of the stuff we're already keying of of
|
|
535
|
+
# in which case we can ignore contributions
|
|
536
|
+
if (
|
|
537
|
+
isinstance(item.expr, AggregateWrapper)
|
|
538
|
+
and set([x.address for x in item.expr.by]) == keys
|
|
539
|
+
):
|
|
540
|
+
continue
|
|
541
|
+
else:
|
|
542
|
+
grain_components += item.concept_arguments
|
|
534
543
|
else:
|
|
535
544
|
grain_components = parent.over + [bcontent.output]
|
|
545
|
+
|
|
536
546
|
final_grain = Grain.from_concepts(grain_components, environment)
|
|
537
547
|
modifiers = get_upstream_modifiers(bcontent.concept_arguments, environment)
|
|
538
548
|
datatype = parent.content.datatype
|
|
@@ -651,7 +661,9 @@ def rowset_concept(
|
|
|
651
661
|
orig_concept = environment.concepts[orig_address.address]
|
|
652
662
|
name = orig_concept.name
|
|
653
663
|
if isinstance(orig_concept.lineage, FilterItem):
|
|
654
|
-
if orig_concept.lineage.where == rowset.select.where_clause
|
|
664
|
+
if orig_concept.lineage.where == rowset.select.where_clause and isinstance(
|
|
665
|
+
orig_concept.lineage.content, (ConceptRef, Concept)
|
|
666
|
+
):
|
|
655
667
|
name = environment.concepts[orig_concept.lineage.content.address].name
|
|
656
668
|
base_namespace = (
|
|
657
669
|
f"{rowset.name}.{orig_concept.namespace}"
|
|
@@ -761,7 +773,10 @@ def arbitrary_to_concept(
|
|
|
761
773
|
)
|
|
762
774
|
elif isinstance(parent, FilterItem):
|
|
763
775
|
if not name:
|
|
764
|
-
|
|
776
|
+
if isinstance(parent.content, ConceptRef):
|
|
777
|
+
name = f"{VIRTUAL_CONCEPT_PREFIX}_filter_{parent.content.name}_{string_to_hash(str(parent))}"
|
|
778
|
+
else:
|
|
779
|
+
name = f"{VIRTUAL_CONCEPT_PREFIX}_filter_{string_to_hash(str(parent))}"
|
|
765
780
|
return filter_item_to_concept(
|
|
766
781
|
parent,
|
|
767
782
|
name,
|