pytrilogy 0.0.1.104__py3-none-any.whl → 0.0.1.106__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.
- {pytrilogy-0.0.1.104.dist-info → pytrilogy-0.0.1.106.dist-info}/METADATA +1 -1
- {pytrilogy-0.0.1.104.dist-info → pytrilogy-0.0.1.106.dist-info}/RECORD +32 -31
- trilogy/__init__.py +3 -2
- trilogy/constants.py +1 -0
- trilogy/core/models.py +226 -49
- trilogy/core/optimization.py +141 -0
- trilogy/core/processing/concept_strategies_v3.py +1 -0
- trilogy/core/processing/node_generators/common.py +19 -7
- trilogy/core/processing/node_generators/filter_node.py +37 -10
- trilogy/core/processing/node_generators/merge_node.py +11 -1
- trilogy/core/processing/nodes/base_node.py +4 -2
- trilogy/core/processing/nodes/group_node.py +5 -2
- trilogy/core/processing/nodes/merge_node.py +13 -8
- trilogy/core/query_processor.py +5 -2
- trilogy/dialect/base.py +85 -54
- trilogy/dialect/bigquery.py +6 -4
- trilogy/dialect/common.py +8 -6
- trilogy/dialect/config.py +69 -1
- trilogy/dialect/duckdb.py +5 -4
- trilogy/dialect/enums.py +40 -19
- trilogy/dialect/postgres.py +4 -2
- trilogy/dialect/presto.py +6 -4
- trilogy/dialect/snowflake.py +6 -4
- trilogy/dialect/sql_server.py +4 -1
- trilogy/executor.py +18 -5
- trilogy/parsing/common.py +30 -0
- trilogy/parsing/parse_engine.py +43 -83
- trilogy/parsing/render.py +0 -122
- {pytrilogy-0.0.1.104.dist-info → pytrilogy-0.0.1.106.dist-info}/LICENSE.md +0 -0
- {pytrilogy-0.0.1.104.dist-info → pytrilogy-0.0.1.106.dist-info}/WHEEL +0 -0
- {pytrilogy-0.0.1.104.dist-info → pytrilogy-0.0.1.106.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.1.104.dist-info → pytrilogy-0.0.1.106.dist-info}/top_level.txt +0 -0
trilogy/parsing/common.py
CHANGED
|
@@ -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)
|
trilogy/parsing/parse_engine.py
CHANGED
|
@@ -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"
|
|
@@ -926,7 +864,7 @@ class ParseToObjects(Transformer):
|
|
|
926
864
|
elif isinstance(val, Grain):
|
|
927
865
|
grain = val
|
|
928
866
|
elif isinstance(val, Query):
|
|
929
|
-
address = Address(location=f"({val.text})")
|
|
867
|
+
address = Address(location=f"({val.text})", is_query=True)
|
|
930
868
|
if not address:
|
|
931
869
|
raise ValueError(
|
|
932
870
|
"Malformed datasource, missing address or query declaration"
|
|
@@ -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
|
|
trilogy/parsing/render.py
CHANGED
|
@@ -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
|