pytrilogy 0.0.3.92__tar.gz → 0.0.3.94__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.92/pytrilogy.egg-info → pytrilogy-0.0.3.94}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94/pytrilogy.egg-info}/PKG-INFO +1 -1
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_discovery_nodes.py +1 -1
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_parsing.py +2 -3
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_query_processing.py +1 -1
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/env_processor.py +4 -2
- pytrilogy-0.0.3.94/trilogy/core/graph_models.py +132 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/models/author.py +17 -26
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/models/build.py +141 -151
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/models/build_environment.py +2 -6
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/models/execute.py +3 -3
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/group_node.py +3 -7
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/node_merge_node.py +30 -28
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +25 -11
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/select_merge_node.py +66 -80
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/parsing/parse_engine.py +1 -1
- pytrilogy-0.0.3.92/trilogy/core/graph_models.py +0 -113
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/LICENSE.md +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/README.md +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/pyproject.toml +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/pytrilogy.egg-info/SOURCES.txt +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/setup.cfg +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/setup.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_enums.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_execute_models.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_executor.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_failure.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_functions.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_models.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_parse_engine.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_parsing_failures.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_query_render.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_select.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_show.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_typing.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_user_functions.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/authoring/__init__.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/constants.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/enums.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/functions.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/models/__init__.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/models/core.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/models/datasource.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/models/environment.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/concept_strategies_v3.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/discovery_loop.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/discovery_node_factory.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/discovery_utility.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/discovery_validation.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/constant_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/recursive_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/union_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/node_generators/window_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/nodes/recursive_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/nodes/union_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/statements/__init__.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/statements/author.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/statements/build.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/statements/common.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/statements/execute.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/core/utility.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/dialect/base.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/dialect/common.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/dialect/dataframe.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/dialect/duckdb.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/executor.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/parsing/common.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/parsing/render.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/parsing/trilogy.lark +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/render.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/std/__init__.py +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/std/date.preql +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/std/display.preql +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/std/geography.preql +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/std/money.preql +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/std/net.preql +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/std/ranking.preql +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/std/report.preql +0 -0
- {pytrilogy-0.0.3.92 → pytrilogy-0.0.3.94}/trilogy/utility.py +0 -0
|
@@ -67,7 +67,7 @@ def test_group_node_property_all(test_environment: Environment, test_environment
|
|
|
67
67
|
sum_name_length = test_environment.concepts["category_name_length_sum"]
|
|
68
68
|
all_rows = test_environment.concepts[f"{INTERNAL_NAMESPACE}.{ALL_ROWS_CONCEPT}"]
|
|
69
69
|
sum_name_length_all_rows = sum_name_length.with_grain(
|
|
70
|
-
BuildGrain(components=
|
|
70
|
+
BuildGrain(components={all_rows.address})
|
|
71
71
|
)
|
|
72
72
|
group_node = gen_group_node(
|
|
73
73
|
sum_name_length_all_rows,
|
|
@@ -5,7 +5,6 @@ from trilogy.core.functions import argument_to_purpose, function_args_to_output_
|
|
|
5
5
|
from trilogy.core.models.author import (
|
|
6
6
|
Comparison,
|
|
7
7
|
Conditional,
|
|
8
|
-
ListWrapper,
|
|
9
8
|
SubselectComparison,
|
|
10
9
|
)
|
|
11
10
|
from trilogy.core.models.build import BuildComparison
|
|
@@ -61,7 +60,7 @@ def test_not_in():
|
|
|
61
60
|
_, parsed = parse_text(
|
|
62
61
|
"const order_id <- 4; SELECT order_id WHERE order_id NOT IN (1,2,3);"
|
|
63
62
|
)
|
|
64
|
-
query:
|
|
63
|
+
query: SelectStatement = parsed[-1]
|
|
65
64
|
right = query.where_clause.conditional.right
|
|
66
65
|
assert isinstance(right, TupleWrapper), type(right)
|
|
67
66
|
assert right[0] == 1
|
|
@@ -75,7 +74,7 @@ def test_datetime_lit_rendering():
|
|
|
75
74
|
from datetime import datetime
|
|
76
75
|
|
|
77
76
|
now = datetime.now()
|
|
78
|
-
wrapper =
|
|
77
|
+
wrapper = TupleWrapper(
|
|
79
78
|
(now,),
|
|
80
79
|
type=DataType.DATETIME,
|
|
81
80
|
)
|
|
@@ -135,7 +135,7 @@ def test_basic_aggregate(test_environment: Environment, test_environment_graph):
|
|
|
135
135
|
)
|
|
136
136
|
datasource = datasource.resolve()
|
|
137
137
|
assert isinstance(datasource, QueryDatasource)
|
|
138
|
-
assert datasource.grain == BuildGrain(components=
|
|
138
|
+
assert datasource.grain == BuildGrain(components={product.address})
|
|
139
139
|
|
|
140
140
|
|
|
141
141
|
def test_join_aggregate(test_environment: Environment, test_environment_graph):
|
|
@@ -44,8 +44,10 @@ def add_concept(
|
|
|
44
44
|
continue
|
|
45
45
|
if pseudonym_node.split("@")[0] == node_name.split("@")[0]:
|
|
46
46
|
continue
|
|
47
|
-
g.add_edge(pseudonym_node, node_name
|
|
48
|
-
g.add_edge(node_name, pseudonym_node
|
|
47
|
+
g.add_edge(pseudonym_node, node_name)
|
|
48
|
+
g.add_edge(node_name, pseudonym_node)
|
|
49
|
+
g.pseudonyms.add((pseudonym_node, node_name))
|
|
50
|
+
g.pseudonyms.add((node_name, pseudonym_node))
|
|
49
51
|
add_concept(pseudonym, g, concept_mapping, default_concept_graph, seen)
|
|
50
52
|
|
|
51
53
|
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
|
|
3
|
+
import networkx as nx
|
|
4
|
+
|
|
5
|
+
from trilogy.core.models.build import BuildConcept, BuildDatasource, BuildWhereClause
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_graph_exact_match(
|
|
9
|
+
g: Union[nx.DiGraph, "ReferenceGraph"],
|
|
10
|
+
accept_partial: bool,
|
|
11
|
+
conditions: BuildWhereClause | None,
|
|
12
|
+
) -> set[str]:
|
|
13
|
+
exact: set[str] = set()
|
|
14
|
+
for node, ds in g.datasources.items():
|
|
15
|
+
if isinstance(ds, list):
|
|
16
|
+
exact.add(node)
|
|
17
|
+
continue
|
|
18
|
+
|
|
19
|
+
if not conditions and not ds.non_partial_for:
|
|
20
|
+
exact.add(node)
|
|
21
|
+
continue
|
|
22
|
+
elif not conditions and accept_partial and ds.non_partial_for:
|
|
23
|
+
exact.add(node)
|
|
24
|
+
continue
|
|
25
|
+
elif conditions:
|
|
26
|
+
if not ds.non_partial_for:
|
|
27
|
+
continue
|
|
28
|
+
if ds.non_partial_for and conditions == ds.non_partial_for:
|
|
29
|
+
exact.add(node)
|
|
30
|
+
continue
|
|
31
|
+
else:
|
|
32
|
+
continue
|
|
33
|
+
|
|
34
|
+
return exact
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def prune_sources_for_conditions(
|
|
38
|
+
g: "ReferenceGraph",
|
|
39
|
+
accept_partial: bool,
|
|
40
|
+
conditions: BuildWhereClause | None,
|
|
41
|
+
):
|
|
42
|
+
complete = get_graph_exact_match(g, accept_partial, conditions)
|
|
43
|
+
to_remove = []
|
|
44
|
+
for node in g.datasources:
|
|
45
|
+
if node not in complete:
|
|
46
|
+
to_remove.append(node)
|
|
47
|
+
|
|
48
|
+
for node in to_remove:
|
|
49
|
+
g.remove_node(node)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def concept_to_node(input: BuildConcept) -> str:
|
|
53
|
+
# if input.purpose == Purpose.METRIC:
|
|
54
|
+
# return f"c~{input.namespace}.{input.name}@{input.grain}"
|
|
55
|
+
return f"c~{input.address}@{input.grain.str_no_condition}"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def datasource_to_node(input: BuildDatasource) -> str:
|
|
59
|
+
# if isinstance(input, JoinedDataSource):
|
|
60
|
+
# return "ds~join~" + ",".join(
|
|
61
|
+
# [datasource_to_node(sub) for sub in input.datasources]
|
|
62
|
+
# )
|
|
63
|
+
return f"ds~{input.identifier}"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class ReferenceGraph(nx.DiGraph):
|
|
67
|
+
def __init__(self, *args, **kwargs):
|
|
68
|
+
super().__init__(*args, **kwargs)
|
|
69
|
+
self.concepts: dict[str, BuildConcept] = {}
|
|
70
|
+
self.datasources: dict[str, BuildDatasource] = {}
|
|
71
|
+
self.pseudonyms: set[tuple[str, str]] = set()
|
|
72
|
+
|
|
73
|
+
def copy(self):
|
|
74
|
+
g = ReferenceGraph()
|
|
75
|
+
g.concepts = self.concepts.copy()
|
|
76
|
+
g.datasources = self.datasources.copy()
|
|
77
|
+
g.pseudonyms = {*self.pseudonyms}
|
|
78
|
+
# g.add_nodes_from(self.nodes(data=True))
|
|
79
|
+
for node in self.nodes:
|
|
80
|
+
g.add_node(node, fast=True)
|
|
81
|
+
for edge in self.edges:
|
|
82
|
+
g.add_edge(edge[0], edge[1], fast=True)
|
|
83
|
+
# g.add_edges_from(self.edges(data=True))
|
|
84
|
+
return g
|
|
85
|
+
|
|
86
|
+
def remove_node(self, n):
|
|
87
|
+
if n in self.concepts:
|
|
88
|
+
del self.concepts[n]
|
|
89
|
+
if n in self.datasources:
|
|
90
|
+
del self.datasources[n]
|
|
91
|
+
super().remove_node(n)
|
|
92
|
+
|
|
93
|
+
def add_node(self, node_for_adding, fast: bool = False, **attr):
|
|
94
|
+
if fast:
|
|
95
|
+
return super().add_node(node_for_adding, **attr)
|
|
96
|
+
if isinstance(node_for_adding, BuildConcept):
|
|
97
|
+
node_name = concept_to_node(node_for_adding)
|
|
98
|
+
self.concepts[node_name] = node_for_adding
|
|
99
|
+
elif isinstance(node_for_adding, BuildDatasource):
|
|
100
|
+
node_name = datasource_to_node(node_for_adding)
|
|
101
|
+
self.datasources[node_name] = node_for_adding
|
|
102
|
+
else:
|
|
103
|
+
node_name = node_for_adding
|
|
104
|
+
if attr.get("datasource"):
|
|
105
|
+
self.datasources[node_name] = attr["datasource"]
|
|
106
|
+
super().add_node(node_name, **attr)
|
|
107
|
+
|
|
108
|
+
def add_edge(self, u_of_edge, v_of_edge, fast: bool = False, **attr):
|
|
109
|
+
if fast:
|
|
110
|
+
return super().add_edge(u_of_edge, v_of_edge, **attr)
|
|
111
|
+
if isinstance(u_of_edge, BuildConcept):
|
|
112
|
+
orig = u_of_edge
|
|
113
|
+
u_of_edge = concept_to_node(u_of_edge)
|
|
114
|
+
if u_of_edge not in self.nodes:
|
|
115
|
+
self.add_node(orig)
|
|
116
|
+
elif isinstance(u_of_edge, BuildDatasource):
|
|
117
|
+
origd = u_of_edge
|
|
118
|
+
u_of_edge = datasource_to_node(u_of_edge)
|
|
119
|
+
if u_of_edge not in self.nodes:
|
|
120
|
+
self.add_node(origd)
|
|
121
|
+
|
|
122
|
+
if isinstance(v_of_edge, BuildConcept):
|
|
123
|
+
orig = v_of_edge
|
|
124
|
+
v_of_edge = concept_to_node(v_of_edge)
|
|
125
|
+
if v_of_edge not in self.nodes:
|
|
126
|
+
self.add_node(orig)
|
|
127
|
+
elif isinstance(v_of_edge, BuildDatasource):
|
|
128
|
+
origd = v_of_edge
|
|
129
|
+
v_of_edge = datasource_to_node(v_of_edge)
|
|
130
|
+
if v_of_edge not in self.nodes:
|
|
131
|
+
self.add_node(origd)
|
|
132
|
+
super().add_edge(u_of_edge, v_of_edge)
|
|
@@ -902,7 +902,11 @@ class Concept(Addressable, DataTyped, ConceptArgs, Mergeable, Namespaced, BaseMo
|
|
|
902
902
|
|
|
903
903
|
@property
|
|
904
904
|
def is_aggregate(self):
|
|
905
|
-
|
|
905
|
+
base = getattr(self, "_is_aggregate", None)
|
|
906
|
+
if base:
|
|
907
|
+
return base
|
|
908
|
+
setattr(self, "_is_aggregate", self.calculate_is_aggregate(self.lineage))
|
|
909
|
+
return self._is_aggregate
|
|
906
910
|
|
|
907
911
|
def with_merge(self, source: Self, target: Self, modifiers: List[Modifier]) -> Self:
|
|
908
912
|
if self.address == source.address:
|
|
@@ -1069,18 +1073,25 @@ class Concept(Addressable, DataTyped, ConceptArgs, Mergeable, Namespaced, BaseMo
|
|
|
1069
1073
|
final_grain = grain if not self.grain.components else self.grain
|
|
1070
1074
|
keys = self.keys
|
|
1071
1075
|
|
|
1072
|
-
if self.is_aggregate and isinstance(new_lineage, Function)
|
|
1076
|
+
if self.is_aggregate and grain.components and isinstance(new_lineage, Function):
|
|
1073
1077
|
grain_components: list[ConceptRef | Concept] = [
|
|
1074
1078
|
environment.concepts[c].reference for c in grain.components
|
|
1075
1079
|
]
|
|
1076
|
-
new_lineage = AggregateWrapper(
|
|
1080
|
+
new_lineage = AggregateWrapper.model_construct(
|
|
1081
|
+
function=new_lineage, by=grain_components
|
|
1082
|
+
)
|
|
1077
1083
|
final_grain = grain
|
|
1078
1084
|
keys = set(grain.components)
|
|
1079
|
-
elif
|
|
1085
|
+
elif (
|
|
1086
|
+
grain
|
|
1087
|
+
and new_lineage
|
|
1088
|
+
and isinstance(new_lineage, AggregateWrapper)
|
|
1089
|
+
and not new_lineage.by
|
|
1090
|
+
):
|
|
1080
1091
|
grain_components = [
|
|
1081
1092
|
environment.concepts[c].reference for c in grain.components
|
|
1082
1093
|
]
|
|
1083
|
-
new_lineage = AggregateWrapper(
|
|
1094
|
+
new_lineage = AggregateWrapper.model_construct(
|
|
1084
1095
|
function=new_lineage.function, by=grain_components
|
|
1085
1096
|
)
|
|
1086
1097
|
final_grain = grain
|
|
@@ -1133,7 +1144,7 @@ class Concept(Addressable, DataTyped, ConceptArgs, Mergeable, Namespaced, BaseMo
|
|
|
1133
1144
|
granularity=self.granularity,
|
|
1134
1145
|
derivation=self.derivation,
|
|
1135
1146
|
lineage=self.lineage,
|
|
1136
|
-
grain=grain if grain else Grain(components=set()),
|
|
1147
|
+
grain=grain if grain else Grain.model_construct(components=set()),
|
|
1137
1148
|
namespace=self.namespace,
|
|
1138
1149
|
keys=self.keys,
|
|
1139
1150
|
modifiers=self.modifiers,
|
|
@@ -1670,15 +1681,6 @@ class Function(DataTyped, ConceptArgs, Mergeable, Namespaced, BaseModel):
|
|
|
1670
1681
|
def datatype(self):
|
|
1671
1682
|
return self.output_datatype
|
|
1672
1683
|
|
|
1673
|
-
@field_validator("output_datatype")
|
|
1674
|
-
@classmethod
|
|
1675
|
-
def parse_output_datatype(cls, v, info: ValidationInfo):
|
|
1676
|
-
values = info.data
|
|
1677
|
-
if values.get("operator") == FunctionType.ATTR_ACCESS:
|
|
1678
|
-
if isinstance(v, StructType):
|
|
1679
|
-
raise SyntaxError
|
|
1680
|
-
return v
|
|
1681
|
-
|
|
1682
1684
|
@field_validator("arguments", mode="before")
|
|
1683
1685
|
@classmethod
|
|
1684
1686
|
def parse_arguments(cls, v, info: ValidationInfo):
|
|
@@ -1845,17 +1847,6 @@ class Function(DataTyped, ConceptArgs, Mergeable, Namespaced, BaseModel):
|
|
|
1845
1847
|
base += get_concept_arguments(arg)
|
|
1846
1848
|
return base
|
|
1847
1849
|
|
|
1848
|
-
@property
|
|
1849
|
-
def output_grain(self):
|
|
1850
|
-
# aggregates have an abstract grain
|
|
1851
|
-
base_grain = Grain(components=[])
|
|
1852
|
-
if self.operator in FunctionClass.AGGREGATE_FUNCTIONS.value:
|
|
1853
|
-
return base_grain
|
|
1854
|
-
# scalars have implicit grain of all arguments
|
|
1855
|
-
for input in self.concept_arguments:
|
|
1856
|
-
base_grain += input.grain
|
|
1857
|
-
return base_grain
|
|
1858
|
-
|
|
1859
1850
|
|
|
1860
1851
|
class FunctionCallWrapper(
|
|
1861
1852
|
DataTyped,
|