pytrilogy 0.0.1.104__tar.gz → 0.0.1.105__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.1.104/pytrilogy.egg-info → pytrilogy-0.0.1.105}/PKG-INFO +1 -1
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105/pytrilogy.egg-info}/PKG-INFO +1 -1
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/__init__.py +1 -1
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/models.py +99 -19
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/concept_strategies_v3.py +1 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/common.py +19 -7
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/filter_node.py +37 -10
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/merge_node.py +11 -1
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/dialect/base.py +12 -3
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/parsing/common.py +30 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/parsing/parse_engine.py +42 -82
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/parsing/render.py +0 -122
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/LICENSE.md +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/README.md +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/pyproject.toml +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/pytrilogy.egg-info/SOURCES.txt +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/pytrilogy.egg-info/dependency_links.txt +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/pytrilogy.egg-info/entry_points.txt +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/pytrilogy.egg-info/requires.txt +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/pytrilogy.egg-info/top_level.txt +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/setup.cfg +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/setup.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_declarations.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_derived_concepts.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_discovery_nodes.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_environment.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_functions.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_imports.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_metadata.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_models.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_multi_join_assignments.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_parsing.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_partial_handling.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_query_processing.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_select.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_statements.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_undefined_concept.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/tests/test_where_clause.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/compiler.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/constants.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/__init__.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/constants.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/enums.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/env_processor.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/environment_helpers.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/ergonomics.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/exceptions.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/functions.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/graph_models.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/internal.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/__init__.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/graph_utils.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/__init__.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/basic_node.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/concept_merge.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/group_node.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/select_node.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/window_node.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/nodes/__init__.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/nodes/base_node.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/nodes/filter_node.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/nodes/group_node.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/nodes/merge_node.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/nodes/unnest_node.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/nodes/window_node.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/utility.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/query_processor.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/dialect/__init__.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/dialect/bigquery.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/dialect/common.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/dialect/config.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/dialect/duckdb.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/dialect/enums.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/dialect/postgres.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/dialect/presto.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/dialect/snowflake.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/dialect/sql_server.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/docs/__init__.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/engine.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/executor.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/hooks/__init__.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/hooks/base_hook.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/hooks/graph_hook.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/hooks/query_debugger.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/metadata/__init__.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/parser.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/parsing/__init__.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/parsing/config.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/parsing/exceptions.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/parsing/helpers.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/py.typed +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/scripts/__init__.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/scripts/trilogy.py +0 -0
- {pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/utility.py +0 -0
|
@@ -113,15 +113,27 @@ NAMESPACED_TYPES = Union[
|
|
|
113
113
|
|
|
114
114
|
|
|
115
115
|
class Namespaced(ABC):
|
|
116
|
-
pass
|
|
117
116
|
|
|
118
117
|
def with_namespace(self, namespace: str):
|
|
119
118
|
raise NotImplementedError
|
|
120
119
|
|
|
121
120
|
|
|
122
|
-
class
|
|
123
|
-
|
|
121
|
+
class ConceptArgs(ABC):
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def concept_arguments(self) -> List["Concept"]:
|
|
125
|
+
raise NotImplementedError
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def existence_arguments(self) -> List["Concept"]:
|
|
129
|
+
return []
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def row_arguments(self) -> List["Concept"]:
|
|
133
|
+
return self.concept_arguments
|
|
124
134
|
|
|
135
|
+
|
|
136
|
+
class SelectGrain(ABC):
|
|
125
137
|
def with_select_grain(self, grain: Grain):
|
|
126
138
|
raise NotImplementedError
|
|
127
139
|
|
|
@@ -1395,16 +1407,11 @@ class MultiSelectStatement(Namespaced, BaseModel):
|
|
|
1395
1407
|
return output
|
|
1396
1408
|
|
|
1397
1409
|
def find_source(self, concept: Concept, cte: CTE) -> Concept:
|
|
1398
|
-
all = []
|
|
1399
1410
|
for x in self.align.items:
|
|
1400
1411
|
if concept.name == x.alias:
|
|
1401
1412
|
for c in x.concepts:
|
|
1402
1413
|
if c.address in cte.output_lcl:
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
if len(all) == 1:
|
|
1406
|
-
return all[0]
|
|
1407
|
-
|
|
1414
|
+
return c
|
|
1408
1415
|
raise SyntaxError(
|
|
1409
1416
|
f"Could not find upstream map for multiselect {str(concept)} on cte ({cte})"
|
|
1410
1417
|
)
|
|
@@ -2546,7 +2553,7 @@ class LazyEnvironment(Environment):
|
|
|
2546
2553
|
return super().__getattribute__(name)
|
|
2547
2554
|
|
|
2548
2555
|
|
|
2549
|
-
class Comparison(Namespaced, SelectGrain, BaseModel):
|
|
2556
|
+
class Comparison(ConceptArgs, Namespaced, SelectGrain, BaseModel):
|
|
2550
2557
|
left: Union[
|
|
2551
2558
|
int,
|
|
2552
2559
|
str,
|
|
@@ -2598,7 +2605,7 @@ class Comparison(Namespaced, SelectGrain, BaseModel):
|
|
|
2598
2605
|
return f"{str(self.left)} {self.operator.value} {str(self.right)}"
|
|
2599
2606
|
|
|
2600
2607
|
def with_namespace(self, namespace: str):
|
|
2601
|
-
return
|
|
2608
|
+
return self.__class__(
|
|
2602
2609
|
left=(
|
|
2603
2610
|
self.left.with_namespace(namespace)
|
|
2604
2611
|
if isinstance(self.left, Namespaced)
|
|
@@ -2613,7 +2620,7 @@ class Comparison(Namespaced, SelectGrain, BaseModel):
|
|
|
2613
2620
|
)
|
|
2614
2621
|
|
|
2615
2622
|
def with_select_grain(self, grain: Grain):
|
|
2616
|
-
return
|
|
2623
|
+
return self.__class__(
|
|
2617
2624
|
left=(
|
|
2618
2625
|
self.left.with_select_grain(grain)
|
|
2619
2626
|
if isinstance(self.left, SelectGrain)
|
|
@@ -2632,7 +2639,9 @@ class Comparison(Namespaced, SelectGrain, BaseModel):
|
|
|
2632
2639
|
output: List[Concept] = []
|
|
2633
2640
|
if isinstance(self.left, (Concept,)):
|
|
2634
2641
|
output += [self.left]
|
|
2635
|
-
if isinstance(
|
|
2642
|
+
if isinstance(
|
|
2643
|
+
self.left, (Comparison, SubselectComparison, Conditional, Parenthetical)
|
|
2644
|
+
):
|
|
2636
2645
|
output += self.left.input
|
|
2637
2646
|
if isinstance(self.left, FilterItem):
|
|
2638
2647
|
output += self.left.concept_arguments
|
|
@@ -2641,7 +2650,9 @@ class Comparison(Namespaced, SelectGrain, BaseModel):
|
|
|
2641
2650
|
|
|
2642
2651
|
if isinstance(self.right, (Concept,)):
|
|
2643
2652
|
output += [self.right]
|
|
2644
|
-
if isinstance(
|
|
2653
|
+
if isinstance(
|
|
2654
|
+
self.right, (Comparison, SubselectComparison, Conditional, Parenthetical)
|
|
2655
|
+
):
|
|
2645
2656
|
output += self.right.input
|
|
2646
2657
|
if isinstance(self.right, FilterItem):
|
|
2647
2658
|
output += self.right.concept_arguments
|
|
@@ -2658,8 +2669,31 @@ class Comparison(Namespaced, SelectGrain, BaseModel):
|
|
|
2658
2669
|
return output
|
|
2659
2670
|
|
|
2660
2671
|
|
|
2672
|
+
class SubselectComparison(Comparison):
|
|
2673
|
+
|
|
2674
|
+
@property
|
|
2675
|
+
def row_arguments(self) -> List[Concept]:
|
|
2676
|
+
return get_concept_arguments(self.left)
|
|
2677
|
+
|
|
2678
|
+
@property
|
|
2679
|
+
def existence_arguments(self) -> List[Concept]:
|
|
2680
|
+
return get_concept_arguments(self.right)
|
|
2681
|
+
|
|
2682
|
+
def with_select_grain(self, grain: Grain):
|
|
2683
|
+
# there's no need to pass the select grain through to a subselect comparison
|
|
2684
|
+
return self.__class__(
|
|
2685
|
+
left=(
|
|
2686
|
+
self.left.with_select_grain(grain)
|
|
2687
|
+
if isinstance(self.left, SelectGrain)
|
|
2688
|
+
else self.left
|
|
2689
|
+
),
|
|
2690
|
+
right=self.right,
|
|
2691
|
+
operator=self.operator,
|
|
2692
|
+
)
|
|
2693
|
+
|
|
2694
|
+
|
|
2661
2695
|
class CaseWhen(Namespaced, SelectGrain, BaseModel):
|
|
2662
|
-
comparison: Conditional | Comparison
|
|
2696
|
+
comparison: Conditional | SubselectComparison | Comparison
|
|
2663
2697
|
expr: "Expr"
|
|
2664
2698
|
|
|
2665
2699
|
@property
|
|
@@ -2726,7 +2760,7 @@ class CaseElse(Namespaced, SelectGrain, BaseModel):
|
|
|
2726
2760
|
)
|
|
2727
2761
|
|
|
2728
2762
|
|
|
2729
|
-
class Conditional(Namespaced, SelectGrain, BaseModel):
|
|
2763
|
+
class Conditional(ConceptArgs, Namespaced, SelectGrain, BaseModel):
|
|
2730
2764
|
left: Union[
|
|
2731
2765
|
int,
|
|
2732
2766
|
str,
|
|
@@ -2821,6 +2855,32 @@ class Conditional(Namespaced, SelectGrain, BaseModel):
|
|
|
2821
2855
|
output += get_concept_arguments(self.right)
|
|
2822
2856
|
return output
|
|
2823
2857
|
|
|
2858
|
+
@property
|
|
2859
|
+
def row_arguments(self) -> List[Concept]:
|
|
2860
|
+
output = []
|
|
2861
|
+
if isinstance(self.left, ConceptArgs):
|
|
2862
|
+
output += self.left.row_arguments
|
|
2863
|
+
else:
|
|
2864
|
+
output += get_concept_arguments(self.left)
|
|
2865
|
+
if isinstance(self.right, ConceptArgs):
|
|
2866
|
+
output += self.right.row_arguments
|
|
2867
|
+
else:
|
|
2868
|
+
output += get_concept_arguments(self.right)
|
|
2869
|
+
return output
|
|
2870
|
+
|
|
2871
|
+
@property
|
|
2872
|
+
def existence_arguments(self) -> List[Concept]:
|
|
2873
|
+
output = []
|
|
2874
|
+
if isinstance(self.left, ConceptArgs):
|
|
2875
|
+
output += self.left.existence_arguments
|
|
2876
|
+
else:
|
|
2877
|
+
output += get_concept_arguments(self.left)
|
|
2878
|
+
if isinstance(self.right, ConceptArgs):
|
|
2879
|
+
output += self.right.existence_arguments
|
|
2880
|
+
else:
|
|
2881
|
+
output += get_concept_arguments(self.right)
|
|
2882
|
+
return output
|
|
2883
|
+
|
|
2824
2884
|
|
|
2825
2885
|
class AggregateWrapper(Namespaced, SelectGrain, BaseModel):
|
|
2826
2886
|
function: Function
|
|
@@ -2864,8 +2924,8 @@ class AggregateWrapper(Namespaced, SelectGrain, BaseModel):
|
|
|
2864
2924
|
return AggregateWrapper(function=self.function.with_select_grain(grain), by=by)
|
|
2865
2925
|
|
|
2866
2926
|
|
|
2867
|
-
class WhereClause(Namespaced, SelectGrain, BaseModel):
|
|
2868
|
-
conditional: Union[Comparison, Conditional, "Parenthetical"]
|
|
2927
|
+
class WhereClause(ConceptArgs, Namespaced, SelectGrain, BaseModel):
|
|
2928
|
+
conditional: Union[SubselectComparison, Comparison, Conditional, "Parenthetical"]
|
|
2869
2929
|
|
|
2870
2930
|
@property
|
|
2871
2931
|
def input(self) -> List[Concept]:
|
|
@@ -2875,6 +2935,14 @@ class WhereClause(Namespaced, SelectGrain, BaseModel):
|
|
|
2875
2935
|
def concept_arguments(self) -> List[Concept]:
|
|
2876
2936
|
return self.conditional.concept_arguments
|
|
2877
2937
|
|
|
2938
|
+
@property
|
|
2939
|
+
def row_arguments(self) -> List[Concept]:
|
|
2940
|
+
return self.conditional.row_arguments
|
|
2941
|
+
|
|
2942
|
+
@property
|
|
2943
|
+
def existence_arguments(self) -> List[Concept]:
|
|
2944
|
+
return self.conditional.existence_arguments
|
|
2945
|
+
|
|
2878
2946
|
def with_namespace(self, namespace: str) -> WhereClause:
|
|
2879
2947
|
return WhereClause(conditional=self.conditional.with_namespace(namespace))
|
|
2880
2948
|
|
|
@@ -3062,7 +3130,7 @@ class RowsetItem(Namespaced, BaseModel):
|
|
|
3062
3130
|
return [self.content]
|
|
3063
3131
|
|
|
3064
3132
|
|
|
3065
|
-
class Parenthetical(Namespaced, SelectGrain, BaseModel):
|
|
3133
|
+
class Parenthetical(ConceptArgs, Namespaced, SelectGrain, BaseModel):
|
|
3066
3134
|
content: "Expr"
|
|
3067
3135
|
|
|
3068
3136
|
def __str__(self):
|
|
@@ -3106,6 +3174,18 @@ class Parenthetical(Namespaced, SelectGrain, BaseModel):
|
|
|
3106
3174
|
base.append(x)
|
|
3107
3175
|
return base
|
|
3108
3176
|
|
|
3177
|
+
@property
|
|
3178
|
+
def row_arguments(self) -> List[Concept]:
|
|
3179
|
+
if isinstance(self.content, ConceptArgs):
|
|
3180
|
+
return self.content.row_arguments
|
|
3181
|
+
return self.concept_arguments
|
|
3182
|
+
|
|
3183
|
+
@property
|
|
3184
|
+
def existence_arguments(self) -> List[Concept]:
|
|
3185
|
+
if isinstance(self.content, ConceptArgs):
|
|
3186
|
+
return self.content.existence_arguments
|
|
3187
|
+
return self.concept_arguments
|
|
3188
|
+
|
|
3109
3189
|
@property
|
|
3110
3190
|
def input(self):
|
|
3111
3191
|
base = []
|
{pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/concept_strategies_v3.py
RENAMED
|
@@ -317,6 +317,7 @@ def generate_node(
|
|
|
317
317
|
return gen_basic_node(
|
|
318
318
|
concept, local_optional, environment, g, depth + 1, source_concepts, history
|
|
319
319
|
)
|
|
320
|
+
|
|
320
321
|
elif concept.derivation == PurposeLineage.ROOT:
|
|
321
322
|
logger.info(
|
|
322
323
|
f"{depth_to_prefix(depth)}{LOGGER_PREFIX} for {concept.address}, generating select node with optional {[x.address for x in local_optional]}"
|
{pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/common.py
RENAMED
|
@@ -45,21 +45,33 @@ def resolve_function_parent_concepts(concept: Concept) -> List[Concept]:
|
|
|
45
45
|
return unique(concept.lineage.concept_arguments, "address")
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
def resolve_filter_parent_concepts(
|
|
48
|
+
def resolve_filter_parent_concepts(
|
|
49
|
+
concept: Concept,
|
|
50
|
+
) -> Tuple[Concept, List[Concept], List[Concept]]:
|
|
49
51
|
if not isinstance(concept.lineage, FilterItem):
|
|
50
|
-
raise ValueError
|
|
52
|
+
raise ValueError(
|
|
53
|
+
f"Concept {concept} lineage is not filter item, is {type(concept.lineage)}"
|
|
54
|
+
)
|
|
51
55
|
direct_parent = concept.lineage.content
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
base_existence = []
|
|
57
|
+
base_rows = [direct_parent]
|
|
58
|
+
base_rows += concept.lineage.where.row_arguments
|
|
59
|
+
base_existence += concept.lineage.where.existence_arguments
|
|
54
60
|
if direct_parent.grain:
|
|
55
|
-
|
|
61
|
+
base_rows += direct_parent.grain.components_copy
|
|
56
62
|
if (
|
|
57
63
|
isinstance(direct_parent, Concept)
|
|
58
64
|
and direct_parent.purpose == Purpose.PROPERTY
|
|
59
65
|
and direct_parent.keys
|
|
60
66
|
):
|
|
61
|
-
|
|
62
|
-
|
|
67
|
+
base_rows += direct_parent.keys
|
|
68
|
+
if concept.lineage.where.existence_arguments:
|
|
69
|
+
return (
|
|
70
|
+
concept.lineage.content,
|
|
71
|
+
unique(base_rows, "address"),
|
|
72
|
+
unique(base_existence, "address"),
|
|
73
|
+
)
|
|
74
|
+
return concept.lineage.content, unique(base_rows, "address"), []
|
|
63
75
|
|
|
64
76
|
|
|
65
77
|
def gen_property_enrichment_node(
|
{pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/filter_node.py
RENAMED
|
@@ -11,7 +11,7 @@ from trilogy.core.processing.node_generators.common import (
|
|
|
11
11
|
resolve_filter_parent_concepts,
|
|
12
12
|
)
|
|
13
13
|
from trilogy.constants import logger
|
|
14
|
-
from trilogy.core.processing.utility import padding
|
|
14
|
+
from trilogy.core.processing.utility import padding, unique
|
|
15
15
|
from trilogy.core.processing.node_generators.common import concept_to_relevant_joins
|
|
16
16
|
|
|
17
17
|
LOGGER_PREFIX = "[GEN_FILTER_NODE]"
|
|
@@ -26,30 +26,57 @@ def gen_filter_node(
|
|
|
26
26
|
source_concepts,
|
|
27
27
|
history: History | None = None,
|
|
28
28
|
) -> MergeNode | FilterNode | None:
|
|
29
|
-
immediate_parent,
|
|
29
|
+
immediate_parent, parent_row_concepts, parent_existence_concepts = (
|
|
30
|
+
resolve_filter_parent_concepts(concept)
|
|
31
|
+
)
|
|
30
32
|
|
|
31
|
-
logger.info(
|
|
33
|
+
logger.info(
|
|
34
|
+
f"{padding(depth)}{LOGGER_PREFIX} fetching filter node row parents {[x.address for x in parent_row_concepts]}"
|
|
35
|
+
)
|
|
36
|
+
core_parents = []
|
|
32
37
|
parent = source_concepts(
|
|
33
|
-
mandatory_list=
|
|
38
|
+
mandatory_list=parent_row_concepts,
|
|
34
39
|
environment=environment,
|
|
35
40
|
g=g,
|
|
36
41
|
depth=depth + 1,
|
|
37
42
|
history=history,
|
|
38
43
|
)
|
|
44
|
+
|
|
39
45
|
if not parent:
|
|
40
46
|
return None
|
|
47
|
+
core_parents.append(parent)
|
|
48
|
+
if parent_existence_concepts:
|
|
49
|
+
logger.info(
|
|
50
|
+
f"{padding(depth)}{LOGGER_PREFIX} fetching filter node existence parents {[x.address for x in parent_existence_concepts]}"
|
|
51
|
+
)
|
|
52
|
+
parent_existence = source_concepts(
|
|
53
|
+
mandatory_list=parent_existence_concepts,
|
|
54
|
+
environment=environment,
|
|
55
|
+
g=g,
|
|
56
|
+
depth=depth + 1,
|
|
57
|
+
history=history,
|
|
58
|
+
)
|
|
59
|
+
if not parent_existence:
|
|
60
|
+
return None
|
|
61
|
+
core_parents.append(parent_existence)
|
|
62
|
+
|
|
41
63
|
filter_node = FilterNode(
|
|
42
|
-
input_concepts=
|
|
43
|
-
|
|
64
|
+
input_concepts=unique(
|
|
65
|
+
[immediate_parent] + parent_row_concepts + parent_existence_concepts,
|
|
66
|
+
"address",
|
|
67
|
+
),
|
|
68
|
+
output_concepts=[concept, immediate_parent] + parent_row_concepts,
|
|
44
69
|
environment=environment,
|
|
45
70
|
g=g,
|
|
46
|
-
parents=
|
|
71
|
+
parents=core_parents,
|
|
47
72
|
)
|
|
48
|
-
if not local_optional
|
|
73
|
+
if not local_optional or all(
|
|
74
|
+
[x.address in [y.address for y in parent_row_concepts] for x in local_optional]
|
|
75
|
+
):
|
|
49
76
|
return filter_node
|
|
50
77
|
enrich_node = source_concepts( # this fetches the parent + join keys
|
|
51
78
|
# to then connect to the rest of the query
|
|
52
|
-
mandatory_list=[immediate_parent] +
|
|
79
|
+
mandatory_list=[immediate_parent] + parent_row_concepts + local_optional,
|
|
53
80
|
environment=environment,
|
|
54
81
|
g=g,
|
|
55
82
|
depth=depth + 1,
|
|
@@ -75,7 +102,7 @@ def gen_filter_node(
|
|
|
75
102
|
left_node=enrich_node,
|
|
76
103
|
right_node=filter_node,
|
|
77
104
|
concepts=concept_to_relevant_joins(
|
|
78
|
-
[immediate_parent] +
|
|
105
|
+
[immediate_parent] + parent_row_concepts
|
|
79
106
|
),
|
|
80
107
|
join_type=JoinType.LEFT_OUTER,
|
|
81
108
|
filter_to_mutual=False,
|
{pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/merge_node.py
RENAMED
|
@@ -87,8 +87,18 @@ def gen_merge_node(
|
|
|
87
87
|
) -> Optional[MergeNode]:
|
|
88
88
|
join_candidates: List[PathInfo] = []
|
|
89
89
|
# anchor on datasources
|
|
90
|
+
final_all_concepts = []
|
|
91
|
+
# implicit_upstream = {}
|
|
92
|
+
for x in all_concepts:
|
|
93
|
+
# if x.derivation in (PurposeLineage.AGGREGATE, PurposeLineage.BASIC):
|
|
94
|
+
# final_all_concepts +=resolve_function_parent_concepts(x)
|
|
95
|
+
# elif x.derivation == PurposeLineage.FILTER:
|
|
96
|
+
# final_all_concepts +=resolve_filter_parent_concepts(x)
|
|
97
|
+
# else:
|
|
98
|
+
# final_all_concepts.append(x)
|
|
99
|
+
final_all_concepts.append(x)
|
|
90
100
|
for datasource in environment.datasources.values():
|
|
91
|
-
path = identify_ds_join_paths(
|
|
101
|
+
path = identify_ds_join_paths(final_all_concepts, g, datasource, accept_partial)
|
|
92
102
|
if path and path.reduced_concepts:
|
|
93
103
|
join_candidates.append(path)
|
|
94
104
|
join_candidates.sort(key=lambda x: sum([len(v) for v in x.paths.values()]))
|
|
@@ -22,6 +22,7 @@ from trilogy.core.models import (
|
|
|
22
22
|
CompiledCTE,
|
|
23
23
|
Conditional,
|
|
24
24
|
Comparison,
|
|
25
|
+
SubselectComparison,
|
|
25
26
|
OrderItem,
|
|
26
27
|
WindowItem,
|
|
27
28
|
FilterItem,
|
|
@@ -273,14 +274,13 @@ class BaseDialect:
|
|
|
273
274
|
]
|
|
274
275
|
rval = f"{self.WINDOW_FUNCTION_MAP[c.lineage.type](concept = self.render_concept_sql(c.lineage.content, cte=cte, alias=False), window=','.join(rendered_over_components), sort=','.join(rendered_order_components))}" # noqa: E501
|
|
275
276
|
elif isinstance(c.lineage, FilterItem):
|
|
276
|
-
rval = f"CASE WHEN {self.render_expr(c.lineage.where.conditional)} THEN {self.render_concept_sql(c.lineage.content, cte=cte, alias=False)} ELSE NULL END"
|
|
277
|
+
rval = f"CASE WHEN {self.render_expr(c.lineage.where.conditional, cte=cte)} THEN {self.render_concept_sql(c.lineage.content, cte=cte, alias=False)} ELSE NULL END"
|
|
277
278
|
elif isinstance(c.lineage, RowsetItem):
|
|
278
279
|
rval = f"{self.render_concept_sql(c.lineage.content, cte=cte, alias=False)}"
|
|
279
280
|
elif isinstance(c.lineage, MultiSelectStatement):
|
|
280
281
|
rval = f"{self.render_concept_sql(c.lineage.find_source(c, cte), cte=cte, alias=False)}"
|
|
281
282
|
elif isinstance(c.lineage, MergeStatement):
|
|
282
283
|
rval = f"{self.render_concept_sql(c.lineage.find_source(c, cte), cte=cte, alias=False)}"
|
|
283
|
-
# rval = f"{self.FUNCTION_MAP[FunctionType.COALESCE](*[self.render_concept_sql(parent, cte=cte, alias=False) for parent in c.lineage.find_sources(c, cte)])}"
|
|
284
284
|
elif isinstance(c.lineage, AggregateWrapper):
|
|
285
285
|
args = [
|
|
286
286
|
self.render_expr(v, cte) # , alias=False)
|
|
@@ -330,6 +330,7 @@ class BaseDialect:
|
|
|
330
330
|
Function,
|
|
331
331
|
Conditional,
|
|
332
332
|
Comparison,
|
|
333
|
+
SubselectComparison,
|
|
333
334
|
Concept,
|
|
334
335
|
str,
|
|
335
336
|
int,
|
|
@@ -358,7 +359,15 @@ class BaseDialect:
|
|
|
358
359
|
# if isinstance(e, Concept):
|
|
359
360
|
# cte = cte or cte_map.get(e.address, None)
|
|
360
361
|
|
|
361
|
-
if isinstance(e,
|
|
362
|
+
if isinstance(e, SubselectComparison):
|
|
363
|
+
assert cte, "Subselects must be rendered with a CTE in context"
|
|
364
|
+
if isinstance(e.right, Concept):
|
|
365
|
+
return f"{self.render_expr(e.left, cte=cte, cte_map=cte_map)} {e.operator.value} (select {self.render_expr(e.right, cte=cte, cte_map=cte_map)} from {cte.source_map[e.right.address][0]})"
|
|
366
|
+
else:
|
|
367
|
+
raise NotImplementedError(
|
|
368
|
+
f"Subselects must be a concept, got {e.right}"
|
|
369
|
+
)
|
|
370
|
+
elif isinstance(e, Comparison):
|
|
362
371
|
return f"{self.render_expr(e.left, cte=cte, cte_map=cte_map)} {e.operator.value} {self.render_expr(e.right, cte=cte, cte_map=cte_map)}"
|
|
363
372
|
elif isinstance(e, Conditional):
|
|
364
373
|
# conditions need to be nested in parentheses
|
|
@@ -174,3 +174,33 @@ def agg_wrapper_to_concept(
|
|
|
174
174
|
keys=tuple(parent.by) if parent.by else keys,
|
|
175
175
|
)
|
|
176
176
|
return out
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def arbitrary_to_concept(
|
|
180
|
+
parent: (
|
|
181
|
+
AggregateWrapper
|
|
182
|
+
| WindowItem
|
|
183
|
+
| FilterItem
|
|
184
|
+
| Function
|
|
185
|
+
| ListWrapper
|
|
186
|
+
| int
|
|
187
|
+
| float
|
|
188
|
+
| str
|
|
189
|
+
),
|
|
190
|
+
namespace: str,
|
|
191
|
+
name: str,
|
|
192
|
+
metadata: Metadata | None = None,
|
|
193
|
+
purpose: Purpose | None = None,
|
|
194
|
+
) -> Concept:
|
|
195
|
+
if isinstance(parent, AggregateWrapper):
|
|
196
|
+
return agg_wrapper_to_concept(parent, namespace, name, metadata, purpose)
|
|
197
|
+
elif isinstance(parent, WindowItem):
|
|
198
|
+
return window_item_to_concept(parent, name, namespace, purpose, metadata)
|
|
199
|
+
elif isinstance(parent, FilterItem):
|
|
200
|
+
return filter_item_to_concept(parent, name, namespace, purpose, metadata)
|
|
201
|
+
elif isinstance(parent, Function):
|
|
202
|
+
return function_to_concept(parent, name, namespace)
|
|
203
|
+
elif isinstance(parent, ListWrapper):
|
|
204
|
+
return constant_to_concept(parent, name, namespace, purpose, metadata)
|
|
205
|
+
else:
|
|
206
|
+
return constant_to_concept(parent, name, namespace, purpose, metadata)
|
|
@@ -17,6 +17,7 @@ from trilogy.constants import (
|
|
|
17
17
|
DEFAULT_NAMESPACE,
|
|
18
18
|
NULL_VALUE,
|
|
19
19
|
VIRTUAL_CONCEPT_PREFIX,
|
|
20
|
+
MagicConstants,
|
|
20
21
|
)
|
|
21
22
|
from trilogy.core.enums import (
|
|
22
23
|
BooleanOperator,
|
|
@@ -62,6 +63,7 @@ from trilogy.core.models import (
|
|
|
62
63
|
ColumnAssignment,
|
|
63
64
|
Comment,
|
|
64
65
|
Comparison,
|
|
66
|
+
SubselectComparison,
|
|
65
67
|
Concept,
|
|
66
68
|
ConceptTransform,
|
|
67
69
|
Conditional,
|
|
@@ -108,6 +110,7 @@ from trilogy.parsing.common import (
|
|
|
108
110
|
function_to_concept,
|
|
109
111
|
filter_item_to_concept,
|
|
110
112
|
constant_to_concept,
|
|
113
|
+
arbitrary_to_concept,
|
|
111
114
|
)
|
|
112
115
|
|
|
113
116
|
CONSTANT_TYPES = (int, float, str, bool, ListWrapper)
|
|
@@ -187,9 +190,9 @@ grammar = r"""
|
|
|
187
190
|
|
|
188
191
|
// FUNCTION blocks
|
|
189
192
|
function: raw_function
|
|
190
|
-
function_binding_item: IDENTIFIER data_type
|
|
193
|
+
function_binding_item: IDENTIFIER ":" data_type
|
|
191
194
|
function_binding_list: (function_binding_item ",")* function_binding_item ","?
|
|
192
|
-
raw_function: "
|
|
195
|
+
raw_function: "bind" "sql" IDENTIFIER "(" function_binding_list ")" "-" ">" data_type "as"i MULTILINE_STRING
|
|
193
196
|
|
|
194
197
|
|
|
195
198
|
// user_id where state = Mexico
|
|
@@ -246,7 +249,9 @@ grammar = r"""
|
|
|
246
249
|
|
|
247
250
|
COMPARISON_OPERATOR: (/is[\s]+not/ | "is" |"=" | ">" | "<" | ">=" | "<=" | "!=" )
|
|
248
251
|
|
|
249
|
-
comparison: (expr COMPARISON_OPERATOR expr) | (expr array_comparison expr_tuple)
|
|
252
|
+
comparison: (expr COMPARISON_OPERATOR expr) | (expr array_comparison expr_tuple)
|
|
253
|
+
|
|
254
|
+
subselect_comparison: expr array_comparison expr
|
|
250
255
|
|
|
251
256
|
expr_tuple: "(" (expr ",")* expr ","? ")"
|
|
252
257
|
|
|
@@ -258,7 +263,7 @@ grammar = r"""
|
|
|
258
263
|
|
|
259
264
|
parenthetical: "(" (conditional | expr) ")"
|
|
260
265
|
|
|
261
|
-
expr: window_item | filter_item | comparison | fgroup | aggregate_functions | unnest | _string_functions | _math_functions | _generic_functions | _constant_functions| _date_functions | literal | expr_reference | index_access | attr_access | parenthetical
|
|
266
|
+
expr: window_item | filter_item | comparison | subselect_comparison | fgroup | aggregate_functions | unnest | _string_functions | _math_functions | _generic_functions | _constant_functions| _date_functions | literal | expr_reference | index_access | attr_access | parenthetical
|
|
262
267
|
|
|
263
268
|
// functions
|
|
264
269
|
|
|
@@ -525,43 +530,11 @@ class ParseToObjects(Transformer):
|
|
|
525
530
|
concept.metadata.line_number = meta.line
|
|
526
531
|
self.environment.add_concept(concept, meta=meta)
|
|
527
532
|
final.append(concept)
|
|
528
|
-
elif isinstance(
|
|
533
|
+
elif isinstance(
|
|
534
|
+
arg, (FilterItem, WindowItem, AggregateWrapper, ListWrapper)
|
|
535
|
+
):
|
|
529
536
|
id_hash = string_to_hash(str(arg))
|
|
530
|
-
concept =
|
|
531
|
-
arg,
|
|
532
|
-
name=f"{VIRTUAL_CONCEPT_PREFIX}_{id_hash}",
|
|
533
|
-
namespace=self.environment.namespace,
|
|
534
|
-
)
|
|
535
|
-
if concept.metadata:
|
|
536
|
-
concept.metadata.line_number = meta.line
|
|
537
|
-
self.environment.add_concept(concept, meta=meta)
|
|
538
|
-
final.append(concept)
|
|
539
|
-
elif isinstance(arg, WindowItem):
|
|
540
|
-
id_hash = string_to_hash(str(arg))
|
|
541
|
-
concept = window_item_to_concept(
|
|
542
|
-
arg,
|
|
543
|
-
namespace=self.environment.namespace,
|
|
544
|
-
name=f"{VIRTUAL_CONCEPT_PREFIX}_{id_hash}",
|
|
545
|
-
)
|
|
546
|
-
if concept.metadata:
|
|
547
|
-
concept.metadata.line_number = meta.line
|
|
548
|
-
self.environment.add_concept(concept, meta=meta)
|
|
549
|
-
final.append(concept)
|
|
550
|
-
elif isinstance(arg, AggregateWrapper):
|
|
551
|
-
id_hash = string_to_hash(str(arg))
|
|
552
|
-
concept = agg_wrapper_to_concept(
|
|
553
|
-
arg,
|
|
554
|
-
namespace=self.environment.namespace,
|
|
555
|
-
name=f"{VIRTUAL_CONCEPT_PREFIX}_{id_hash}",
|
|
556
|
-
)
|
|
557
|
-
if concept.metadata:
|
|
558
|
-
concept.metadata.line_number = meta.line
|
|
559
|
-
self.environment.add_concept(concept, meta=meta)
|
|
560
|
-
final.append(concept)
|
|
561
|
-
# we don't need virtual types for most constants
|
|
562
|
-
elif isinstance(arg, (ListWrapper)):
|
|
563
|
-
id_hash = string_to_hash(str(arg))
|
|
564
|
-
concept = constant_to_concept(
|
|
537
|
+
concept = arbitrary_to_concept(
|
|
565
538
|
arg,
|
|
566
539
|
name=f"{VIRTUAL_CONCEPT_PREFIX}_{id_hash}",
|
|
567
540
|
namespace=self.environment.namespace,
|
|
@@ -570,6 +543,7 @@ class ParseToObjects(Transformer):
|
|
|
570
543
|
concept.metadata.line_number = meta.line
|
|
571
544
|
self.environment.add_concept(concept, meta=meta)
|
|
572
545
|
final.append(concept)
|
|
546
|
+
|
|
573
547
|
else:
|
|
574
548
|
final.append(arg)
|
|
575
549
|
return final
|
|
@@ -773,8 +747,10 @@ class ParseToObjects(Transformer):
|
|
|
773
747
|
while isinstance(source_value, Parenthetical):
|
|
774
748
|
source_value = source_value.content
|
|
775
749
|
|
|
776
|
-
if isinstance(
|
|
777
|
-
|
|
750
|
+
if isinstance(
|
|
751
|
+
source_value, (FilterItem, WindowItem, AggregateWrapper, Function)
|
|
752
|
+
):
|
|
753
|
+
concept = arbitrary_to_concept(
|
|
778
754
|
source_value,
|
|
779
755
|
name=name,
|
|
780
756
|
namespace=namespace,
|
|
@@ -782,31 +758,6 @@ class ParseToObjects(Transformer):
|
|
|
782
758
|
metadata=metadata,
|
|
783
759
|
)
|
|
784
760
|
|
|
785
|
-
if concept.metadata:
|
|
786
|
-
concept.metadata.line_number = meta.line
|
|
787
|
-
self.environment.add_concept(concept, meta=meta)
|
|
788
|
-
return ConceptDerivation(concept=concept)
|
|
789
|
-
elif isinstance(source_value, WindowItem):
|
|
790
|
-
|
|
791
|
-
concept = window_item_to_concept(
|
|
792
|
-
source_value,
|
|
793
|
-
name=name,
|
|
794
|
-
namespace=namespace,
|
|
795
|
-
purpose=purpose,
|
|
796
|
-
metadata=metadata,
|
|
797
|
-
)
|
|
798
|
-
if concept.metadata:
|
|
799
|
-
concept.metadata.line_number = meta.line
|
|
800
|
-
self.environment.add_concept(concept, meta=meta)
|
|
801
|
-
return ConceptDerivation(concept=concept)
|
|
802
|
-
elif isinstance(source_value, AggregateWrapper):
|
|
803
|
-
concept = agg_wrapper_to_concept(
|
|
804
|
-
source_value,
|
|
805
|
-
namespace=namespace,
|
|
806
|
-
name=name,
|
|
807
|
-
metadata=metadata,
|
|
808
|
-
purpose=purpose,
|
|
809
|
-
)
|
|
810
761
|
if concept.metadata:
|
|
811
762
|
concept.metadata.line_number = meta.line
|
|
812
763
|
self.environment.add_concept(concept, meta=meta)
|
|
@@ -824,19 +775,6 @@ class ParseToObjects(Transformer):
|
|
|
824
775
|
self.environment.add_concept(concept, meta=meta)
|
|
825
776
|
return ConceptDerivation(concept=concept)
|
|
826
777
|
|
|
827
|
-
elif isinstance(source_value, Function):
|
|
828
|
-
function: Function = source_value
|
|
829
|
-
|
|
830
|
-
concept = function_to_concept(
|
|
831
|
-
function,
|
|
832
|
-
name=name,
|
|
833
|
-
namespace=namespace,
|
|
834
|
-
)
|
|
835
|
-
if concept.metadata:
|
|
836
|
-
concept.metadata.line_number = meta.line
|
|
837
|
-
self.environment.add_concept(concept, meta=meta)
|
|
838
|
-
return ConceptDerivation(concept=concept)
|
|
839
|
-
|
|
840
778
|
raise SyntaxError(
|
|
841
779
|
f"Received invalid type {type(args[2])} {args[2]} as input to select"
|
|
842
780
|
" transform"
|
|
@@ -1219,7 +1157,14 @@ class ParseToObjects(Transformer):
|
|
|
1219
1157
|
def where(self, args):
|
|
1220
1158
|
root = args[0]
|
|
1221
1159
|
if not isinstance(root, (Comparison, Conditional, Parenthetical)):
|
|
1222
|
-
|
|
1160
|
+
if arg_to_datatype(root) == DataType.BOOL:
|
|
1161
|
+
root = Comparison(left=root, right=True, operator=ComparisonOperator.EQ)
|
|
1162
|
+
else:
|
|
1163
|
+
root = Comparison(
|
|
1164
|
+
left=root,
|
|
1165
|
+
right=MagicConstants.NULL,
|
|
1166
|
+
operator=ComparisonOperator.IS_NOT,
|
|
1167
|
+
)
|
|
1223
1168
|
return WhereClause(conditional=root)
|
|
1224
1169
|
|
|
1225
1170
|
@v_args(meta=True)
|
|
@@ -1232,7 +1177,6 @@ class ParseToObjects(Transformer):
|
|
|
1232
1177
|
|
|
1233
1178
|
@v_args(meta=True)
|
|
1234
1179
|
def raw_function(self, meta: Meta, args) -> Function:
|
|
1235
|
-
print(args)
|
|
1236
1180
|
identity = args[0]
|
|
1237
1181
|
fargs = args[1]
|
|
1238
1182
|
output = args[2]
|
|
@@ -1273,6 +1217,22 @@ class ParseToObjects(Transformer):
|
|
|
1273
1217
|
def comparison(self, args) -> Comparison:
|
|
1274
1218
|
return Comparison(left=args[0], right=args[2], operator=args[1])
|
|
1275
1219
|
|
|
1220
|
+
@v_args(meta=True)
|
|
1221
|
+
def subselect_comparison(self, meta: Meta, args) -> SubselectComparison:
|
|
1222
|
+
right = args[2]
|
|
1223
|
+
if not isinstance(right, Concept):
|
|
1224
|
+
right = arbitrary_to_concept(
|
|
1225
|
+
right,
|
|
1226
|
+
namespace=self.environment.namespace,
|
|
1227
|
+
name=f"{VIRTUAL_CONCEPT_PREFIX}_{string_to_hash(str(right))}",
|
|
1228
|
+
)
|
|
1229
|
+
self.environment.add_concept(right)
|
|
1230
|
+
return SubselectComparison(
|
|
1231
|
+
left=args[0],
|
|
1232
|
+
right=right,
|
|
1233
|
+
operator=args[1],
|
|
1234
|
+
)
|
|
1235
|
+
|
|
1276
1236
|
def expr_tuple(self, args):
|
|
1277
1237
|
return Parenthetical(content=args)
|
|
1278
1238
|
|
|
@@ -298,128 +298,6 @@ class Renderer:
|
|
|
298
298
|
def _(self, arg: "FilterItem"):
|
|
299
299
|
return f"filter {self.to_string(arg.content)} where {self.to_string(arg.where)}"
|
|
300
300
|
|
|
301
|
-
@to_string.register
|
|
302
|
-
def _(self, arg: "WindowItem"):
|
|
303
|
-
over = ",".join(self.to_string(c) for c in arg.over)
|
|
304
|
-
order = ",".join(self.to_string(c) for c in arg.order_by)
|
|
305
|
-
if over:
|
|
306
|
-
return (
|
|
307
|
-
f"{arg.type.value} {self.to_string(arg.content)} by {order} OVER {over}"
|
|
308
|
-
)
|
|
309
|
-
return f"{arg.type.value} {self.to_string(arg.content)} by {order}"
|
|
310
|
-
|
|
311
|
-
@to_string.register
|
|
312
|
-
def _(self, arg: "FilterItem"):
|
|
313
|
-
return f"filter {self.to_string(arg.content)} where {self.to_string(arg.where)}"
|
|
314
|
-
|
|
315
|
-
@to_string.register
|
|
316
|
-
def _(self, arg: "ImportStatement"):
|
|
317
|
-
return f"import {arg.path} as {arg.alias};"
|
|
318
|
-
|
|
319
|
-
@to_string.register
|
|
320
|
-
def _(self, arg: "WindowItem"):
|
|
321
|
-
over = ",".join(self.to_string(c) for c in arg.over)
|
|
322
|
-
order = ",".join(self.to_string(c) for c in arg.order_by)
|
|
323
|
-
if over:
|
|
324
|
-
return (
|
|
325
|
-
f"{arg.type.value} {self.to_string(arg.content)} by {order} OVER {over}"
|
|
326
|
-
)
|
|
327
|
-
return f"{arg.type.value} {self.to_string(arg.content)} by {order}"
|
|
328
|
-
|
|
329
|
-
@to_string.register
|
|
330
|
-
def _(self, arg: "FilterItem"):
|
|
331
|
-
return f"filter {self.to_string(arg.content)} where {self.to_string(arg.where)}"
|
|
332
|
-
|
|
333
|
-
@to_string.register
|
|
334
|
-
def _(self, arg: "ImportStatement"):
|
|
335
|
-
return f"import {arg.path} as {arg.alias};"
|
|
336
|
-
|
|
337
|
-
@to_string.register
|
|
338
|
-
def _(self, arg: "WindowItem"):
|
|
339
|
-
over = ",".join(self.to_string(c) for c in arg.over)
|
|
340
|
-
order = ",".join(self.to_string(c) for c in arg.order_by)
|
|
341
|
-
if over:
|
|
342
|
-
return (
|
|
343
|
-
f"{arg.type.value} {self.to_string(arg.content)} by {order} OVER {over}"
|
|
344
|
-
)
|
|
345
|
-
return f"{arg.type.value} {self.to_string(arg.content)} by {order}"
|
|
346
|
-
|
|
347
|
-
@to_string.register
|
|
348
|
-
def _(self, arg: "FilterItem"):
|
|
349
|
-
return f"filter {self.to_string(arg.content)} where {self.to_string(arg.where)}"
|
|
350
|
-
|
|
351
|
-
@to_string.register
|
|
352
|
-
def _(self, arg: "ImportStatement"):
|
|
353
|
-
return f"import {arg.path} as {arg.alias};"
|
|
354
|
-
|
|
355
|
-
@to_string.register
|
|
356
|
-
def _(self, arg: "WindowItem"):
|
|
357
|
-
over = ",".join(self.to_string(c) for c in arg.over)
|
|
358
|
-
order = ",".join(self.to_string(c) for c in arg.order_by)
|
|
359
|
-
if over:
|
|
360
|
-
return (
|
|
361
|
-
f"{arg.type.value} {self.to_string(arg.content)} by {order} OVER {over}"
|
|
362
|
-
)
|
|
363
|
-
return f"{arg.type.value} {self.to_string(arg.content)} by {order}"
|
|
364
|
-
|
|
365
|
-
@to_string.register
|
|
366
|
-
def _(self, arg: "FilterItem"):
|
|
367
|
-
return f"filter {self.to_string(arg.content)} where {self.to_string(arg.where)}"
|
|
368
|
-
|
|
369
|
-
@to_string.register
|
|
370
|
-
def _(self, arg: "ImportStatement"):
|
|
371
|
-
return f"import {arg.path} as {arg.alias};"
|
|
372
|
-
|
|
373
|
-
@to_string.register
|
|
374
|
-
def _(self, arg: "WindowItem"):
|
|
375
|
-
over = ",".join(self.to_string(c) for c in arg.over)
|
|
376
|
-
order = ",".join(self.to_string(c) for c in arg.order_by)
|
|
377
|
-
if over:
|
|
378
|
-
return (
|
|
379
|
-
f"{arg.type.value} {self.to_string(arg.content)} by {order} OVER {over}"
|
|
380
|
-
)
|
|
381
|
-
return f"{arg.type.value} {self.to_string(arg.content)} by {order}"
|
|
382
|
-
|
|
383
|
-
@to_string.register
|
|
384
|
-
def _(self, arg: "FilterItem"):
|
|
385
|
-
return f"filter {self.to_string(arg.content)} where {self.to_string(arg.where)}"
|
|
386
|
-
|
|
387
|
-
@to_string.register
|
|
388
|
-
def _(self, arg: "ImportStatement"):
|
|
389
|
-
return f"import {arg.path} as {arg.alias};"
|
|
390
|
-
|
|
391
|
-
@to_string.register
|
|
392
|
-
def _(self, arg: "WindowItem"):
|
|
393
|
-
over = ",".join(self.to_string(c) for c in arg.over)
|
|
394
|
-
order = ",".join(self.to_string(c) for c in arg.order_by)
|
|
395
|
-
if over:
|
|
396
|
-
return (
|
|
397
|
-
f"{arg.type.value} {self.to_string(arg.content)} by {order} OVER {over}"
|
|
398
|
-
)
|
|
399
|
-
return f"{arg.type.value} {self.to_string(arg.content)} by {order}"
|
|
400
|
-
|
|
401
|
-
@to_string.register
|
|
402
|
-
def _(self, arg: "FilterItem"):
|
|
403
|
-
return f"filter {self.to_string(arg.content)} where {self.to_string(arg.where)}"
|
|
404
|
-
|
|
405
|
-
@to_string.register
|
|
406
|
-
def _(self, arg: "ImportStatement"):
|
|
407
|
-
return f"import {arg.path} as {arg.alias};"
|
|
408
|
-
|
|
409
|
-
@to_string.register
|
|
410
|
-
def _(self, arg: "WindowItem"):
|
|
411
|
-
over = ",".join(self.to_string(c) for c in arg.over)
|
|
412
|
-
order = ",".join(self.to_string(c) for c in arg.order_by)
|
|
413
|
-
if over:
|
|
414
|
-
return (
|
|
415
|
-
f"{arg.type.value} {self.to_string(arg.content)} by {order} OVER {over}"
|
|
416
|
-
)
|
|
417
|
-
return f"{arg.type.value} {self.to_string(arg.content)} by {order}"
|
|
418
|
-
|
|
419
|
-
@to_string.register
|
|
420
|
-
def _(self, arg: "FilterItem"):
|
|
421
|
-
return f"filter {self.to_string(arg.content)} where {self.to_string(arg.where)}"
|
|
422
|
-
|
|
423
301
|
@to_string.register
|
|
424
302
|
def _(self, arg: "ImportStatement"):
|
|
425
303
|
return f"import {arg.path} as {arg.alias};"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/__init__.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/basic_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/concept_merge.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/group_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/group_to_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/rowset_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/select_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/trilogy/core/processing/node_generators/unnest_node.py
RENAMED
|
File without changes
|
{pytrilogy-0.0.1.104 → pytrilogy-0.0.1.105}/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
|