pytrilogy 0.0.3.20__tar.gz → 0.0.3.22__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.20/pytrilogy.egg-info → pytrilogy-0.0.3.22}/PKG-INFO +3 -2
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22/pytrilogy.egg-info}/PKG-INFO +3 -2
- pytrilogy-0.0.3.22/pytrilogy.egg-info/entry_points.txt +2 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/setup.py +1 -1
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_parsing.py +31 -1
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/constants.py +9 -1
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/models/execute.py +1 -1
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/concept_strategies_v3.py +7 -5
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/statements/author.py +2 -2
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/dialect/base.py +11 -4
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/dialect/common.py +4 -1
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/dialect/config.py +10 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/dialect/enums.py +4 -1
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/executor.py +3 -2
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/parsing/parse_engine.py +23 -4
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/render.py +13 -9
- pytrilogy-0.0.3.20/pytrilogy.egg-info/entry_points.txt +0 -2
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/LICENSE.md +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/README.md +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/pyproject.toml +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/pytrilogy.egg-info/SOURCES.txt +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/setup.cfg +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_datatypes.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_enums.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_executor.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_functions.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_models.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_parse_engine.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_query_render.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_select.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_show.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_typing.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_user_functions.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/authoring/__init__.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/enums.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/functions.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/models/__init__.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/models/author.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/models/build.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/models/build_environment.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/models/core.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/models/datasource.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/models/environment.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/optimization.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/optimizations/__init__.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/optimizations/base_optimization.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/optimizations/inline_constant.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/optimizations/inline_datasource.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/common.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/filter_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/group_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/union_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/window_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/nodes/union_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/statements/__init__.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/statements/build.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/statements/common.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/statements/execute.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/dialect/dataframe.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/dialect/duckdb.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/parsing/common.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/parsing/render.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/parsing/trilogy.lark +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/utility.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: pytrilogy
|
|
3
|
-
Version: 0.0.3.
|
|
3
|
+
Version: 0.0.3.22
|
|
4
4
|
Summary: Declarative, typed query language that compiles to SQL.
|
|
5
5
|
Home-page:
|
|
6
6
|
Author:
|
|
@@ -31,6 +31,7 @@ Dynamic: author-email
|
|
|
31
31
|
Dynamic: classifier
|
|
32
32
|
Dynamic: description
|
|
33
33
|
Dynamic: description-content-type
|
|
34
|
+
Dynamic: license-file
|
|
34
35
|
Dynamic: provides-extra
|
|
35
36
|
Dynamic: requires-dist
|
|
36
37
|
Dynamic: summary
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: pytrilogy
|
|
3
|
-
Version: 0.0.3.
|
|
3
|
+
Version: 0.0.3.22
|
|
4
4
|
Summary: Declarative, typed query language that compiles to SQL.
|
|
5
5
|
Home-page:
|
|
6
6
|
Author:
|
|
@@ -31,6 +31,7 @@ Dynamic: author-email
|
|
|
31
31
|
Dynamic: classifier
|
|
32
32
|
Dynamic: description
|
|
33
33
|
Dynamic: description-content-type
|
|
34
|
+
Dynamic: license-file
|
|
34
35
|
Dynamic: provides-extra
|
|
35
36
|
Dynamic: requires-dist
|
|
36
37
|
Dynamic: summary
|
|
@@ -49,7 +49,7 @@ setuptools.setup(
|
|
|
49
49
|
"snowflake": ["snowflake-sqlalchemy"],
|
|
50
50
|
},
|
|
51
51
|
entry_points={
|
|
52
|
-
"console_scripts": ["trilogy=
|
|
52
|
+
"console_scripts": ["trilogy=trilogy.scripts.trilogy:cli"],
|
|
53
53
|
},
|
|
54
54
|
classifiers=[
|
|
55
55
|
"Programming Language :: Python",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from pytest import raises
|
|
2
2
|
|
|
3
3
|
from trilogy import Dialects
|
|
4
|
-
from trilogy.constants import MagicConstants
|
|
4
|
+
from trilogy.constants import MagicConstants, Parsing
|
|
5
5
|
from trilogy.core.enums import BooleanOperator, ComparisonOperator, Purpose
|
|
6
6
|
from trilogy.core.functions import argument_to_purpose, function_args_to_output_purpose
|
|
7
7
|
from trilogy.core.models.author import Comparison
|
|
@@ -19,6 +19,7 @@ from trilogy.core.statements.author import SelectStatement, ShowStatement
|
|
|
19
19
|
from trilogy.core.statements.execute import ProcessedQuery
|
|
20
20
|
from trilogy.dialect.base import BaseDialect
|
|
21
21
|
from trilogy.parsing.parse_engine import (
|
|
22
|
+
ParseError,
|
|
22
23
|
arg_to_datatype,
|
|
23
24
|
parse_text,
|
|
24
25
|
)
|
|
@@ -704,3 +705,32 @@ key x int;
|
|
|
704
705
|
)
|
|
705
706
|
assert "TYPO" in str(e.value)
|
|
706
707
|
assert 1 == 0
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
def test_concept_shadow_warning():
|
|
711
|
+
x = """
|
|
712
|
+
key scalar int;
|
|
713
|
+
property scalar.int_array list<int>;
|
|
714
|
+
|
|
715
|
+
key split <- unnest(int_array);
|
|
716
|
+
|
|
717
|
+
datasource avalues (
|
|
718
|
+
int_array: int_array,
|
|
719
|
+
scalar: scalar
|
|
720
|
+
)
|
|
721
|
+
grain (scalar)
|
|
722
|
+
query '''(
|
|
723
|
+
select [1,2,3,4] as int_array, 2 as scalar
|
|
724
|
+
union all
|
|
725
|
+
select [5,6,7,8] as int_array, 4 as scalar
|
|
726
|
+
)''';
|
|
727
|
+
|
|
728
|
+
SELECT
|
|
729
|
+
int_array,
|
|
730
|
+
sum(scalar)->scalar
|
|
731
|
+
;
|
|
732
|
+
"""
|
|
733
|
+
with raises(ParseError):
|
|
734
|
+
env, parsed = parse_text(
|
|
735
|
+
x, parse_config=Parsing(strict_name_shadow_enforcement=True)
|
|
736
|
+
)
|
|
@@ -47,6 +47,14 @@ class Rendering:
|
|
|
47
47
|
concise: bool = False
|
|
48
48
|
|
|
49
49
|
|
|
50
|
+
@dataclass
|
|
51
|
+
class Parsing:
|
|
52
|
+
"""Control Parsing"""
|
|
53
|
+
|
|
54
|
+
strict_name_shadow_enforcement: bool = False
|
|
55
|
+
select_as_definition: bool = True
|
|
56
|
+
|
|
57
|
+
|
|
50
58
|
# TODO: support loading from environments
|
|
51
59
|
@dataclass
|
|
52
60
|
class Config:
|
|
@@ -57,7 +65,7 @@ class Config:
|
|
|
57
65
|
comments: Comments = field(default_factory=Comments)
|
|
58
66
|
optimizations: Optimizations = field(default_factory=Optimizations)
|
|
59
67
|
rendering: Rendering = field(default_factory=Rendering)
|
|
60
|
-
|
|
68
|
+
parsing: Parsing = field(default_factory=Parsing)
|
|
61
69
|
|
|
62
70
|
@property
|
|
63
71
|
def show_comments(self) -> bool:
|
|
@@ -787,15 +787,17 @@ def _search_concepts(
|
|
|
787
787
|
)
|
|
788
788
|
# if anything we need to get is in the filter set and it's a computed value
|
|
789
789
|
# we need to get _everything_ in this loop
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
x.derivation not in (Derivation.ROOT, Derivation.CONSTANT)
|
|
790
|
+
required_filters = [
|
|
791
|
+
x
|
|
792
|
+
for x in mandatory_list if x.derivation not in (Derivation.ROOT, Derivation.CONSTANT)
|
|
793
|
+
and not (x.derivation == Derivation.AGGREGATE and x.granularity == Granularity.SINGLE_ROW)
|
|
793
794
|
and x.address in conditions.row_arguments
|
|
794
|
-
for x in mandatory_list
|
|
795
795
|
]
|
|
796
|
+
if any(
|
|
797
|
+
required_filters
|
|
796
798
|
):
|
|
797
799
|
logger.info(
|
|
798
|
-
f"{depth_to_prefix(depth)}{LOGGER_PREFIX} derived condition row
|
|
800
|
+
f"{depth_to_prefix(depth)}{LOGGER_PREFIX} derived condition row inputs {[x.address for x in required_filters]} present in mandatory list, forcing condition evaluation at this level. "
|
|
799
801
|
)
|
|
800
802
|
mandatory_list = completion_mandatory
|
|
801
803
|
must_evaluate_condition_on_this_level_not_push_down = True
|
|
@@ -142,7 +142,7 @@ class SelectStatement(HasUUID, SelectTypeMixin, BaseModel):
|
|
|
142
142
|
if isinstance(x.content.output, UndefinedConcept):
|
|
143
143
|
continue
|
|
144
144
|
if (
|
|
145
|
-
CONFIG.select_as_definition
|
|
145
|
+
CONFIG.parsing.select_as_definition
|
|
146
146
|
and not environment.frozen
|
|
147
147
|
and x.concept.address not in environment.concepts
|
|
148
148
|
):
|
|
@@ -156,7 +156,7 @@ class SelectStatement(HasUUID, SelectTypeMixin, BaseModel):
|
|
|
156
156
|
elif isinstance(x.content, ConceptRef):
|
|
157
157
|
output.local_concepts[x.content.address] = environment.concepts[
|
|
158
158
|
x.content.address
|
|
159
|
-
]
|
|
159
|
+
]
|
|
160
160
|
output.validate_syntax(environment)
|
|
161
161
|
return output
|
|
162
162
|
|
|
@@ -3,7 +3,7 @@ from typing import Any, Callable, Dict, List, Optional, Sequence, Union
|
|
|
3
3
|
|
|
4
4
|
from jinja2 import Template
|
|
5
5
|
|
|
6
|
-
from trilogy.constants import CONFIG, MagicConstants, logger
|
|
6
|
+
from trilogy.constants import CONFIG, MagicConstants, Rendering, logger
|
|
7
7
|
from trilogy.core.enums import (
|
|
8
8
|
DatePart,
|
|
9
9
|
FunctionType,
|
|
@@ -283,6 +283,9 @@ class BaseDialect:
|
|
|
283
283
|
DATATYPE_MAP = DATATYPE_MAP
|
|
284
284
|
UNNEST_MODE = UnnestMode.CROSS_APPLY
|
|
285
285
|
|
|
286
|
+
def __init__(self, rendering: Rendering | None = None):
|
|
287
|
+
self.rendering = rendering or CONFIG.rendering
|
|
288
|
+
|
|
286
289
|
def render_order_item(
|
|
287
290
|
self,
|
|
288
291
|
order_item: BuildOrderItem,
|
|
@@ -416,7 +419,7 @@ class BaseDialect:
|
|
|
416
419
|
elif (
|
|
417
420
|
isinstance(c.lineage, FUNCTION_ITEMS)
|
|
418
421
|
and c.lineage.operator == FunctionType.CONSTANT
|
|
419
|
-
and
|
|
422
|
+
and self.rendering.parameters is True
|
|
420
423
|
and c.datatype.data_type != DataType.MAP
|
|
421
424
|
):
|
|
422
425
|
rval = f":{c.safe_address}"
|
|
@@ -633,7 +636,7 @@ class BaseDialect:
|
|
|
633
636
|
if (
|
|
634
637
|
isinstance(e.lineage, FUNCTION_ITEMS)
|
|
635
638
|
and e.lineage.operator == FunctionType.CONSTANT
|
|
636
|
-
and
|
|
639
|
+
and self.rendering.parameters is True
|
|
637
640
|
and e.datatype.data_type != DataType.MAP
|
|
638
641
|
):
|
|
639
642
|
return f":{e.safe_address}"
|
|
@@ -723,9 +726,13 @@ class BaseDialect:
|
|
|
723
726
|
UnnestMode.CROSS_JOIN_ALIAS,
|
|
724
727
|
UnnestMode.CROSS_JOIN,
|
|
725
728
|
UnnestMode.CROSS_APPLY,
|
|
726
|
-
UnnestMode.SNOWFLAKE,
|
|
727
729
|
):
|
|
728
730
|
|
|
731
|
+
source = f"{render_unnest(self.UNNEST_MODE, self.QUOTE_CHARACTER, cte.join_derived_concepts[0], self.render_concept_sql, cte)}"
|
|
732
|
+
elif (
|
|
733
|
+
cte.join_derived_concepts
|
|
734
|
+
and self.UNNEST_MODE == UnnestMode.SNOWFLAKE
|
|
735
|
+
):
|
|
729
736
|
source = f"{render_unnest(self.UNNEST_MODE, self.QUOTE_CHARACTER, cte.join_derived_concepts[0], self.render_concept_sql, cte)}"
|
|
730
737
|
# direct - eg DUCK DB - can be directly selected inline
|
|
731
738
|
elif (
|
|
@@ -28,7 +28,10 @@ def render_unnest(
|
|
|
28
28
|
elif unnest_mode == UnnestMode.CROSS_JOIN_ALIAS:
|
|
29
29
|
return f"{render_func(concept, cte, False)} as unnest_wrapper ({quote_character}{concept.safe_address}{quote_character})"
|
|
30
30
|
elif unnest_mode == UnnestMode.SNOWFLAKE:
|
|
31
|
-
|
|
31
|
+
# if we don't actually have a join, we're directly unnesting a concept, and we can skip the flatten
|
|
32
|
+
if not cte.render_from_clause:
|
|
33
|
+
return f"{render_func(concept, cte, False)} as unnest_wrapper ( unnest1, unnest2, unnest3, unnest4, {quote_character}{cte.join_derived_concepts[0].safe_address}{quote_character})"
|
|
34
|
+
# otherwise, flatten the concept for the join
|
|
32
35
|
return f"flatten({render_func(concept, cte, False)}) as unnest_wrapper ( unnest1, unnest2, unnest3, unnest4, {quote_character}{cte.join_derived_concepts[0].safe_address}{quote_character})"
|
|
33
36
|
return f"{render_func(concept, cte, False)} as {quote_character}{concept.safe_address}{quote_character}"
|
|
34
37
|
|
|
@@ -76,12 +76,22 @@ class SnowflakeConfig(DialectConfig):
|
|
|
76
76
|
account: str,
|
|
77
77
|
username: str,
|
|
78
78
|
password: str,
|
|
79
|
+
database: str | None = None,
|
|
80
|
+
schema: str | None = None,
|
|
79
81
|
):
|
|
80
82
|
self.account = account
|
|
81
83
|
self.username = username
|
|
82
84
|
self.password = password
|
|
85
|
+
self.database = database
|
|
86
|
+
self.schema = schema
|
|
87
|
+
if self.schema and not self.database:
|
|
88
|
+
raise ValueError("Setting snowflake schema also requires setting database")
|
|
83
89
|
|
|
84
90
|
def connection_string(self) -> str:
|
|
91
|
+
if self.schema:
|
|
92
|
+
return f"snowflake://{self.username}:{self.password}@{self.account}/{self.database}/{self.schema}"
|
|
93
|
+
if self.database:
|
|
94
|
+
return f"snowflake://{self.username}:{self.password}@{self.account}/{self.database}"
|
|
85
95
|
return f"snowflake://{self.username}:{self.password}@{self.account}"
|
|
86
96
|
|
|
87
97
|
|
|
@@ -7,7 +7,7 @@ if TYPE_CHECKING:
|
|
|
7
7
|
from trilogy import Executor
|
|
8
8
|
from trilogy.hooks.base_hook import BaseHook
|
|
9
9
|
|
|
10
|
-
from trilogy.constants import logger
|
|
10
|
+
from trilogy.constants import Rendering, logger
|
|
11
11
|
from trilogy.dialect.config import DialectConfig
|
|
12
12
|
|
|
13
13
|
|
|
@@ -114,6 +114,7 @@ class Dialects(Enum):
|
|
|
114
114
|
environment: Optional["Environment"] = None,
|
|
115
115
|
hooks: List["BaseHook"] | None = None,
|
|
116
116
|
conf: DialectConfig | None = None,
|
|
117
|
+
rendering: Rendering | None = None,
|
|
117
118
|
_engine_factory: Callable | None = None,
|
|
118
119
|
) -> "Executor":
|
|
119
120
|
from trilogy import Executor
|
|
@@ -123,6 +124,7 @@ class Dialects(Enum):
|
|
|
123
124
|
engine=self.default_engine(conf=conf, _engine_factory=_engine_factory),
|
|
124
125
|
environment=environment or Environment(),
|
|
125
126
|
dialect=self,
|
|
127
|
+
rendering=rendering,
|
|
126
128
|
hooks=hooks,
|
|
127
129
|
)
|
|
128
130
|
|
|
@@ -130,5 +132,6 @@ class Dialects(Enum):
|
|
|
130
132
|
engine=self.default_engine(conf=conf),
|
|
131
133
|
environment=environment or Environment(),
|
|
132
134
|
dialect=self,
|
|
135
|
+
rendering=rendering,
|
|
133
136
|
hooks=hooks,
|
|
134
137
|
)
|
|
@@ -6,7 +6,7 @@ from typing import Any, Generator, List, Optional, Protocol
|
|
|
6
6
|
from sqlalchemy import text
|
|
7
7
|
from sqlalchemy.engine import CursorResult
|
|
8
8
|
|
|
9
|
-
from trilogy.constants import logger
|
|
9
|
+
from trilogy.constants import Rendering, logger
|
|
10
10
|
from trilogy.core.enums import FunctionType, Granularity, IOType
|
|
11
11
|
from trilogy.core.models.author import Concept, Function
|
|
12
12
|
from trilogy.core.models.build import BuildConcept, BuildFunction
|
|
@@ -75,6 +75,7 @@ class Executor(object):
|
|
|
75
75
|
dialect: Dialects,
|
|
76
76
|
engine: ExecutionEngine,
|
|
77
77
|
environment: Optional[Environment] = None,
|
|
78
|
+
rendering: Rendering | None = None,
|
|
78
79
|
hooks: List[BaseHook] | None = None,
|
|
79
80
|
):
|
|
80
81
|
self.dialect: Dialects = dialect
|
|
@@ -83,7 +84,7 @@ class Executor(object):
|
|
|
83
84
|
self.generator: BaseDialect
|
|
84
85
|
self.logger = logger
|
|
85
86
|
self.hooks = hooks
|
|
86
|
-
self.generator = get_dialect_generator(self.dialect)
|
|
87
|
+
self.generator = get_dialect_generator(self.dialect, rendering)
|
|
87
88
|
self.connection = self.engine.connect()
|
|
88
89
|
# TODO: make generic
|
|
89
90
|
if self.dialect == Dialects.DATAFRAME:
|
|
@@ -18,9 +18,11 @@ from lark.tree import Meta
|
|
|
18
18
|
from pydantic import ValidationError
|
|
19
19
|
|
|
20
20
|
from trilogy.constants import (
|
|
21
|
+
CONFIG,
|
|
21
22
|
DEFAULT_NAMESPACE,
|
|
22
23
|
NULL_VALUE,
|
|
23
24
|
MagicConstants,
|
|
25
|
+
Parsing,
|
|
24
26
|
)
|
|
25
27
|
from trilogy.core.enums import (
|
|
26
28
|
BooleanOperator,
|
|
@@ -282,6 +284,7 @@ class ParseToObjects(Transformer):
|
|
|
282
284
|
text_lookup: dict[Path | str, str] | None = None,
|
|
283
285
|
environment_lookup: dict[str, Environment] | None = None,
|
|
284
286
|
import_keys: list[str] | None = None,
|
|
287
|
+
parse_config: Parsing | None = None,
|
|
285
288
|
):
|
|
286
289
|
Transformer.__init__(self, True)
|
|
287
290
|
self.environment: Environment = environment
|
|
@@ -298,6 +301,7 @@ class ParseToObjects(Transformer):
|
|
|
298
301
|
self.parse_pass = ParsePass.INITIAL
|
|
299
302
|
self.function_factory = FunctionFactory(self.environment)
|
|
300
303
|
self.import_keys: list[str] = import_keys or ["root"]
|
|
304
|
+
self.parse_config: Parsing = parse_config or CONFIG.parsing
|
|
301
305
|
|
|
302
306
|
def set_text(self, text: str):
|
|
303
307
|
self.text_lookup[self.token_address] = text
|
|
@@ -1014,6 +1018,7 @@ class ParseToObjects(Transformer):
|
|
|
1014
1018
|
tokens=self.tokens,
|
|
1015
1019
|
text_lookup=self.text_lookup,
|
|
1016
1020
|
import_keys=self.import_keys + [cache_key],
|
|
1021
|
+
parse_config=self.parse_config,
|
|
1017
1022
|
)
|
|
1018
1023
|
nparser.transform(raw_tokens)
|
|
1019
1024
|
self.parsed[cache_lookup] = nparser
|
|
@@ -1148,8 +1153,8 @@ class ParseToObjects(Transformer):
|
|
|
1148
1153
|
elif isinstance(arg, HavingClause):
|
|
1149
1154
|
having = arg
|
|
1150
1155
|
if not select_items:
|
|
1151
|
-
raise
|
|
1152
|
-
|
|
1156
|
+
raise ParseError("Malformed select, missing select items")
|
|
1157
|
+
pre_keys = set(self.environment.concepts.keys())
|
|
1153
1158
|
base = SelectStatement.from_inputs(
|
|
1154
1159
|
environment=self.environment,
|
|
1155
1160
|
selection=select_items,
|
|
@@ -1159,6 +1164,15 @@ class ParseToObjects(Transformer):
|
|
|
1159
1164
|
limit=limit,
|
|
1160
1165
|
meta=Metadata(line_number=meta.line),
|
|
1161
1166
|
)
|
|
1167
|
+
if (
|
|
1168
|
+
self.parse_pass == ParsePass.INITIAL
|
|
1169
|
+
and self.parse_config.strict_name_shadow_enforcement
|
|
1170
|
+
):
|
|
1171
|
+
intersection = base.locally_derived.intersection(pre_keys)
|
|
1172
|
+
if intersection:
|
|
1173
|
+
raise ParseError(
|
|
1174
|
+
f"Select statement {base} has derived concepts {list(intersection)} that shadow existing environment concepts, which may cause unexpected behavior. Rename these."
|
|
1175
|
+
)
|
|
1162
1176
|
return base
|
|
1163
1177
|
|
|
1164
1178
|
@v_args(meta=True)
|
|
@@ -1740,7 +1754,10 @@ def parse_text_raw(text: str, environment: Optional[Environment] = None):
|
|
|
1740
1754
|
|
|
1741
1755
|
|
|
1742
1756
|
def parse_text(
|
|
1743
|
-
text: str,
|
|
1757
|
+
text: str,
|
|
1758
|
+
environment: Optional[Environment] = None,
|
|
1759
|
+
root: Path | None = None,
|
|
1760
|
+
parse_config: Parsing | None = None,
|
|
1744
1761
|
) -> Tuple[
|
|
1745
1762
|
Environment,
|
|
1746
1763
|
List[
|
|
@@ -1756,7 +1773,9 @@ def parse_text(
|
|
|
1756
1773
|
environment = environment or (
|
|
1757
1774
|
Environment(working_path=root) if root else Environment()
|
|
1758
1775
|
)
|
|
1759
|
-
parser = ParseToObjects(
|
|
1776
|
+
parser = ParseToObjects(
|
|
1777
|
+
environment=environment, import_keys=["root"], parse_config=parse_config
|
|
1778
|
+
)
|
|
1760
1779
|
|
|
1761
1780
|
try:
|
|
1762
1781
|
parser.set_text(text)
|
|
@@ -1,38 +1,42 @@
|
|
|
1
|
+
from trilogy.constants import Rendering
|
|
2
|
+
from trilogy.dialect.base import BaseDialect
|
|
1
3
|
from trilogy.dialect.enums import Dialects
|
|
2
4
|
|
|
3
5
|
|
|
4
|
-
def get_dialect_generator(
|
|
6
|
+
def get_dialect_generator(
|
|
7
|
+
dialect: Dialects, rendering: Rendering | None = None
|
|
8
|
+
) -> BaseDialect:
|
|
5
9
|
if dialect == Dialects.BIGQUERY:
|
|
6
10
|
from trilogy.dialect.bigquery import BigqueryDialect
|
|
7
11
|
|
|
8
|
-
return BigqueryDialect()
|
|
12
|
+
return BigqueryDialect(rendering=rendering)
|
|
9
13
|
elif dialect == Dialects.SQL_SERVER:
|
|
10
14
|
from trilogy.dialect.sql_server import SqlServerDialect
|
|
11
15
|
|
|
12
|
-
return SqlServerDialect()
|
|
16
|
+
return SqlServerDialect(rendering=rendering)
|
|
13
17
|
elif dialect == Dialects.DUCK_DB:
|
|
14
18
|
from trilogy.dialect.duckdb import DuckDBDialect
|
|
15
19
|
|
|
16
|
-
return DuckDBDialect()
|
|
20
|
+
return DuckDBDialect(rendering=rendering)
|
|
17
21
|
elif dialect == Dialects.PRESTO:
|
|
18
22
|
from trilogy.dialect.presto import PrestoDialect
|
|
19
23
|
|
|
20
|
-
return PrestoDialect()
|
|
24
|
+
return PrestoDialect(rendering=rendering)
|
|
21
25
|
elif dialect == Dialects.TRINO:
|
|
22
26
|
from trilogy.dialect.presto import TrinoDialect
|
|
23
27
|
|
|
24
|
-
return TrinoDialect()
|
|
28
|
+
return TrinoDialect(rendering=rendering)
|
|
25
29
|
elif dialect == Dialects.POSTGRES:
|
|
26
30
|
from trilogy.dialect.postgres import PostgresDialect
|
|
27
31
|
|
|
28
|
-
return PostgresDialect()
|
|
32
|
+
return PostgresDialect(rendering=rendering)
|
|
29
33
|
elif dialect == Dialects.SNOWFLAKE:
|
|
30
34
|
from trilogy.dialect.snowflake import SnowflakeDialect
|
|
31
35
|
|
|
32
|
-
return SnowflakeDialect()
|
|
36
|
+
return SnowflakeDialect(rendering=rendering)
|
|
33
37
|
elif dialect == Dialects.DATAFRAME:
|
|
34
38
|
from trilogy.dialect.dataframe import DataframeDialect
|
|
35
39
|
|
|
36
|
-
return DataframeDialect()
|
|
40
|
+
return DataframeDialect(rendering=rendering)
|
|
37
41
|
else:
|
|
38
42
|
raise ValueError(f"Unsupported dialect {dialect}")
|
|
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.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/__init__.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/basic_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/filter_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/group_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/group_to_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/node_merge_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/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.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/select_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/synonym_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/union_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/trilogy/core/processing/node_generators/unnest_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.3.20 → pytrilogy-0.0.3.22}/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
|