pytrilogy 0.0.2.47__py3-none-any.whl → 0.0.2.48__py3-none-any.whl

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.

Files changed (69) hide show
  1. {pytrilogy-0.0.2.47.dist-info → pytrilogy-0.0.2.48.dist-info}/METADATA +1 -1
  2. pytrilogy-0.0.2.48.dist-info/RECORD +85 -0
  3. trilogy/__init__.py +2 -2
  4. trilogy/constants.py +4 -2
  5. trilogy/core/enums.py +7 -1
  6. trilogy/core/env_processor.py +1 -2
  7. trilogy/core/environment_helpers.py +5 -5
  8. trilogy/core/functions.py +11 -10
  9. trilogy/core/internal.py +2 -3
  10. trilogy/core/models.py +444 -392
  11. trilogy/core/optimization.py +37 -21
  12. trilogy/core/optimizations/__init__.py +1 -1
  13. trilogy/core/optimizations/base_optimization.py +6 -6
  14. trilogy/core/optimizations/inline_constant.py +7 -4
  15. trilogy/core/optimizations/inline_datasource.py +14 -5
  16. trilogy/core/optimizations/predicate_pushdown.py +20 -10
  17. trilogy/core/processing/concept_strategies_v3.py +40 -24
  18. trilogy/core/processing/graph_utils.py +2 -3
  19. trilogy/core/processing/node_generators/__init__.py +7 -5
  20. trilogy/core/processing/node_generators/basic_node.py +4 -4
  21. trilogy/core/processing/node_generators/common.py +10 -11
  22. trilogy/core/processing/node_generators/filter_node.py +7 -9
  23. trilogy/core/processing/node_generators/group_node.py +10 -11
  24. trilogy/core/processing/node_generators/group_to_node.py +5 -5
  25. trilogy/core/processing/node_generators/multiselect_node.py +10 -12
  26. trilogy/core/processing/node_generators/node_merge_node.py +7 -9
  27. trilogy/core/processing/node_generators/rowset_node.py +9 -8
  28. trilogy/core/processing/node_generators/select_merge_node.py +11 -10
  29. trilogy/core/processing/node_generators/select_node.py +5 -5
  30. trilogy/core/processing/node_generators/union_node.py +75 -0
  31. trilogy/core/processing/node_generators/unnest_node.py +2 -3
  32. trilogy/core/processing/node_generators/window_node.py +3 -4
  33. trilogy/core/processing/nodes/__init__.py +9 -5
  34. trilogy/core/processing/nodes/base_node.py +17 -13
  35. trilogy/core/processing/nodes/filter_node.py +3 -4
  36. trilogy/core/processing/nodes/group_node.py +8 -10
  37. trilogy/core/processing/nodes/merge_node.py +11 -11
  38. trilogy/core/processing/nodes/select_node_v2.py +8 -9
  39. trilogy/core/processing/nodes/union_node.py +50 -0
  40. trilogy/core/processing/nodes/unnest_node.py +2 -3
  41. trilogy/core/processing/nodes/window_node.py +2 -3
  42. trilogy/core/processing/utility.py +37 -40
  43. trilogy/core/query_processor.py +68 -44
  44. trilogy/dialect/base.py +95 -53
  45. trilogy/dialect/bigquery.py +2 -3
  46. trilogy/dialect/common.py +5 -4
  47. trilogy/dialect/config.py +0 -2
  48. trilogy/dialect/duckdb.py +2 -2
  49. trilogy/dialect/enums.py +5 -5
  50. trilogy/dialect/postgres.py +2 -2
  51. trilogy/dialect/presto.py +3 -4
  52. trilogy/dialect/snowflake.py +2 -2
  53. trilogy/dialect/sql_server.py +3 -4
  54. trilogy/engine.py +2 -1
  55. trilogy/executor.py +43 -30
  56. trilogy/hooks/base_hook.py +5 -4
  57. trilogy/hooks/graph_hook.py +2 -1
  58. trilogy/hooks/query_debugger.py +18 -8
  59. trilogy/parsing/common.py +15 -20
  60. trilogy/parsing/parse_engine.py +124 -88
  61. trilogy/parsing/render.py +32 -35
  62. trilogy/parsing/trilogy.lark +8 -1
  63. trilogy/scripts/trilogy.py +6 -4
  64. trilogy/utility.py +1 -1
  65. pytrilogy-0.0.2.47.dist-info/RECORD +0 -83
  66. {pytrilogy-0.0.2.47.dist-info → pytrilogy-0.0.2.48.dist-info}/LICENSE.md +0 -0
  67. {pytrilogy-0.0.2.47.dist-info → pytrilogy-0.0.2.48.dist-info}/WHEEL +0 -0
  68. {pytrilogy-0.0.2.47.dist-info → pytrilogy-0.0.2.48.dist-info}/entry_points.txt +0 -0
  69. {pytrilogy-0.0.2.47.dist-info → pytrilogy-0.0.2.48.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,10 @@
1
+ from dataclasses import dataclass
1
2
  from os.path import dirname, join
2
- from typing import List, Optional, Tuple, Union
3
+ from pathlib import Path
3
4
  from re import IGNORECASE
4
- from lark import Lark, Transformer, v_args, Tree, ParseTree
5
+ from typing import List, Optional, Tuple, Union
6
+
7
+ from lark import Lark, ParseTree, Transformer, Tree, v_args
5
8
  from lark.exceptions import (
6
9
  UnexpectedCharacters,
7
10
  UnexpectedEOF,
@@ -9,11 +12,11 @@ from lark.exceptions import (
9
12
  UnexpectedToken,
10
13
  VisitError,
11
14
  )
12
- from pathlib import Path
13
15
  from lark.tree import Meta
14
16
  from pydantic import ValidationError
15
- from trilogy.core.internal import INTERNAL_NAMESPACE, ALL_ROWS_CONCEPT
17
+
16
18
  from trilogy.constants import (
19
+ CONFIG,
17
20
  DEFAULT_NAMESPACE,
18
21
  NULL_VALUE,
19
22
  MagicConstants,
@@ -21,110 +24,111 @@ from trilogy.constants import (
21
24
  from trilogy.core.enums import (
22
25
  BooleanOperator,
23
26
  ComparisonOperator,
27
+ ConceptSource,
28
+ DatePart,
24
29
  FunctionType,
25
30
  InfiniteFunctionArgs,
31
+ IOType,
26
32
  Modifier,
27
33
  Ordering,
28
34
  Purpose,
35
+ ShowCategory,
29
36
  WindowOrder,
30
37
  WindowType,
31
- DatePart,
32
- ShowCategory,
33
- IOType,
34
- ConceptSource,
35
38
  )
36
39
  from trilogy.core.exceptions import InvalidSyntaxException, UndefinedConceptException
37
40
  from trilogy.core.functions import (
41
+ Abs,
42
+ AttrAccess,
43
+ Bool,
44
+ Coalesce,
38
45
  Count,
39
46
  CountDistinct,
47
+ CurrentDate,
48
+ CurrentDatetime,
40
49
  Group,
50
+ IndexAccess,
51
+ IsNull,
52
+ MapAccess,
41
53
  Max,
42
54
  Min,
43
55
  Split,
44
- IndexAccess,
45
- MapAccess,
46
- AttrAccess,
47
- Abs,
56
+ StrPos,
57
+ SubString,
48
58
  Unnest,
49
- Coalesce,
50
59
  function_args_to_output_purpose,
51
- CurrentDate,
52
- CurrentDatetime,
53
- IsNull,
54
- Bool,
55
- SubString,
56
- StrPos,
57
60
  )
61
+ from trilogy.core.internal import ALL_ROWS_CONCEPT, INTERNAL_NAMESPACE
58
62
  from trilogy.core.models import (
59
63
  Address,
64
+ AggregateWrapper,
60
65
  AlignClause,
61
66
  AlignItem,
62
- AggregateWrapper,
63
67
  CaseElse,
64
68
  CaseWhen,
65
69
  ColumnAssignment,
66
70
  Comment,
67
71
  Comparison,
68
- SubselectComparison,
69
72
  Concept,
73
+ ConceptDeclarationStatement,
74
+ ConceptDerivation,
70
75
  ConceptTransform,
71
76
  Conditional,
77
+ CopyStatement,
72
78
  Datasource,
73
- MergeStatementV2,
79
+ DataType,
74
80
  Environment,
81
+ EnvironmentConceptDict,
75
82
  FilterItem,
76
83
  Function,
77
84
  Grain,
85
+ HavingClause,
78
86
  ImportStatement,
79
87
  Limit,
88
+ ListType,
89
+ ListWrapper,
90
+ MapType,
91
+ MapWrapper,
92
+ MergeStatementV2,
80
93
  Metadata,
81
94
  MultiSelectStatement,
95
+ NumericType,
82
96
  OrderBy,
83
97
  OrderItem,
84
98
  Parenthetical,
85
99
  PersistStatement,
86
100
  Query,
101
+ RawColumnExpr,
87
102
  RawSQLStatement,
88
- CopyStatement,
89
- SelectStatement,
103
+ RowsetDerivationStatement,
90
104
  SelectItem,
105
+ SelectStatement,
106
+ ShowStatement,
107
+ StructType,
108
+ SubselectComparison,
109
+ TupleWrapper,
110
+ UndefinedConcept,
91
111
  WhereClause,
92
112
  Window,
93
113
  WindowItem,
94
114
  WindowItemOrder,
95
115
  WindowItemOver,
96
- RawColumnExpr,
97
116
  arg_to_datatype,
98
- merge_datatypes,
99
- ListWrapper,
100
- MapWrapper,
101
- MapType,
102
- ShowStatement,
103
- DataType,
104
- StructType,
105
- ListType,
106
- ConceptDeclarationStatement,
107
- ConceptDerivation,
108
- RowsetDerivationStatement,
117
+ dict_to_map_wrapper,
109
118
  list_to_wrapper,
119
+ merge_datatypes,
110
120
  tuple_to_wrapper,
111
- dict_to_map_wrapper,
112
- NumericType,
113
- HavingClause,
114
- TupleWrapper,
115
121
  )
116
- from trilogy.parsing.exceptions import ParseError
117
122
  from trilogy.parsing.common import (
118
123
  agg_wrapper_to_concept,
119
- window_item_to_concept,
120
- function_to_concept,
121
- filter_item_to_concept,
122
- constant_to_concept,
123
124
  arbitrary_to_concept,
125
+ constant_to_concept,
126
+ filter_item_to_concept,
127
+ function_to_concept,
124
128
  process_function_args,
129
+ window_item_to_concept,
125
130
  )
126
- from dataclasses import dataclass
127
-
131
+ from trilogy.parsing.exceptions import ParseError
128
132
 
129
133
  CONSTANT_TYPES = (int, float, str, bool, list, ListWrapper, MapWrapper)
130
134
 
@@ -195,7 +199,7 @@ def unwrap_transformation(
195
199
  str,
196
200
  float,
197
201
  bool,
198
- ]
202
+ ],
199
203
  ) -> Function | FilterItem | WindowItem | AggregateWrapper:
200
204
  if isinstance(input, Function):
201
205
  return input
@@ -264,7 +268,6 @@ class ParseToObjects(Transformer):
264
268
  if v.pass_count == 2:
265
269
  continue
266
270
  v.hydrate_missing()
267
- self.environment.concepts.fail_on_missing = True
268
271
  reparsed = self.transform(self.tokens[self.token_address])
269
272
  self.environment.concepts.undefined = {}
270
273
  return reparsed
@@ -310,7 +313,8 @@ class ParseToObjects(Transformer):
310
313
 
311
314
  @v_args(meta=True)
312
315
  def concept_lit(self, meta: Meta, args) -> Concept:
313
- return self.environment.concepts.__getitem__(args[0], meta.line)
316
+ address = args[0]
317
+ return self.environment.concepts.__getitem__(address, meta.line)
314
318
 
315
319
  def ADDRESS(self, args) -> Address:
316
320
  return Address(location=args.value, quoted=False)
@@ -429,7 +433,6 @@ class ParseToObjects(Transformer):
429
433
 
430
434
  @v_args(meta=True)
431
435
  def concept_property_declaration(self, meta: Meta, args) -> Concept:
432
-
433
436
  metadata = Metadata()
434
437
  modifiers = []
435
438
  for arg in args:
@@ -488,12 +491,11 @@ class ParseToObjects(Transformer):
488
491
  )
489
492
  if concept.metadata:
490
493
  concept.metadata.line_number = meta.line
491
- self.environment.add_concept(concept, meta=meta)
494
+ self.environment.add_concept(concept, meta=meta, force=True)
492
495
  return ConceptDeclarationStatement(concept=concept)
493
496
 
494
497
  @v_args(meta=True)
495
498
  def concept_derivation(self, meta: Meta, args) -> ConceptDerivation:
496
-
497
499
  if len(args) > 3:
498
500
  metadata = args[3]
499
501
  else:
@@ -604,7 +606,6 @@ class ParseToObjects(Transformer):
604
606
 
605
607
  @v_args(meta=True)
606
608
  def concept(self, meta: Meta, args) -> ConceptDeclarationStatement:
607
-
608
609
  if isinstance(args[0], Concept):
609
610
  concept: Concept = args[0]
610
611
  else:
@@ -680,7 +681,6 @@ class ParseToObjects(Transformer):
680
681
 
681
682
  @v_args(meta=True)
682
683
  def select_transform(self, meta: Meta, args) -> ConceptTransform:
683
-
684
684
  output: str = args[1]
685
685
  transformation = unwrap_transformation(args[0])
686
686
  lookup, namespace, output, parent = parse_concept_reference(
@@ -712,7 +712,6 @@ class ParseToObjects(Transformer):
712
712
  else:
713
713
  raise SyntaxError("Invalid transformation")
714
714
 
715
- self.environment.add_concept(concept, meta=meta)
716
715
  return ConceptTransform(function=transformation, output=concept)
717
716
 
718
717
  @v_args(meta=True)
@@ -761,7 +760,6 @@ class ParseToObjects(Transformer):
761
760
  return Ordering(base)
762
761
 
763
762
  def order_list(self, args):
764
-
765
763
  def handle_order_item(x, namespace: str):
766
764
  if not isinstance(x, Concept):
767
765
  x = arbitrary_to_concept(
@@ -843,7 +841,6 @@ class ParseToObjects(Transformer):
843
841
 
844
842
  @v_args(meta=True)
845
843
  def copy_statement(self, meta: Meta, args) -> CopyStatement:
846
-
847
844
  return CopyStatement(
848
845
  target=args[1],
849
846
  target_type=args[0],
@@ -959,7 +956,7 @@ class ParseToObjects(Transformer):
959
956
 
960
957
  @v_args(meta=True)
961
958
  def multi_select_statement(self, meta: Meta, args) -> MultiSelectStatement:
962
- selects = []
959
+ selects: list[SelectStatement] = []
963
960
  align: AlignClause | None = None
964
961
  limit: int | None = None
965
962
  order_by: OrderBy | None = None
@@ -978,6 +975,10 @@ class ParseToObjects(Transformer):
978
975
 
979
976
  assert align
980
977
  assert align is not None
978
+ base_local: EnvironmentConceptDict = selects[0].local_concepts
979
+ for select in selects[1:]:
980
+ for k, v in select.local_concepts.items():
981
+ base_local[k] = v
981
982
  multi = MultiSelectStatement(
982
983
  selects=selects,
983
984
  align=align,
@@ -986,6 +987,7 @@ class ParseToObjects(Transformer):
986
987
  order_by=order_by,
987
988
  limit=limit,
988
989
  meta=Metadata(line_number=meta.line),
990
+ local_concepts=base_local,
989
991
  )
990
992
  for concept in multi.derived_concepts:
991
993
  self.environment.add_concept(concept, meta=meta)
@@ -1019,34 +1021,55 @@ class ParseToObjects(Transformer):
1019
1021
  order_by=order_by,
1020
1022
  meta=Metadata(line_number=meta.line),
1021
1023
  )
1022
- for item in select_items:
1023
- # we don't know the grain of an aggregate at assignment time
1024
- # so rebuild at this point in the tree
1025
- # TODO: simplify
1026
- if isinstance(item.content, ConceptTransform):
1027
- new_concept = item.content.output.with_select_context(
1028
- output.grain,
1029
- conditional=None,
1030
- environment=self.environment,
1031
- )
1032
- self.environment.add_concept(new_concept, meta=meta)
1033
- item.content.output = new_concept
1034
- elif isinstance(item.content, Concept):
1035
- # Sometimes cached values here don't have the latest info
1036
- # but we can't just use environment, as it might not have the right grain.
1037
- item.content = self.environment.concepts[
1038
- item.content.address
1039
- ].with_grain(item.content.grain)
1024
+ for parse_pass in [1, 2]:
1025
+ # the first pass will result in all concepts being defined
1026
+ # the second will get grains appropriately
1027
+ # eg if someone does sum(x)->a, b+c -> z - we don't know if Z is a key to group by or an aggregate
1028
+ # until after the first pass, and so don't know the grain of a
1029
+ nselect = []
1030
+ for item in select_items:
1031
+ # we don't know the grain of an aggregate at assignment time
1032
+ # so rebuild at this point in the tree
1033
+ # TODO: simplify
1034
+ if isinstance(item.content, ConceptTransform):
1035
+ new_concept = item.content.output.with_select_context(
1036
+ output.local_concepts,
1037
+ output.grain,
1038
+ environment=self.environment,
1039
+ )
1040
+ output.local_concepts[new_concept.address] = new_concept
1041
+ item.content.output = new_concept
1042
+ if parse_pass == 2 and CONFIG.select_as_definition:
1043
+ self.environment.add_concept(new_concept)
1044
+ elif isinstance(item.content, UndefinedConcept):
1045
+ self.environment.concepts.raise_undefined(
1046
+ item.content.address,
1047
+ line_no=item.content.metadata.line_number,
1048
+ file=self.token_address,
1049
+ )
1050
+ elif isinstance(item.content, Concept):
1051
+ # Sometimes cached values here don't have the latest info
1052
+ # but we can't just use environment, as it might not have the right grain.
1053
+ item.content = item.content.with_select_context(
1054
+ output.local_concepts,
1055
+ output.grain,
1056
+ environment=self.environment,
1057
+ )
1058
+ output.local_concepts[item.content.address] = item.content
1059
+ nselect.append(item)
1040
1060
  if order_by:
1041
- for orderitem in order_by.items:
1042
- if isinstance(orderitem.expr, Concept):
1043
- if orderitem.expr.purpose == Purpose.METRIC:
1044
- orderitem.expr = orderitem.expr.with_select_context(
1045
- output.grain,
1046
- conditional=None,
1047
- environment=self.environment,
1048
- )
1049
- output.validate_syntax()
1061
+ output.order_by = order_by.with_select_context(
1062
+ local_concepts=output.local_concepts,
1063
+ grain=output.grain,
1064
+ environment=self.environment,
1065
+ )
1066
+ if output.having_clause:
1067
+ output.having_clause = output.having_clause.with_select_context(
1068
+ local_concepts=output.local_concepts,
1069
+ grain=output.grain,
1070
+ environment=self.environment,
1071
+ )
1072
+ output.validate_syntax(self.environment)
1050
1073
  return output
1051
1074
 
1052
1075
  @v_args(meta=True)
@@ -1126,7 +1149,6 @@ class ParseToObjects(Transformer):
1126
1149
  return args[0]
1127
1150
 
1128
1151
  def struct_lit(self, args):
1129
-
1130
1152
  zipped = dict(zip(args[::2], args[1::2]))
1131
1153
  types = [arg_to_datatype(x) for x in args[1::2]]
1132
1154
  return Function(
@@ -1422,10 +1444,23 @@ class ParseToObjects(Transformer):
1422
1444
  output_datatype=DataType.STRING,
1423
1445
  output_purpose=Purpose.PROPERTY,
1424
1446
  valid_inputs={DataType.STRING},
1425
- arg_count=99,
1447
+ arg_count=-1,
1426
1448
  # output_grain=args[0].grain,
1427
1449
  )
1428
1450
 
1451
+ @v_args(meta=True)
1452
+ def union(self, meta, args):
1453
+ args = process_function_args(args, meta=meta, environment=self.environment)
1454
+ output_datatype = merge_datatypes([arg_to_datatype(x) for x in args])
1455
+ return Function(
1456
+ operator=FunctionType.UNION,
1457
+ arguments=args,
1458
+ output_datatype=output_datatype,
1459
+ output_purpose=Purpose.KEY,
1460
+ valid_inputs={*DataType},
1461
+ arg_count=-1,
1462
+ )
1463
+
1429
1464
  @v_args(meta=True)
1430
1465
  def like(self, meta, args):
1431
1466
  args = process_function_args(args, meta=meta, environment=self.environment)
@@ -1945,6 +1980,7 @@ def parse_text(text: str, environment: Optional[Environment] = None) -> Tuple[
1945
1980
  # this will reset fail on missing
1946
1981
  pass_two = parser.hydrate_missing()
1947
1982
  output = [v for v in pass_two if v]
1983
+ environment.concepts.fail_on_missing = True
1948
1984
  except VisitError as e:
1949
1985
  unpack_visit_error(e)
1950
1986
  # this will never be reached
trilogy/parsing/render.py CHANGED
@@ -1,55 +1,52 @@
1
+ from collections import defaultdict
1
2
  from functools import singledispatchmethod
2
3
 
3
4
  from jinja2 import Template
4
5
 
5
- from trilogy.constants import DEFAULT_NAMESPACE, MagicConstants, VIRTUAL_CONCEPT_PREFIX
6
- from trilogy.core.enums import Purpose, ConceptSource, DatePart, FunctionType
6
+ from trilogy.constants import DEFAULT_NAMESPACE, VIRTUAL_CONCEPT_PREFIX, MagicConstants
7
+ from trilogy.core.enums import ConceptSource, DatePart, FunctionType, Modifier, Purpose
7
8
  from trilogy.core.models import (
8
- DataType,
9
9
  Address,
10
- Query,
11
- Concept,
12
- ConceptTransform,
13
- Function,
14
- Grain,
15
- OrderItem,
16
- SelectStatement,
17
- SelectItem,
18
- WhereClause,
19
- Conditional,
20
- SubselectComparison,
10
+ AggregateWrapper,
11
+ AlignClause,
12
+ AlignItem,
13
+ CaseElse,
14
+ CaseWhen,
15
+ ColumnAssignment,
21
16
  Comparison,
22
- Environment,
17
+ Concept,
23
18
  ConceptDeclarationStatement,
24
19
  ConceptDerivation,
20
+ ConceptTransform,
21
+ Conditional,
22
+ CopyStatement,
25
23
  Datasource,
26
- WindowItem,
24
+ DataType,
25
+ Environment,
27
26
  FilterItem,
28
- ColumnAssignment,
29
- RawColumnExpr,
30
- CaseElse,
31
- CaseWhen,
27
+ Function,
28
+ Grain,
32
29
  ImportStatement,
33
- Parenthetical,
34
- AggregateWrapper,
35
- PersistStatement,
36
- ListWrapper,
37
30
  ListType,
38
- TupleWrapper,
39
- RowsetDerivationStatement,
31
+ ListWrapper,
32
+ MergeStatementV2,
40
33
  MultiSelectStatement,
34
+ NumericType,
41
35
  OrderBy,
42
- AlignClause,
43
- AlignItem,
36
+ OrderItem,
37
+ Parenthetical,
38
+ PersistStatement,
39
+ Query,
40
+ RawColumnExpr,
44
41
  RawSQLStatement,
45
- NumericType,
46
- MergeStatementV2,
47
- CopyStatement,
42
+ RowsetDerivationStatement,
43
+ SelectItem,
44
+ SelectStatement,
45
+ SubselectComparison,
46
+ TupleWrapper,
47
+ WhereClause,
48
+ WindowItem,
48
49
  )
49
- from trilogy.core.enums import Modifier
50
-
51
- from collections import defaultdict
52
-
53
50
 
54
51
  QUERY_TEMPLATE = Template(
55
52
  """{% if where %}WHERE
@@ -79,6 +79,8 @@
79
79
  // raw sql statement
80
80
  rawsql_statement: "raw_sql"i "(" MULTILINE_STRING ")"
81
81
 
82
+
83
+
82
84
  // copy statement
83
85
 
84
86
  COPY_TYPE: "csv"i
@@ -166,12 +168,17 @@
166
168
  //unnesting is a function
167
169
  _UNNEST.1: "UNNEST("i
168
170
  unnest: _UNNEST expr ")"
171
+
172
+ // union statement
173
+ _UNION.1: "UNION("i
174
+ union: _UNION (expr ",")* expr ")"
175
+
169
176
  //indexing into an expression is a function
170
177
  index_access: expr "[" int_lit "]"
171
178
  map_key_access: expr "[" string_lit "]"
172
179
  attr_access: expr "." string_lit
173
180
 
174
- expr: _constant_functions | window_item | filter_item | subselect_comparison | between_comparison | fgroup | aggregate_functions | unnest | _static_functions | literal | concept_lit | index_access | map_key_access | attr_access | parenthetical | expr_tuple | comparison | alt_like
181
+ expr: _constant_functions | window_item | filter_item | subselect_comparison | between_comparison | fgroup | aggregate_functions | unnest | union | _static_functions | literal | concept_lit | index_access | map_key_access | attr_access | parenthetical | expr_tuple | comparison | alt_like
175
182
 
176
183
  // functions
177
184
 
@@ -1,11 +1,13 @@
1
- from click import Path, argument, option, group, pass_context, UNPROCESSED
2
- from trilogy import Executor, Environment, parse
3
- from trilogy.dialect.enums import Dialects
4
1
  from datetime import datetime
5
2
  from pathlib import Path as PathlibPath
3
+
4
+ from click import UNPROCESSED, Path, argument, group, option, pass_context
5
+
6
+ from trilogy import Environment, Executor, parse
7
+ from trilogy.constants import DEFAULT_NAMESPACE
8
+ from trilogy.dialect.enums import Dialects
6
9
  from trilogy.hooks.query_debugger import DebuggingHook
7
10
  from trilogy.parsing.render import Renderer
8
- from trilogy.constants import DEFAULT_NAMESPACE
9
11
 
10
12
 
11
13
  def print_tabulate(q, tabulate):
trilogy/utility.py CHANGED
@@ -1,5 +1,5 @@
1
1
  import hashlib
2
- from typing import List, Any, Union, Callable
2
+ from typing import Any, Callable, List, Union
3
3
 
4
4
  from trilogy.constants import DEFAULT_NAMESPACE
5
5
 
@@ -1,83 +0,0 @@
1
- trilogy/__init__.py,sha256=1AtwhSy-U-0z7qVDt7pbGMULzjuha1IHXXyCkuZwRiw,291
2
- trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- trilogy/constants.py,sha256=UPymm94T2c6a55XdDaXw0aleTe1pOJ6lf6gOWLKZyKg,1430
4
- trilogy/engine.py,sha256=R5ubIxYyrxRExz07aZCUfrTsoXCHQ8DKFTDsobXdWdA,1102
5
- trilogy/executor.py,sha256=mgWg9VR3V6Uo_sNmHtpAtT2ikYvXXFzo7QTWtbQJig4,15398
6
- trilogy/parser.py,sha256=UtuqSiGiCjpMAYgo1bvNq-b7NSzCA5hzbUW31RXaMII,281
7
- trilogy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- trilogy/utility.py,sha256=zM__8r29EsyDW7K9VOHz8yvZC2bXFzh7xKy3cL7GKsk,707
9
- trilogy/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- trilogy/core/constants.py,sha256=7XaCpZn5mQmjTobbeBn56SzPWq9eMNDfzfsRU-fP0VE,171
11
- trilogy/core/enums.py,sha256=z-qBLh0YW52tkRtp6VLn6afxLfgI45r7_QfDtGH9CSw,6858
12
- trilogy/core/env_processor.py,sha256=SHVB3nkidIlFc5dz-sofRMKXx66stpLQNuVdQSjC-So,2586
13
- trilogy/core/environment_helpers.py,sha256=DIsoo-GcXmXVPB1JbNh8Oku25Nyef9mexPIdy2ur_sk,7159
14
- trilogy/core/ergonomics.py,sha256=ASLDd0RqKWrZiG3XcKHo8nyTjaB_8xfE9t4NZ1UvGpc,1639
15
- trilogy/core/exceptions.py,sha256=1c1lQCwSw4_5CQS3q7scOkXU8GQvullJXfPHubprl90,617
16
- trilogy/core/functions.py,sha256=IhVpt3n6wEanKHnGu3oA2w6-hKIlxWpEyz7fHN66mpo,10720
17
- trilogy/core/graph_models.py,sha256=mameUTiuCajtihDw_2-W218xyJlvTusOWrEKP1yAWgk,2003
18
- trilogy/core/internal.py,sha256=jNGFHKENnbMiMCtAgsnLZYVSENDK4b5ALecXFZpTDzQ,1075
19
- trilogy/core/models.py,sha256=Hk25VWc8mA6eJNozhoNaP3_Rx7ECpCYXXQaanS_pwn4,164150
20
- trilogy/core/optimization.py,sha256=VFSvJLNoCCOraip-PZUKeE4qrlxtXARjQUzJZiW-yRk,7325
21
- trilogy/core/query_processor.py,sha256=mbcZlgjChrRjDHkdmMbKe-T70UpbBkJhS09MyU5a6UY,17785
22
- trilogy/core/optimizations/__init__.py,sha256=bWQecbeiwiDx9LJnLsa7dkWxdbl2wcnkcTN69JyP8iI,356
23
- trilogy/core/optimizations/base_optimization.py,sha256=tWWT-xnTbnEU-mNi_isMNbywm8B9WTRsNFwGpeh3rqE,468
24
- trilogy/core/optimizations/inline_constant.py,sha256=kHNyc2UoaPVdYfVAPAFwnWuk4sJ_IF5faRtVcDOrBtw,1110
25
- trilogy/core/optimizations/inline_datasource.py,sha256=NqUOVl0pOXF1R_roELVW8I0qN7or2wPtAsRmDD9QJso,3658
26
- trilogy/core/optimizations/predicate_pushdown.py,sha256=oJy09U7lb8FMKexWISjg4Ksyf98Nx22bzIxmm9WuXtk,8899
27
- trilogy/core/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- trilogy/core/processing/concept_strategies_v3.py,sha256=Qy3WHiKaF371dDmbA0DWVQqSMKptH_gK714Uc41wbqc,36132
29
- trilogy/core/processing/graph_utils.py,sha256=aq-kqk4Iado2HywDxWEejWc-7PGO6Oa-ZQLAM6XWPHw,1199
30
- trilogy/core/processing/utility.py,sha256=_sWLDuV8WAEWdEIcAPM8-FcXgBai30UV12i4O9u5Mpc,18680
31
- trilogy/core/processing/node_generators/__init__.py,sha256=-mzYkRsaRNa_dfTckYkKVFSR8h8a3ihEiPJDU_tAmDo,672
32
- trilogy/core/processing/node_generators/basic_node.py,sha256=qsQ8HegQ2qOSpXFleq7yHJ-rYfF6XQGCC7h2pC-t1kQ,2878
33
- trilogy/core/processing/node_generators/common.py,sha256=eslHTTPFTkmwHwKIuUsbFn54jxj-Avtt-QScqtNwzdg,8945
34
- trilogy/core/processing/node_generators/filter_node.py,sha256=Vz9Rb67e1dfZgnliekwwLeDPVkthMbdrnrKRdz7J1ik,7654
35
- trilogy/core/processing/node_generators/group_node.py,sha256=r54IVEhXW-tzod6uEHIQObrxgQt6aNySk5emWkWyqCU,4938
36
- trilogy/core/processing/node_generators/group_to_node.py,sha256=R9i_wHipxjXJyfYEwfeTw2EPpuanXVA327XyfcP2tBg,2537
37
- trilogy/core/processing/node_generators/multiselect_node.py,sha256=Prn0tWu6gpxyP1tJywVoMG6YAKB8kVRRpPMYdqnl6SE,6583
38
- trilogy/core/processing/node_generators/node_merge_node.py,sha256=dIEv5P2MTViAES2MzqJgccYzM3HldjHrQYFwH00cqyc,14003
39
- trilogy/core/processing/node_generators/rowset_node.py,sha256=KtdN6t2xM8CJxobc4aQX4W8uX98U6IabeuBF_FtBLR4,4583
40
- trilogy/core/processing/node_generators/select_merge_node.py,sha256=zVPSYzhl-jSMobL7L1JauG03yNMkhKp0-tOVXiuC0Vo,12690
41
- trilogy/core/processing/node_generators/select_node.py,sha256=xTCWOoucRPBWkTccm5wepidhuZix-wd0YXWyOsy8nLs,1795
42
- trilogy/core/processing/node_generators/unnest_node.py,sha256=cZ26CN338CBnd6asML1OBUtNcDzmNlFpY0Vnade4yrc,2256
43
- trilogy/core/processing/node_generators/window_node.py,sha256=Ywb2K0T5Ym_Y4XStzIE2fuWV1fW2dp5eQ2hXVFTLsGM,3511
44
- trilogy/core/processing/nodes/__init__.py,sha256=qS5EJDRwwIrCEfS7ibCA2ESE0RPzsAIii1UWd_wNsHA,4760
45
- trilogy/core/processing/nodes/base_node.py,sha256=sc3HrXkWk-xpsAQ7B7ltX1ZejYAkqFiv8Ei8Jg5VGkQ,15579
46
- trilogy/core/processing/nodes/filter_node.py,sha256=GfZ9eghpFDI-s7iQP2UqTljCmn25LT_T5TAxDlh7PkQ,2343
47
- trilogy/core/processing/nodes/group_node.py,sha256=PrBHaGq_f8RmokUw9lXLGJ5YbjdP77P7Ag0pgR6e2cU,7293
48
- trilogy/core/processing/nodes/merge_node.py,sha256=W3eCjmJbs8Wfw7Y5AgIY2pP-ntPCrrMe11UG-QGJvA8,14835
49
- trilogy/core/processing/nodes/select_node_v2.py,sha256=7WoFxeGEAzhpS4y4Zw2nH2tt7OzdlLfMvDFoLF_vb4Y,8108
50
- trilogy/core/processing/nodes/unnest_node.py,sha256=mAmFluzm2yeeiQ6NfIB7BU_8atRGh-UJfPf9ROwbhr8,2152
51
- trilogy/core/processing/nodes/window_node.py,sha256=ro0QfMFi4ZmIn5Q4D0M_vJWfnHH_C0MN7XkVkx8Gygg,1214
52
- trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
- trilogy/dialect/base.py,sha256=YyJy20CNJfOmuHg-WhYEwIamJzAQxb48_lqghriTm8c,36261
54
- trilogy/dialect/bigquery.py,sha256=15KJ-cOpBlk9O7FPviPgmg8xIydJeKx7WfmL3SSsPE8,2953
55
- trilogy/dialect/common.py,sha256=eqJi_Si1iyb2sV0siTf8g8JOHueWu6RkdtQZtutKazk,3826
56
- trilogy/dialect/config.py,sha256=tLVEMctaTDhUgARKXUNfHUcIolGaALkQ0RavUvXAY4w,2994
57
- trilogy/dialect/duckdb.py,sha256=_0a5HBU8zRNtZj7YED3ju4fHXRYG9jNeKwnlZwUDvwI,3419
58
- trilogy/dialect/enums.py,sha256=4NdpsydBpDn6jnh0JzFz5VvQEtnShErWtWHVyT6TNpw,3948
59
- trilogy/dialect/postgres.py,sha256=ev1RJZsC8BB3vJSxJ4q-TTYqZ4Hk1NXUtuRkLrQEBX0,3254
60
- trilogy/dialect/presto.py,sha256=2Rs53UfPxKU0rJTcEbiS-Lxm-CDiqUGojh7yRpQgyRE,3416
61
- trilogy/dialect/snowflake.py,sha256=_Bf4XO7-nImMv9XCSsTfVM3g2f_KHdO17VTa9J-HgSM,2989
62
- trilogy/dialect/sql_server.py,sha256=owUZbMFrooYIMj1DSLstPWxPO7K7WAUEWNvDKM-DMt0,3118
63
- trilogy/hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
- trilogy/hooks/base_hook.py,sha256=Xkb-A2qCHozYjum0A36zOy5PwTVwrP3NLDF0U2GpgHo,1100
65
- trilogy/hooks/graph_hook.py,sha256=onHvMQPwj_KOS3HOTpRFiy7QLLKAiycq2MzJ_Q0Oh5Y,2467
66
- trilogy/hooks/query_debugger.py,sha256=787umJjdGA057DCC714dqFstzJRUbwmz3MNr66IdpQI,4404
67
- trilogy/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
- trilogy/parsing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
69
- trilogy/parsing/common.py,sha256=3kly4cH36F_8nwR1evKB5_yk1ezEtwwoeav4PrHUJ6o,10417
70
- trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
71
- trilogy/parsing/exceptions.py,sha256=92E5i2frv5hj9wxObJZsZqj5T6bglvPzvdvco_vW1Zk,38
72
- trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
73
- trilogy/parsing/parse_engine.py,sha256=fWE_0n30ecBdlT6OvAZL5DYJRs-q2MiD-m8wqxQ_9XE,65201
74
- trilogy/parsing/render.py,sha256=-qqpXQg4yHcv284Vosjnsc_vrPveH6oaYbeCd3ZSvs0,15682
75
- trilogy/parsing/trilogy.lark,sha256=B6NM3-rBHtYB_WSEti0DiS8Z-I8YH3kZU47xNzQvBx4,12389
76
- trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
- trilogy/scripts/trilogy.py,sha256=PHxvv6f2ODv0esyyhWxlARgra8dVhqQhYl0lTrSyVNo,3729
78
- pytrilogy-0.0.2.47.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
79
- pytrilogy-0.0.2.47.dist-info/METADATA,sha256=Mb0qndiqtvzvG5pNpM-PE3qSZKQmtKa-Gdsv5CDdOFc,8426
80
- pytrilogy-0.0.2.47.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
81
- pytrilogy-0.0.2.47.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
82
- pytrilogy-0.0.2.47.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
83
- pytrilogy-0.0.2.47.dist-info/RECORD,,