pytrilogy 0.0.1.113__tar.gz → 0.0.1.115__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.

Files changed (100) hide show
  1. {pytrilogy-0.0.1.113/pytrilogy.egg-info → pytrilogy-0.0.1.115}/PKG-INFO +1 -1
  2. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115/pytrilogy.egg-info}/PKG-INFO +1 -1
  3. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/pytrilogy.egg-info/SOURCES.txt +1 -0
  4. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/setup.py +1 -1
  5. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_parsing.py +29 -0
  6. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/__init__.py +1 -1
  7. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/models.py +3 -1
  8. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/parsing/parse_engine.py +6 -3
  9. pytrilogy-0.0.1.115/trilogy/parsing/trilogy.lark +300 -0
  10. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/LICENSE.md +0 -0
  11. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/README.md +0 -0
  12. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/pyproject.toml +0 -0
  13. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/pytrilogy.egg-info/dependency_links.txt +0 -0
  14. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/pytrilogy.egg-info/entry_points.txt +0 -0
  15. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/pytrilogy.egg-info/requires.txt +0 -0
  16. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/pytrilogy.egg-info/top_level.txt +0 -0
  17. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/setup.cfg +0 -0
  18. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_declarations.py +0 -0
  19. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_derived_concepts.py +0 -0
  20. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_discovery_nodes.py +0 -0
  21. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_environment.py +0 -0
  22. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_functions.py +0 -0
  23. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_imports.py +0 -0
  24. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_metadata.py +0 -0
  25. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_models.py +0 -0
  26. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_multi_join_assignments.py +0 -0
  27. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_partial_handling.py +0 -0
  28. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_query_processing.py +0 -0
  29. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_select.py +0 -0
  30. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_statements.py +0 -0
  31. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_undefined_concept.py +0 -0
  32. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/tests/test_where_clause.py +0 -0
  33. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/compiler.py +0 -0
  34. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/constants.py +0 -0
  35. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/__init__.py +0 -0
  36. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/constants.py +0 -0
  37. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/enums.py +0 -0
  38. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/env_processor.py +0 -0
  39. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/environment_helpers.py +0 -0
  40. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/ergonomics.py +0 -0
  41. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/exceptions.py +0 -0
  42. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/functions.py +0 -0
  43. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/graph_models.py +0 -0
  44. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/internal.py +0 -0
  45. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/optimization.py +0 -0
  46. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/__init__.py +0 -0
  47. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/concept_strategies_v3.py +0 -0
  48. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/graph_utils.py +0 -0
  49. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/node_generators/__init__.py +0 -0
  50. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/node_generators/basic_node.py +0 -0
  51. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/node_generators/common.py +0 -0
  52. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/node_generators/concept_merge_node.py +0 -0
  53. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/node_generators/filter_node.py +0 -0
  54. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/node_generators/group_node.py +0 -0
  55. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
  56. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
  57. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
  58. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
  59. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/node_generators/select_node.py +0 -0
  60. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
  61. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/node_generators/window_node.py +0 -0
  62. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/nodes/__init__.py +0 -0
  63. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/nodes/base_node.py +0 -0
  64. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/nodes/filter_node.py +0 -0
  65. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/nodes/group_node.py +0 -0
  66. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/nodes/merge_node.py +0 -0
  67. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
  68. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/nodes/unnest_node.py +0 -0
  69. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/nodes/window_node.py +0 -0
  70. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/processing/utility.py +0 -0
  71. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/core/query_processor.py +0 -0
  72. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/dialect/__init__.py +0 -0
  73. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/dialect/base.py +0 -0
  74. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/dialect/bigquery.py +0 -0
  75. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/dialect/common.py +0 -0
  76. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/dialect/config.py +0 -0
  77. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/dialect/duckdb.py +0 -0
  78. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/dialect/enums.py +0 -0
  79. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/dialect/postgres.py +0 -0
  80. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/dialect/presto.py +0 -0
  81. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/dialect/snowflake.py +0 -0
  82. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/dialect/sql_server.py +0 -0
  83. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/engine.py +0 -0
  84. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/executor.py +0 -0
  85. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/hooks/__init__.py +0 -0
  86. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/hooks/base_hook.py +0 -0
  87. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/hooks/graph_hook.py +0 -0
  88. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/hooks/query_debugger.py +0 -0
  89. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/metadata/__init__.py +0 -0
  90. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/parser.py +0 -0
  91. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/parsing/__init__.py +0 -0
  92. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/parsing/common.py +0 -0
  93. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/parsing/config.py +0 -0
  94. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/parsing/exceptions.py +0 -0
  95. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/parsing/helpers.py +0 -0
  96. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/parsing/render.py +0 -0
  97. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/py.typed +0 -0
  98. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/scripts/__init__.py +0 -0
  99. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/scripts/trilogy.py +0 -0
  100. {pytrilogy-0.0.1.113 → pytrilogy-0.0.1.115}/trilogy/utility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytrilogy
3
- Version: 0.0.1.113
3
+ Version: 0.0.1.115
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytrilogy
3
- Version: 0.0.1.113
3
+ Version: 0.0.1.115
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -93,5 +93,6 @@ trilogy/parsing/exceptions.py
93
93
  trilogy/parsing/helpers.py
94
94
  trilogy/parsing/parse_engine.py
95
95
  trilogy/parsing/render.py
96
+ trilogy/parsing/trilogy.lark
96
97
  trilogy/scripts/__init__.py
97
98
  trilogy/scripts/trilogy.py
@@ -40,7 +40,7 @@ setuptools.setup(
40
40
  ]
41
41
  ),
42
42
  package_data={
43
- "": ["*.tf", "*.jinja", "py.typed"],
43
+ "": ["*.tf", "*.jinja", "py.typed", "*.lark"],
44
44
  },
45
45
  install_requires=install_requires,
46
46
  extras_require={
@@ -263,3 +263,32 @@ def test_the_comments():
263
263
  assert isinstance(right, MagicConstants), type(right)
264
264
  rendered = BaseDialect().render_expr(right)
265
265
  assert rendered == "null"
266
+
267
+
268
+ def test_purpose_nesting():
269
+
270
+ env, parsed = parse_text(
271
+ """key year int;
272
+ """
273
+ )
274
+
275
+ env2: Environment = Environment()
276
+ env2.add_import("dates", env)
277
+
278
+ env2, _ = parse_text(
279
+ """
280
+ property <dates.year>.generation <-
281
+ CASE WHEN dates.year BETWEEN 1883 AND 1900 THEN 'Lost Generation'
282
+ WHEN dates.year BETWEEN 1901 AND 1927 THEN 'The Greatest Generation'
283
+ WHEN dates.year BETWEEN 1928 AND 1945 THEN 'The Silent Generation'
284
+ WHEN dates.year BETWEEN 1946 AND 1964 THEN 'Baby Boomer'
285
+ WHEN dates.year BETWEEN 1965 AND 1980 THEN 'Generation X'
286
+ WHEN dates.year BETWEEN 1981 AND 1996 THEN 'Millennials'
287
+ WHEN dates.year BETWEEN 1997 AND 2012 THEN 'Generation Z'
288
+ ELSE 'Unknown'
289
+ END;
290
+ """,
291
+ env2,
292
+ )
293
+
294
+ assert env2.concepts["dates.generation"].purpose == Purpose.PROPERTY
@@ -4,6 +4,6 @@ from trilogy.executor import Executor
4
4
  from trilogy.parser import parse
5
5
  from trilogy.constants import CONFIG
6
6
 
7
- __version__ = "0.0.1.113"
7
+ __version__ = "0.0.1.115"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
@@ -2669,7 +2669,8 @@ class Environment(BaseModel):
2669
2669
 
2670
2670
 
2671
2671
  class LazyEnvironment(Environment):
2672
- """Variant of environment to defer parsing of a path"""
2672
+ """Variant of environment to defer parsing of a path
2673
+ until relevant attributes accessed."""
2673
2674
 
2674
2675
  load_path: Path
2675
2676
  loaded: bool = False
@@ -2681,6 +2682,7 @@ class LazyEnvironment(Environment):
2681
2682
  "working_path",
2682
2683
  "model_config",
2683
2684
  "model_fields",
2685
+ "model_post_init",
2684
2686
  ) or name.startswith("_"):
2685
2687
  return super().__getattribute__(name)
2686
2688
  if not self.loaded:
@@ -465,16 +465,19 @@ class ParseToObjects(Transformer):
465
465
  if purpose == Purpose.AUTO:
466
466
  purpose = None
467
467
  raw_name = args[1]
468
+ # abc.def.property pattern
468
469
  if isinstance(raw_name, str):
469
470
  lookup, namespace, name, parent_concept = parse_concept_reference(
470
471
  raw_name, self.environment, purpose
471
472
  )
473
+ # <abc.def,zef.gf>.property pattern
472
474
  else:
473
475
  keys, name = raw_name
474
- if "." in name:
475
- namespace, name = name.rsplit(".", 1)
476
- else:
476
+ namespaces = set([x.namespace for x in keys])
477
+ if not len(namespaces) == 1:
477
478
  namespace = self.environment.namespace or DEFAULT_NAMESPACE
479
+ else:
480
+ namespace = namespaces.pop()
478
481
  source_value = args[2]
479
482
  # we need to strip off every parenthetical to see what is being assigned.
480
483
  while isinstance(source_value, Parenthetical):
@@ -0,0 +1,300 @@
1
+ !start: ( block | show_statement )*
2
+ block: statement _TERMINATOR PARSE_COMMENT?
3
+ ?statement: concept
4
+ | datasource
5
+ | function
6
+ | multi_select_statement
7
+ | select_statement
8
+ | persist_statement
9
+ | rowset_derivation_statement
10
+ | import_statement
11
+ | merge_statement
12
+
13
+ _TERMINATOR: ";"i /\s*/
14
+
15
+ PARSE_COMMENT.1: /#.*(\n|$)/ | /\/\/.*\n/
16
+
17
+ // property display_name string
18
+ concept_declaration: PURPOSE IDENTIFIER data_type concept_nullable_modifier? metadata?
19
+ //customer_id.property first_name STRING;
20
+ //<customer_id,country>.property local_alias STRING
21
+ concept_property_declaration: PROPERTY (prop_ident | IDENTIFIER) data_type concept_nullable_modifier? metadata?
22
+ //metric post_length <- len(post_text);
23
+ concept_derivation: (PURPOSE | AUTO | PROPERTY ) (prop_ident | IDENTIFIER) "<-" expr
24
+
25
+ rowset_derivation_statement: ("rowset"i IDENTIFIER "<-" (multi_select_statement | select_statement)) | ("with"i IDENTIFIER "as"i (multi_select_statement | select_statement))
26
+
27
+ constant_derivation: CONST IDENTIFIER "<-" (literal | _constant_functions)
28
+
29
+ concept_nullable_modifier: "?"
30
+ concept: (concept_declaration | concept_derivation | concept_property_declaration | constant_derivation)
31
+
32
+ //concept property
33
+ prop_ident: "<" IDENTIFIER ("," IDENTIFIER )* ","? ">" "." IDENTIFIER
34
+
35
+ // datasource concepts
36
+ datasource: "datasource" IDENTIFIER "(" column_assignment_list ")" grain_clause? (address | query)
37
+
38
+ grain_clause: "grain" "(" column_list ")"
39
+
40
+ address: "address" ADDRESS
41
+
42
+ query: "query" MULTILINE_STRING
43
+
44
+ concept_assignment: SHORTHAND_MODIFIER? IDENTIFIER
45
+
46
+ //column_assignment
47
+ //figure out if we want static
48
+ column_assignment: ((IDENTIFIER | _static_functions | raw_column_assignment ) ":" concept_assignment)
49
+
50
+ raw_column_assignment: "raw" "(" MULTILINE_STRING ")"
51
+
52
+ column_assignment_list : column_assignment ("," column_assignment)* ","?
53
+
54
+ column_list : (IDENTIFIER "," )* IDENTIFIER ","?
55
+
56
+ import_statement: "import" (IDENTIFIER ".") * IDENTIFIER "as" IDENTIFIER
57
+
58
+ // persist_statement
59
+ persist_statement: "persist"i IDENTIFIER "into"i IDENTIFIER "from"i select_statement grain_clause?
60
+
61
+ // select statement
62
+ select_statement: "select"i select_list where? order_by? limit?
63
+
64
+ // multiple_selects
65
+ multi_select_statement: select_statement ("merge" select_statement)+ "align"i align_clause where? order_by? limit?
66
+
67
+ align_item: IDENTIFIER ":" IDENTIFIER ("," IDENTIFIER)* ","?
68
+
69
+ align_clause: align_item ("AND"i align_item)* "AND"i?
70
+
71
+ // merge statemment
72
+ merge_statement: "merge" IDENTIFIER ("," IDENTIFIER)* ","?
73
+
74
+ // FUNCTION blocks
75
+ function: raw_function
76
+ function_binding_item: IDENTIFIER ":" data_type
77
+ function_binding_list: function_binding_item ("," function_binding_item )* ","?
78
+ raw_function: "bind" "sql" IDENTIFIER "(" function_binding_list ")" "->" data_type "as"i MULTILINE_STRING
79
+
80
+ // user_id where state = Mexico
81
+ filter_item: "filter"i IDENTIFIER where
82
+
83
+ // rank/lag/lead
84
+ WINDOW_TYPE: ("row_number"i|"rank"i|"lag"i|"lead"i | "sum"i) /[\s]+/
85
+
86
+ window_item: WINDOW_TYPE int_lit? concept_lit window_item_over? window_item_order?
87
+
88
+ window_item_over: ("OVER"i over_list)
89
+
90
+ window_item_order: ("ORDER"i? "BY"i order_list)
91
+
92
+ select_hide_modifier: "--"
93
+ select_partial_modifier: "~"
94
+ select_item: (select_hide_modifier | select_partial_modifier)? (concept_lit | select_transform )
95
+
96
+ select_list: select_item ("," select_item )* ","?
97
+
98
+ // count(post_id) -> post_count
99
+ _assignment: ("->") | "as"i
100
+ select_transform : expr _assignment IDENTIFIER metadata?
101
+
102
+ metadata: "metadata" "(" IDENTIFIER "=" _string_lit ")"
103
+
104
+ limit: "LIMIT"i /[0-9]+/
105
+
106
+ !window_order: ("TOP"i | "BOTTOM"i)
107
+
108
+ window: window_order /[0-9]+/
109
+
110
+ window_order_by: "BY"i column_list
111
+
112
+ order_list: expr ordering ("," expr ordering)* ","?
113
+
114
+ over_list: concept_lit ("," concept_lit )* ","?
115
+
116
+ !ordering: ("ASC"i | "DESC"i ) ("NULLS"i ("FIRST"i | "LAST"i | "AUTO"i) )?
117
+
118
+ order_by: "ORDER"i "BY"i order_list
119
+
120
+ //WHERE STATEMENT
121
+
122
+ !logical_operator: "and"i | "or"i
123
+
124
+ conditional: expr logical_operator expr
125
+
126
+ where: "WHERE"i expr+
127
+
128
+ !array_comparison: ( ("NOT"i "IN"i) | "IN"i)
129
+
130
+ COMPARISON_OPERATOR: (/is[\s]+not/ | "is" |"=" | ">" | "<" | ">=" | "<=" | "!=")
131
+
132
+ comparison: expr COMPARISON_OPERATOR expr
133
+
134
+ between_comparison: expr "between"i expr "and"i expr
135
+
136
+ subselect_comparison: expr array_comparison (literal | _constant_functions | _string_functions | concept_lit | filter_item | window_item | unnest | fgroup | expr_tuple | parenthetical )
137
+
138
+ expr_tuple: "(" expr ("," expr)+ ","? ")"
139
+
140
+ parenthetical: "(" expr ")"
141
+
142
+ //unnesting is a function
143
+ _UNNEST.1: "UNNEST("i
144
+ unnest: _UNNEST expr ")"
145
+ //indexing into an expression is a function
146
+ index_access: expr "[" int_lit "]"
147
+ attr_access: expr "[" _string_lit "]"
148
+
149
+ expr: _constant_functions | window_item | filter_item | subselect_comparison | between_comparison | fgroup | aggregate_functions | unnest | _static_functions | literal | concept_lit | index_access | attr_access | parenthetical | expr_tuple | comparison | conditional | alt_like
150
+
151
+ // functions
152
+
153
+ fadd: ("add"i "(" expr "," expr ")" ) | ( expr "+" expr )
154
+ fsub: ("subtract"i "(" expr "," expr ")" ) | ( expr "-" expr )
155
+ fmul: ("multiply"i "(" expr "," expr ")" ) | ( expr "*" expr )
156
+ fdiv: ( "divide"i "(" expr "," expr ")") | ( expr "/" expr )
157
+ fmod: ( "mod"i "(" expr "," (int_lit | concept_lit ) ")") | ( expr "%" (int_lit | concept_lit ) )
158
+ fround: "round"i "(" expr "," expr ")"
159
+ fabs: "abs"i "(" expr ")"
160
+
161
+ _math_functions: fmul | fdiv | fadd | fsub | fround | fmod | fabs
162
+
163
+ //generic
164
+ fcast: "cast"i "(" expr "as"i data_type ")"
165
+ concat: ("concat"i "(" (expr ",")* expr ")") | (expr "||" expr)
166
+ fcoalesce: "coalesce"i "(" (expr ",")* expr ")"
167
+ fcase_when: "WHEN"i (expr | conditional) "THEN"i expr
168
+ fcase_else: "ELSE"i expr
169
+ fcase: "CASE"i (fcase_when)* (fcase_else)? "END"i
170
+ len: "len"i "(" expr ")"
171
+ fnot: "NOT"i expr
172
+
173
+ _generic_functions: fcast | concat | fcoalesce | fcase | len | fnot
174
+
175
+ //constant
176
+ CURRENT_DATE.1: /current_date\(\)/
177
+ CURRENT_DATETIME.1: /current_datetime\(\)/
178
+ fcurrent_date: CURRENT_DATE
179
+ fcurrent_datetime: CURRENT_DATETIME
180
+
181
+ _constant_functions: fcurrent_date | fcurrent_datetime
182
+
183
+ //string
184
+ like: "like"i "(" expr "," _string_lit ")"
185
+ ilike: "ilike"i "(" expr "," _string_lit ")"
186
+ alt_like: expr "like"i expr
187
+ upper: "upper"i "(" expr ")"
188
+ lower: "lower"i "(" expr ")"
189
+ fsplit: "split"i "(" expr "," _string_lit ")"
190
+ fstrpos: "strpos"i "(" expr "," expr ")"
191
+ _SUBSTRING.1: "substring("i
192
+ fsubstring: _SUBSTRING expr "," expr "," expr ")"
193
+
194
+ _string_functions: like | ilike | upper | lower | fsplit | fstrpos | fsubstring
195
+
196
+ // special aggregate
197
+ fgroup: "group"i "(" expr ")" aggregate_over?
198
+ //aggregates
199
+ _COUNT.1: "count("i
200
+ count: _COUNT expr ")"
201
+ count_distinct: "count_distinct"i "(" expr ")"
202
+
203
+ sum: "sum"i "(" expr ")"
204
+ avg: "avg"i "(" expr ")"
205
+ max: "max"i "(" expr ")"
206
+ min: "min"i "(" expr ")"
207
+
208
+ //aggregates can force a grain
209
+ aggregate_all: "*"
210
+ aggregate_over: ("BY"i (aggregate_all | over_list))
211
+ aggregate_functions: (count | count_distinct | sum | avg | max | min) aggregate_over?
212
+
213
+ // date functions
214
+ _DATE.1: "date("i
215
+ fdate: _DATE expr ")"
216
+ fdatetime: "datetime"i "(" expr ")"
217
+ ftimestamp: "timestamp"i "(" expr ")"
218
+
219
+ _SECOND.1: "second("i
220
+ fsecond: _SECOND expr ")"
221
+ _MINUTE.1: "minute("i
222
+ fminute: _MINUTE expr ")"
223
+ _HOUR.1: "hour("i
224
+ fhour: _HOUR expr ")"
225
+ _DAY.1: "day("i
226
+ fday: _DAY expr ")"
227
+ _DAY_OF_WEEK.1: "day_of_week("i
228
+ fday_of_week: _DAY_OF_WEEK expr ")"
229
+ _WEEK.1: "week("i
230
+ fweek: _WEEK expr ")"
231
+ _MONTH.1: "month("i
232
+ fmonth: _MONTH expr ")"
233
+ _QUARTER.1: "quarter("i
234
+ fquarter: _QUARTER expr ")"
235
+ _YEAR.1: "year("i
236
+ fyear: _YEAR expr ")"
237
+
238
+ DATE_PART: "DAY"i | "WEEK"i | "MONTH"i | "QUARTER"i | "YEAR"i | "MINUTE"i | "HOUR"i | "SECOND"i
239
+ fdate_trunc: "date_trunc"i "(" expr "," DATE_PART ")"
240
+ fdate_part: "date_part"i "(" expr "," DATE_PART ")"
241
+ fdate_add: "date_add"i "(" expr "," DATE_PART "," int_lit ")"
242
+ fdate_diff: "date_diff"i "(" expr "," expr "," DATE_PART ")"
243
+
244
+ _date_functions: fdate | fdate_add | fdate_diff | fdatetime | ftimestamp | fsecond | fminute | fhour | fday | fday_of_week | fweek | fmonth | fquarter | fyear | fdate_part | fdate_trunc
245
+
246
+ _static_functions: _string_functions | _math_functions | _generic_functions | _date_functions
247
+
248
+ // base language constructs
249
+ concept_lit: IDENTIFIER
250
+ IDENTIFIER: /[a-zA-Z\_][a-zA-Z0-9\_\-\.\-]*/
251
+ ADDRESS: IDENTIFIER | /`[a-zA-Z\_][a-zA-Z0-9\_\-\.\-\*]*`/
252
+
253
+ MULTILINE_STRING: /\'{3}(.*?)\'{3}/s
254
+
255
+ DOUBLE_STRING_CHARS: /(?:(?!\${)([^"\\]|\\.))+/+ // any character except "
256
+ SINGLE_STRING_CHARS: /(?:(?!\${)([^'\\]|\\.))+/+ // any character except '
257
+ _single_quote: "'" ( SINGLE_STRING_CHARS )* "'"
258
+ _double_quote: "\"" ( DOUBLE_STRING_CHARS )* "\""
259
+ _string_lit: _single_quote | _double_quote
260
+
261
+ MINUS: "-"
262
+
263
+ int_lit: MINUS? /[0-9]+/
264
+
265
+ float_lit: /[0-9]*\.[0-9]+/
266
+
267
+ array_lit: "[" (literal ",")* literal ","? "]"()
268
+
269
+ !bool_lit: "True"i | "False"i
270
+
271
+ !null_lit.1: "null"i
272
+
273
+ literal: null_lit | _string_lit | int_lit | float_lit | bool_lit | array_lit
274
+
275
+ MODIFIER: "Optional"i | "Partial"i | "Nullable"i
276
+
277
+ SHORTHAND_MODIFIER: "~"
278
+
279
+ struct_type: "struct" "<" ((data_type | IDENTIFIER) ",")* (data_type | IDENTIFIER) ","? ">"
280
+
281
+ list_type: "list" "<" data_type ">"
282
+
283
+
284
+ !data_type: "string"i | "number"i | "numeric"i | "map"i | "list"i | "array"i | "any"i | "int"i | "bigint" | "date"i | "datetime"i | "timestamp"i | "float"i | "bool"i | struct_type | list_type
285
+
286
+ PURPOSE: "key"i | "metric"i | CONST
287
+ PROPERTY: "property"i
288
+ CONST: "const"i | "constant"i
289
+ AUTO: "AUTO"i
290
+
291
+ // meta functions
292
+ CONCEPTS: "CONCEPTS"i
293
+ DATASOURCES: "DATASOURCES"i
294
+ show_category: CONCEPTS | DATASOURCES
295
+
296
+ show_statement: "show"i ( show_category | select_statement | persist_statement) _TERMINATOR
297
+ COMMENT: /#.*(\n|$)/ | /\/\/.*\n/
298
+ %import common.WS
299
+ %ignore WS
300
+ %ignore COMMENT
File without changes
File without changes
File without changes