pytrilogy 0.0.3.27__tar.gz → 0.0.3.28__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.27/pytrilogy.egg-info → pytrilogy-0.0.3.28}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28/pytrilogy.egg-info}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/models/build.py +11 -1
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/group_node.py +2 -2
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/rowset_node.py +3 -1
- pytrilogy-0.0.3.28/trilogy/core/processing/node_generators/window_node.py +173 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/nodes/window_node.py +12 -1
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/parsing/common.py +8 -1
- pytrilogy-0.0.3.27/trilogy/core/processing/node_generators/window_node.py +0 -105
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/LICENSE.md +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/README.md +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/pyproject.toml +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/pytrilogy.egg-info/SOURCES.txt +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/setup.cfg +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/setup.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_enums.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_executor.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_functions.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_models.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_parse_engine.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_parsing.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_query_render.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_select.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_show.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_typing.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_user_functions.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/authoring/__init__.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/constants.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/enums.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/functions.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/models/__init__.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/models/author.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/models/build_environment.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/models/core.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/models/datasource.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/models/environment.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/models/execute.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/optimizations/inline_constant.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/concept_strategies_v3.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/union_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/nodes/union_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/statements/__init__.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/statements/author.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/statements/build.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/statements/common.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/statements/execute.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/dialect/base.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/dialect/common.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/dialect/dataframe.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/dialect/duckdb.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/executor.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/parsing/parse_engine.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/parsing/render.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/parsing/trilogy.lark +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/render.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/std/__init__.py +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/std/dashboard.preql +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/std/date.preql +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/std/geography.preql +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/std/money.preql +0 -0
- {pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/utility.py +0 -0
|
@@ -1610,8 +1610,18 @@ class Factory:
|
|
|
1610
1610
|
|
|
1611
1611
|
@build.register
|
|
1612
1612
|
def _(self, base: OrderItem) -> BuildOrderItem:
|
|
1613
|
+
from trilogy.parsing.common import arbitrary_to_concept
|
|
1614
|
+
|
|
1615
|
+
bexpr: Any
|
|
1616
|
+
if isinstance(base.expr, AggregateWrapper):
|
|
1617
|
+
bexpr = arbitrary_to_concept(
|
|
1618
|
+
base.expr,
|
|
1619
|
+
environment=self.environment,
|
|
1620
|
+
)
|
|
1621
|
+
else:
|
|
1622
|
+
bexpr = base.expr
|
|
1613
1623
|
return BuildOrderItem.model_construct(
|
|
1614
|
-
expr=(self.build(
|
|
1624
|
+
expr=(self.build(bexpr)),
|
|
1615
1625
|
order=base.order,
|
|
1616
1626
|
)
|
|
1617
1627
|
|
{pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/group_node.py
RENAMED
|
@@ -86,7 +86,7 @@ def gen_group_node(
|
|
|
86
86
|
)
|
|
87
87
|
else:
|
|
88
88
|
logger.info(
|
|
89
|
-
f"{padding(depth)}{LOGGER_PREFIX} cannot include optional agg; mismatched grain {BuildGrain.from_concepts(agg_parents)} vs {BuildGrain.from_concepts(parent_concepts)}"
|
|
89
|
+
f"{padding(depth)}{LOGGER_PREFIX} cannot include optional agg {possible_agg.address}; mismatched grain {BuildGrain.from_concepts(agg_parents)} vs {BuildGrain.from_concepts(parent_concepts)}"
|
|
90
90
|
)
|
|
91
91
|
if parent_concepts:
|
|
92
92
|
logger.info(
|
|
@@ -139,7 +139,7 @@ def gen_group_node(
|
|
|
139
139
|
)
|
|
140
140
|
return group_node
|
|
141
141
|
logger.info(
|
|
142
|
-
f"{padding(depth)}{LOGGER_PREFIX} group node requires enrichment, missing {missing_optional}"
|
|
142
|
+
f"{padding(depth)}{LOGGER_PREFIX} group node for {concept.address} requires enrichment, missing {missing_optional}"
|
|
143
143
|
)
|
|
144
144
|
return gen_enrichment_node(
|
|
145
145
|
group_node,
|
{pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/rowset_node.py
RENAMED
|
@@ -91,7 +91,9 @@ def gen_rowset_node(
|
|
|
91
91
|
and x.derivation != Derivation.ROWSET
|
|
92
92
|
and not any(z in lineage.rowset.derived_concepts for z in x.pseudonyms)
|
|
93
93
|
]
|
|
94
|
-
logger.info(
|
|
94
|
+
logger.info(
|
|
95
|
+
f"{padding(depth)}{LOGGER_PREFIX} hiding {final_hidden} local optional {local_optional}"
|
|
96
|
+
)
|
|
95
97
|
node.hide_output_concepts(final_hidden)
|
|
96
98
|
assert node.resolution_cache
|
|
97
99
|
# assume grain to be output of select
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from trilogy.constants import logger
|
|
4
|
+
from trilogy.core.models.build import (
|
|
5
|
+
BuildConcept,
|
|
6
|
+
BuildGrain,
|
|
7
|
+
BuildWhereClause,
|
|
8
|
+
BuildWindowItem,
|
|
9
|
+
)
|
|
10
|
+
from trilogy.core.models.build_environment import BuildEnvironment
|
|
11
|
+
from trilogy.core.processing.node_generators.common import (
|
|
12
|
+
gen_enrichment_node,
|
|
13
|
+
)
|
|
14
|
+
from trilogy.core.processing.nodes import History, StrategyNode, WindowNode
|
|
15
|
+
from trilogy.core.processing.utility import create_log_lambda, padding
|
|
16
|
+
from trilogy.utility import unique
|
|
17
|
+
|
|
18
|
+
LOGGER_PREFIX = "[GEN_WINDOW_NODE]"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
WINDOW_TYPES = (BuildWindowItem,)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def resolve_window_parent_concepts(
|
|
25
|
+
concept: BuildConcept, environment: BuildEnvironment
|
|
26
|
+
) -> tuple[BuildConcept, List[BuildConcept]]:
|
|
27
|
+
if not isinstance(concept.lineage, WINDOW_TYPES):
|
|
28
|
+
raise ValueError
|
|
29
|
+
base = []
|
|
30
|
+
if concept.lineage.over:
|
|
31
|
+
base += concept.lineage.over
|
|
32
|
+
if concept.lineage.order_by:
|
|
33
|
+
for item in concept.lineage.order_by:
|
|
34
|
+
base += item.concept_arguments
|
|
35
|
+
|
|
36
|
+
return concept.lineage.content, unique(base, "address")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def gen_window_node(
|
|
40
|
+
concept: BuildConcept,
|
|
41
|
+
local_optional: list[BuildConcept],
|
|
42
|
+
environment: BuildEnvironment,
|
|
43
|
+
g,
|
|
44
|
+
depth: int,
|
|
45
|
+
source_concepts,
|
|
46
|
+
history: History,
|
|
47
|
+
conditions: BuildWhereClause | None = None,
|
|
48
|
+
) -> StrategyNode | None:
|
|
49
|
+
base, parent_concepts = resolve_window_parent_concepts(concept, environment)
|
|
50
|
+
logger.info(
|
|
51
|
+
f"{padding(depth)}{LOGGER_PREFIX} generating window node for {concept} with parents {parent_concepts} and optional {local_optional}"
|
|
52
|
+
)
|
|
53
|
+
equivalent_optional = [
|
|
54
|
+
x
|
|
55
|
+
for x in local_optional
|
|
56
|
+
if isinstance(x.lineage, WINDOW_TYPES)
|
|
57
|
+
and resolve_window_parent_concepts(x, environment)[1] == parent_concepts
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
targets = [base]
|
|
61
|
+
# append in keys to get the right grain
|
|
62
|
+
if concept.keys:
|
|
63
|
+
for item in concept.keys:
|
|
64
|
+
targets.append(environment.concepts[item])
|
|
65
|
+
additional_outputs = []
|
|
66
|
+
if equivalent_optional:
|
|
67
|
+
for x in equivalent_optional:
|
|
68
|
+
assert isinstance(x.lineage, WINDOW_TYPES)
|
|
69
|
+
logger.info(
|
|
70
|
+
f"{padding(depth)}{LOGGER_PREFIX} found equivalent optional {x} with parents {resolve_window_parent_concepts(x, environment)[1]}"
|
|
71
|
+
)
|
|
72
|
+
additional_outputs.append(x)
|
|
73
|
+
|
|
74
|
+
grain_equivalents = [
|
|
75
|
+
x for x in local_optional if x.keys and all([key in targets for key in x.keys])
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
for x in grain_equivalents:
|
|
79
|
+
targets.append(x)
|
|
80
|
+
|
|
81
|
+
# finally, the ones we'll need to enrich
|
|
82
|
+
non_equivalent_optional = [x for x in local_optional if x.address not in targets]
|
|
83
|
+
|
|
84
|
+
logger.info(
|
|
85
|
+
f"{padding(depth)}{LOGGER_PREFIX} resolving final parents {parent_concepts + targets}"
|
|
86
|
+
)
|
|
87
|
+
parent_node: StrategyNode = source_concepts(
|
|
88
|
+
mandatory_list=parent_concepts + targets,
|
|
89
|
+
environment=environment,
|
|
90
|
+
g=g,
|
|
91
|
+
depth=depth + 1,
|
|
92
|
+
history=history,
|
|
93
|
+
conditions=conditions,
|
|
94
|
+
)
|
|
95
|
+
if not parent_node:
|
|
96
|
+
logger.info(f"{padding(depth)}{LOGGER_PREFIX} window node parents unresolvable")
|
|
97
|
+
return None
|
|
98
|
+
parent_node.resolve()
|
|
99
|
+
if not all(
|
|
100
|
+
[
|
|
101
|
+
x.address in [y.address for y in parent_node.output_concepts]
|
|
102
|
+
for x in parent_concepts
|
|
103
|
+
]
|
|
104
|
+
):
|
|
105
|
+
missing = [
|
|
106
|
+
x
|
|
107
|
+
for x in parent_concepts
|
|
108
|
+
if x.address not in [y.address for y in parent_node.output_concepts]
|
|
109
|
+
]
|
|
110
|
+
logger.info(
|
|
111
|
+
f"{padding(depth)}{LOGGER_PREFIX} window node parents unresolvable, missing {missing}"
|
|
112
|
+
)
|
|
113
|
+
raise SyntaxError
|
|
114
|
+
_window_node = WindowNode(
|
|
115
|
+
input_concepts=parent_concepts + targets,
|
|
116
|
+
output_concepts=[concept] + additional_outputs + parent_concepts + targets,
|
|
117
|
+
environment=environment,
|
|
118
|
+
parents=[
|
|
119
|
+
parent_node,
|
|
120
|
+
],
|
|
121
|
+
depth=depth,
|
|
122
|
+
preexisting_conditions=conditions.conditional if conditions else None,
|
|
123
|
+
)
|
|
124
|
+
_window_node.rebuild_cache()
|
|
125
|
+
_window_node.resolve()
|
|
126
|
+
window_node = StrategyNode(
|
|
127
|
+
input_concepts=[concept] + additional_outputs + parent_concepts + targets,
|
|
128
|
+
output_concepts=[concept] + additional_outputs + parent_concepts + targets,
|
|
129
|
+
environment=environment,
|
|
130
|
+
parents=[_window_node],
|
|
131
|
+
preexisting_conditions=conditions.conditional if conditions else None,
|
|
132
|
+
# hidden_concepts=[
|
|
133
|
+
# x.address for x in parent_concepts if x.address not in local_optional
|
|
134
|
+
# ],
|
|
135
|
+
)
|
|
136
|
+
if not non_equivalent_optional:
|
|
137
|
+
logger.info(
|
|
138
|
+
f"{padding(depth)}{LOGGER_PREFIX} no optional concepts, returning window node"
|
|
139
|
+
)
|
|
140
|
+
return window_node
|
|
141
|
+
|
|
142
|
+
missing_optional = [
|
|
143
|
+
x.address
|
|
144
|
+
for x in local_optional
|
|
145
|
+
if x.address not in window_node.output_concepts
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
if not missing_optional:
|
|
149
|
+
logger.info(
|
|
150
|
+
f"{padding(depth)}{LOGGER_PREFIX} no extra enrichment needed for window node, has all of {[x.address for x in local_optional]}"
|
|
151
|
+
)
|
|
152
|
+
return window_node
|
|
153
|
+
logger.info(
|
|
154
|
+
f"{padding(depth)}{LOGGER_PREFIX} window node for {concept.address} requires enrichment, missing {missing_optional}, has {[x.address for x in window_node.output_concepts]}"
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
return gen_enrichment_node(
|
|
158
|
+
window_node,
|
|
159
|
+
join_keys=[
|
|
160
|
+
environment.concepts[c]
|
|
161
|
+
for c in BuildGrain.from_concepts(
|
|
162
|
+
concepts=targets, environment=environment
|
|
163
|
+
).components
|
|
164
|
+
],
|
|
165
|
+
local_optional=local_optional,
|
|
166
|
+
environment=environment,
|
|
167
|
+
g=g,
|
|
168
|
+
depth=depth,
|
|
169
|
+
source_concepts=source_concepts,
|
|
170
|
+
log_lambda=create_log_lambda(LOGGER_PREFIX, depth, logger),
|
|
171
|
+
history=history,
|
|
172
|
+
conditions=conditions,
|
|
173
|
+
)
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
from typing import List
|
|
2
2
|
|
|
3
3
|
from trilogy.core.enums import SourceType
|
|
4
|
-
from trilogy.core.models.build import
|
|
4
|
+
from trilogy.core.models.build import (
|
|
5
|
+
BuildComparison,
|
|
6
|
+
BuildConcept,
|
|
7
|
+
BuildConditional,
|
|
8
|
+
BuildOrderBy,
|
|
9
|
+
BuildParenthetical,
|
|
10
|
+
)
|
|
5
11
|
from trilogy.core.models.execute import QueryDatasource
|
|
6
12
|
from trilogy.core.processing.nodes.base_node import StrategyNode
|
|
7
13
|
|
|
@@ -18,6 +24,9 @@ class WindowNode(StrategyNode):
|
|
|
18
24
|
parents: List["StrategyNode"] | None = None,
|
|
19
25
|
depth: int = 0,
|
|
20
26
|
ordering: BuildOrderBy | None = None,
|
|
27
|
+
preexisting_conditions: (
|
|
28
|
+
BuildConditional | BuildComparison | BuildParenthetical | None
|
|
29
|
+
) = None,
|
|
21
30
|
):
|
|
22
31
|
super().__init__(
|
|
23
32
|
input_concepts=input_concepts,
|
|
@@ -27,6 +36,7 @@ class WindowNode(StrategyNode):
|
|
|
27
36
|
parents=parents,
|
|
28
37
|
depth=depth,
|
|
29
38
|
ordering=ordering,
|
|
39
|
+
preexisting_conditions=preexisting_conditions,
|
|
30
40
|
)
|
|
31
41
|
|
|
32
42
|
def _resolve(self) -> QueryDatasource:
|
|
@@ -42,4 +52,5 @@ class WindowNode(StrategyNode):
|
|
|
42
52
|
parents=self.parents,
|
|
43
53
|
depth=self.depth,
|
|
44
54
|
ordering=self.ordering,
|
|
55
|
+
preexisting_conditions=self.preexisting_conditions,
|
|
45
56
|
)
|
|
@@ -417,7 +417,14 @@ def window_item_to_concept(
|
|
|
417
417
|
bcontent = environment.concepts[parent.content.address]
|
|
418
418
|
if isinstance(bcontent, UndefinedConcept):
|
|
419
419
|
return UndefinedConcept(address=f"{namespace}.{name}", metadata=fmetadata)
|
|
420
|
-
|
|
420
|
+
|
|
421
|
+
if bcontent.purpose == Purpose.METRIC:
|
|
422
|
+
local_purpose, keys = get_purpose_and_keys(None, (bcontent,), environment)
|
|
423
|
+
else:
|
|
424
|
+
local_purpose = Purpose.PROPERTY
|
|
425
|
+
keys = {
|
|
426
|
+
bcontent.address,
|
|
427
|
+
}
|
|
421
428
|
|
|
422
429
|
if parent.order_by:
|
|
423
430
|
grain_components = parent.over + [bcontent.output]
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
from typing import List
|
|
2
|
-
|
|
3
|
-
from trilogy.constants import logger
|
|
4
|
-
from trilogy.core.models.build import BuildConcept, BuildWhereClause, BuildWindowItem
|
|
5
|
-
from trilogy.core.models.build_environment import BuildEnvironment
|
|
6
|
-
from trilogy.core.processing.nodes import History, StrategyNode, WindowNode
|
|
7
|
-
from trilogy.core.processing.utility import padding
|
|
8
|
-
from trilogy.utility import unique
|
|
9
|
-
|
|
10
|
-
LOGGER_PREFIX = "[GEN_WINDOW_NODE]"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
WINDOW_TYPES = (BuildWindowItem,)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def resolve_window_parent_concepts(
|
|
17
|
-
concept: BuildConcept, environment: BuildEnvironment
|
|
18
|
-
) -> tuple[BuildConcept, List[BuildConcept]]:
|
|
19
|
-
if not isinstance(concept.lineage, WINDOW_TYPES):
|
|
20
|
-
raise ValueError
|
|
21
|
-
base = []
|
|
22
|
-
if concept.lineage.over:
|
|
23
|
-
base += concept.lineage.over
|
|
24
|
-
if concept.lineage.order_by:
|
|
25
|
-
for item in concept.lineage.order_by:
|
|
26
|
-
base += item.concept_arguments
|
|
27
|
-
return concept.lineage.content, unique(base, "address")
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def gen_window_node(
|
|
31
|
-
concept: BuildConcept,
|
|
32
|
-
local_optional: list[BuildConcept],
|
|
33
|
-
environment: BuildEnvironment,
|
|
34
|
-
g,
|
|
35
|
-
depth: int,
|
|
36
|
-
source_concepts,
|
|
37
|
-
history: History | None = None,
|
|
38
|
-
conditions: BuildWhereClause | None = None,
|
|
39
|
-
) -> StrategyNode | None:
|
|
40
|
-
base, parent_concepts = resolve_window_parent_concepts(concept, environment)
|
|
41
|
-
logger.info(
|
|
42
|
-
f"{padding(depth)}{LOGGER_PREFIX} generating window node for {concept} with parents {parent_concepts}"
|
|
43
|
-
)
|
|
44
|
-
equivalent_optional = [
|
|
45
|
-
x
|
|
46
|
-
for x in local_optional
|
|
47
|
-
if isinstance(x.lineage, WINDOW_TYPES)
|
|
48
|
-
and resolve_window_parent_concepts(x, environment)[1] == parent_concepts
|
|
49
|
-
]
|
|
50
|
-
|
|
51
|
-
non_equivalent_optional = [
|
|
52
|
-
x for x in local_optional if x.address not in equivalent_optional
|
|
53
|
-
]
|
|
54
|
-
targets = [base]
|
|
55
|
-
if equivalent_optional:
|
|
56
|
-
for x in equivalent_optional:
|
|
57
|
-
assert isinstance(x.lineage, WINDOW_TYPES)
|
|
58
|
-
targets.append(x.lineage.content)
|
|
59
|
-
|
|
60
|
-
parent_node: StrategyNode = source_concepts(
|
|
61
|
-
mandatory_list=parent_concepts + targets + non_equivalent_optional,
|
|
62
|
-
environment=environment,
|
|
63
|
-
g=g,
|
|
64
|
-
depth=depth + 1,
|
|
65
|
-
history=history,
|
|
66
|
-
conditions=conditions,
|
|
67
|
-
)
|
|
68
|
-
if not parent_node:
|
|
69
|
-
logger.info(f"{padding(depth)}{LOGGER_PREFIX} window node parents unresolvable")
|
|
70
|
-
return None
|
|
71
|
-
parent_node.resolve()
|
|
72
|
-
if not all(
|
|
73
|
-
[
|
|
74
|
-
x.address in [y.address for y in parent_node.output_concepts]
|
|
75
|
-
for x in parent_concepts
|
|
76
|
-
]
|
|
77
|
-
):
|
|
78
|
-
missing = [
|
|
79
|
-
x
|
|
80
|
-
for x in parent_concepts
|
|
81
|
-
if x.address not in [y.address for y in parent_node.output_concepts]
|
|
82
|
-
]
|
|
83
|
-
logger.info(
|
|
84
|
-
f"{padding(depth)}{LOGGER_PREFIX} window node parents unresolvable, missing {missing}"
|
|
85
|
-
)
|
|
86
|
-
raise SyntaxError
|
|
87
|
-
_window_node = WindowNode(
|
|
88
|
-
input_concepts=parent_concepts + targets + non_equivalent_optional,
|
|
89
|
-
output_concepts=[concept] + parent_concepts + local_optional,
|
|
90
|
-
environment=environment,
|
|
91
|
-
parents=[
|
|
92
|
-
parent_node,
|
|
93
|
-
],
|
|
94
|
-
depth=depth,
|
|
95
|
-
)
|
|
96
|
-
_window_node.rebuild_cache()
|
|
97
|
-
_window_node.resolve()
|
|
98
|
-
window_node = StrategyNode(
|
|
99
|
-
input_concepts=[concept] + local_optional,
|
|
100
|
-
output_concepts=[concept] + local_optional,
|
|
101
|
-
environment=environment,
|
|
102
|
-
parents=[_window_node],
|
|
103
|
-
preexisting_conditions=conditions.conditional if conditions else None,
|
|
104
|
-
)
|
|
105
|
-
return window_node
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/__init__.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/basic_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/filter_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/group_to_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/node_merge_node.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/select_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/synonym_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/union_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.27 → pytrilogy-0.0.3.28}/trilogy/core/processing/node_generators/unnest_node.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|