pytrilogy 0.0.2.10__py3-none-any.whl → 0.0.2.12__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 (30) hide show
  1. {pytrilogy-0.0.2.10.dist-info → pytrilogy-0.0.2.12.dist-info}/METADATA +1 -1
  2. {pytrilogy-0.0.2.10.dist-info → pytrilogy-0.0.2.12.dist-info}/RECORD +30 -30
  3. trilogy/__init__.py +1 -1
  4. trilogy/core/enums.py +0 -1
  5. trilogy/core/environment_helpers.py +44 -6
  6. trilogy/core/models.py +47 -26
  7. trilogy/core/optimization.py +31 -3
  8. trilogy/core/optimizations/__init__.py +2 -1
  9. trilogy/core/optimizations/predicate_pushdown.py +60 -42
  10. trilogy/core/processing/concept_strategies_v3.py +8 -4
  11. trilogy/core/processing/node_generators/basic_node.py +15 -9
  12. trilogy/core/processing/node_generators/filter_node.py +20 -3
  13. trilogy/core/processing/node_generators/group_node.py +2 -0
  14. trilogy/core/processing/node_generators/node_merge_node.py +28 -2
  15. trilogy/core/processing/node_generators/unnest_node.py +10 -3
  16. trilogy/core/processing/nodes/base_node.py +7 -2
  17. trilogy/core/processing/nodes/group_node.py +0 -1
  18. trilogy/core/processing/nodes/merge_node.py +11 -4
  19. trilogy/core/processing/nodes/unnest_node.py +13 -9
  20. trilogy/core/processing/utility.py +3 -1
  21. trilogy/core/query_processor.py +20 -5
  22. trilogy/dialect/base.py +96 -56
  23. trilogy/dialect/common.py +3 -3
  24. trilogy/parsing/common.py +58 -1
  25. trilogy/parsing/parse_engine.py +111 -136
  26. trilogy/parsing/trilogy.lark +5 -1
  27. {pytrilogy-0.0.2.10.dist-info → pytrilogy-0.0.2.12.dist-info}/LICENSE.md +0 -0
  28. {pytrilogy-0.0.2.10.dist-info → pytrilogy-0.0.2.12.dist-info}/WHEEL +0 -0
  29. {pytrilogy-0.0.2.10.dist-info → pytrilogy-0.0.2.12.dist-info}/entry_points.txt +0 -0
  30. {pytrilogy-0.0.2.10.dist-info → pytrilogy-0.0.2.12.dist-info}/top_level.txt +0 -0
@@ -24,7 +24,6 @@ from trilogy.core.enums import (
24
24
  ComparisonOperator,
25
25
  FunctionType,
26
26
  InfiniteFunctionArgs,
27
- FunctionClass,
28
27
  Modifier,
29
28
  Ordering,
30
29
  Purpose,
@@ -104,7 +103,6 @@ from trilogy.core.models import (
104
103
  ConceptDeclarationStatement,
105
104
  ConceptDerivation,
106
105
  RowsetDerivationStatement,
107
- LooseConceptList,
108
106
  list_to_wrapper,
109
107
  dict_to_map_wrapper,
110
108
  NumericType,
@@ -119,6 +117,7 @@ from trilogy.parsing.common import (
119
117
  filter_item_to_concept,
120
118
  constant_to_concept,
121
119
  arbitrary_to_concept,
120
+ process_function_args,
122
121
  )
123
122
 
124
123
  CONSTANT_TYPES = (int, float, str, bool, list, ListWrapper, MapWrapper)
@@ -230,50 +229,6 @@ class ParseToObjects(Transformer):
230
229
  self.environment.concepts.undefined = {}
231
230
  return reparsed
232
231
 
233
- def process_function_args(
234
- self, args, meta: Meta, concept_arguments: Optional[LooseConceptList] = None
235
- ):
236
- final: List[Concept | Function] = []
237
- for arg in args:
238
- # if a function has an anonymous function argument
239
- # create an implicit concept
240
- while isinstance(arg, Parenthetical):
241
- arg = arg.content
242
- if isinstance(arg, Function):
243
- # if it's not an aggregate function, we can skip the virtual concepts
244
- # to simplify anonymous function handling
245
- if arg.operator not in FunctionClass.AGGREGATE_FUNCTIONS.value:
246
- final.append(arg)
247
- continue
248
- id_hash = string_to_hash(str(arg))
249
- concept = function_to_concept(
250
- arg,
251
- name=f"{VIRTUAL_CONCEPT_PREFIX}_{id_hash}",
252
- namespace=self.environment.namespace,
253
- )
254
- # to satisfy mypy, concept will always have metadata
255
- if concept.metadata:
256
- concept.metadata.line_number = meta.line
257
- self.environment.add_concept(concept, meta=meta)
258
- final.append(concept)
259
- elif isinstance(
260
- arg, (FilterItem, WindowItem, AggregateWrapper, ListWrapper, MapWrapper)
261
- ):
262
- id_hash = string_to_hash(str(arg))
263
- concept = arbitrary_to_concept(
264
- arg,
265
- name=f"{VIRTUAL_CONCEPT_PREFIX}_{id_hash}",
266
- namespace=self.environment.namespace,
267
- )
268
- if concept.metadata:
269
- concept.metadata.line_number = meta.line
270
- self.environment.add_concept(concept, meta=meta)
271
- final.append(concept)
272
-
273
- else:
274
- final.append(arg)
275
- return final
276
-
277
232
  def start(self, args):
278
233
  return args
279
234
 
@@ -319,17 +274,18 @@ class ParseToObjects(Transformer):
319
274
  @v_args(meta=True)
320
275
  def struct_type(self, meta: Meta, args) -> StructType:
321
276
  final: list[
322
- DataType | MapType | ListType | StructType | NumericType | Concept
277
+ DataType | MapType | ListType | NumericType | StructType | Concept
323
278
  ] = []
324
279
  for arg in args:
325
- if not isinstance(arg, (DataType, ListType, StructType)):
326
- new = self.environment.concepts.__getitem__( # type: ignore
327
- key=arg, line_no=meta.line
328
- )
329
- final.append(new)
330
- else:
331
- final.append(arg)
332
- return StructType(fields=final)
280
+ new = self.environment.concepts.__getitem__( # type: ignore
281
+ key=arg, line_no=meta.line
282
+ )
283
+ final.append(new)
284
+
285
+ return StructType(
286
+ fields=final,
287
+ fields_map={x.name: x for x in final if isinstance(x, Concept)},
288
+ )
333
289
 
334
290
  def list_type(self, args) -> ListType:
335
291
  return ListType(type=args[0])
@@ -520,18 +476,6 @@ class ParseToObjects(Transformer):
520
476
  if concept.metadata:
521
477
  concept.metadata.line_number = meta.line
522
478
  self.environment.add_concept(concept, meta=meta)
523
- assert isinstance(concept.datatype, StructType)
524
- for key, value in concept.datatype.fields_map.items():
525
- args = self.process_function_args([concept, key], meta=meta)
526
- self.environment.add_concept(
527
- Concept(
528
- name=key,
529
- datatype=arg_to_datatype(value),
530
- purpose=Purpose.PROPERTY,
531
- namespace=self.environment.namespace + "." + name,
532
- lineage=AttrAccess(args),
533
- )
534
- )
535
479
  return ConceptDerivation(concept=concept)
536
480
  elif (
537
481
  isinstance(source_value, Function)
@@ -983,6 +927,7 @@ class ParseToObjects(Transformer):
983
927
  order_by=order_by,
984
928
  meta=Metadata(line_number=meta.line),
985
929
  )
930
+
986
931
  for item in select_items:
987
932
  # we don't know the grain of an aggregate at assignment time
988
933
  # so rebuild at this point in the tree
@@ -1000,21 +945,49 @@ class ParseToObjects(Transformer):
1000
945
  )
1001
946
  self.environment.add_concept(new_concept, meta=meta)
1002
947
  item.content.output = new_concept
948
+ elif isinstance(item.content, Concept):
949
+ # Sometimes cached values here don't have the latest info
950
+ # bug we can't just use environment, as it might not have the right grain.
951
+ item.content = self.environment.concepts[
952
+ item.content.address
953
+ ].with_grain(item.content.grain)
954
+ # TODO: revisit if we can push down every filter
955
+ # else:
956
+ # item.content = (
957
+ # item.content.with_filter(
958
+ # output.where_clause.conditional, environment=self.environment
959
+ # )
960
+ # if output.where_clause
961
+ # and output.where_clause_category == SelectFiltering.IMPLICIT
962
+ # else item.content
963
+ # )
964
+
1003
965
  if order_by:
1004
966
  for orderitem in order_by.items:
1005
- if (
1006
- isinstance(orderitem.expr, Concept)
1007
- and orderitem.expr.purpose == Purpose.METRIC
1008
- ):
1009
- orderitem.expr = orderitem.expr.with_select_context(
1010
- output.grain,
1011
- conditional=(
1012
- output.where_clause.conditional
1013
- if output.where_clause
1014
- and output.where_clause_category == SelectFiltering.IMPLICIT
1015
- else None
1016
- ),
1017
- )
967
+ if isinstance(orderitem.expr, Concept):
968
+ if orderitem.expr.purpose == Purpose.METRIC:
969
+ orderitem.expr = orderitem.expr.with_select_context(
970
+ output.grain,
971
+ conditional=(
972
+ output.where_clause.conditional
973
+ if output.where_clause
974
+ and output.where_clause_category
975
+ == SelectFiltering.IMPLICIT
976
+ else None
977
+ ),
978
+ environment=self.environment,
979
+ )
980
+ # TODO :push down every filter
981
+ # else:
982
+ # orderitem.expr = (
983
+ # orderitem.expr.with_filter(
984
+ # output.where_clause.conditional,
985
+ # environment=self.environment,
986
+ # )
987
+ # if output.where_clause
988
+ # and output.where_clause_category == SelectFiltering.IMPLICIT
989
+ # else orderitem.expr
990
+ # )
1018
991
  return output
1019
992
 
1020
993
  @v_args(meta=True)
@@ -1237,7 +1210,11 @@ class ParseToObjects(Transformer):
1237
1210
 
1238
1211
  def filter_item(self, args) -> FilterItem:
1239
1212
  where: WhereClause
1240
- string_concept, where = args
1213
+ string_concept, raw = args
1214
+ if isinstance(raw, WhereClause):
1215
+ where = raw
1216
+ else:
1217
+ where = WhereClause(conditional=raw)
1241
1218
  concept = self.environment.concepts[string_concept]
1242
1219
  return FilterItem(content=concept, where=where)
1243
1220
 
@@ -1264,57 +1241,58 @@ class ParseToObjects(Transformer):
1264
1241
 
1265
1242
  @v_args(meta=True)
1266
1243
  def index_access(self, meta, args):
1267
- args = self.process_function_args(args, meta=meta)
1244
+ args = process_function_args(args, meta=meta, environment=self.environment)
1268
1245
  if args[0].datatype == DataType.MAP or isinstance(args[0].datatype, MapType):
1269
1246
  return MapAccess(args)
1270
1247
  return IndexAccess(args)
1271
1248
 
1272
1249
  @v_args(meta=True)
1273
1250
  def map_key_access(self, meta, args):
1274
- args = self.process_function_args(args, meta=meta)
1251
+ args = process_function_args(args, meta=meta, environment=self.environment)
1275
1252
  return MapAccess(args)
1276
1253
 
1277
1254
  @v_args(meta=True)
1278
1255
  def attr_access(self, meta, args):
1279
- args = self.process_function_args(args, meta=meta)
1256
+ args = process_function_args(args, meta=meta, environment=self.environment)
1280
1257
  return AttrAccess(args)
1281
1258
 
1282
1259
  @v_args(meta=True)
1283
1260
  def fcoalesce(self, meta, args):
1284
- args = self.process_function_args(args, meta=meta)
1261
+ args = process_function_args(args, meta=meta, environment=self.environment)
1285
1262
  return Coalesce(args)
1286
1263
 
1287
1264
  @v_args(meta=True)
1288
1265
  def unnest(self, meta, args):
1289
- args = self.process_function_args(args, meta=meta)
1266
+ args = process_function_args(args, meta=meta, environment=self.environment)
1290
1267
  return Unnest(args)
1291
1268
 
1292
1269
  @v_args(meta=True)
1293
1270
  def count(self, meta, args):
1294
- args = self.process_function_args(args, meta=meta)
1271
+ args = process_function_args(args, meta=meta, environment=self.environment)
1295
1272
  return Count(args)
1296
1273
 
1297
1274
  @v_args(meta=True)
1298
1275
  def fgroup(self, meta, args):
1299
1276
  if len(args) == 2:
1300
- args = self.process_function_args([args[0]] + args[1], meta=meta)
1277
+ fargs = [args[0]] + args[1]
1301
1278
  else:
1302
- args = self.process_function_args([args[0]], meta=meta)
1279
+ fargs = [args[0]]
1280
+ args = process_function_args(fargs, meta=meta, environment=self.environment)
1303
1281
  return Group(args)
1304
1282
 
1305
1283
  @v_args(meta=True)
1306
1284
  def fabs(self, meta, args):
1307
- args = self.process_function_args(args, meta=meta)
1285
+ args = process_function_args(args, meta=meta, environment=self.environment)
1308
1286
  return Abs(args)
1309
1287
 
1310
1288
  @v_args(meta=True)
1311
1289
  def count_distinct(self, meta, args):
1312
- args = self.process_function_args(args, meta=meta)
1290
+ args = process_function_args(args, meta=meta, environment=self.environment)
1313
1291
  return CountDistinct(args)
1314
1292
 
1315
1293
  @v_args(meta=True)
1316
1294
  def sum(self, meta, args):
1317
- args = self.process_function_args(args, meta=meta)
1295
+ args = process_function_args(args, meta=meta, environment=self.environment)
1318
1296
  return Function(
1319
1297
  operator=FunctionType.SUM,
1320
1298
  arguments=args,
@@ -1325,7 +1303,7 @@ class ParseToObjects(Transformer):
1325
1303
 
1326
1304
  @v_args(meta=True)
1327
1305
  def avg(self, meta, args):
1328
- args = self.process_function_args(args, meta=meta)
1306
+ args = process_function_args(args, meta=meta, environment=self.environment)
1329
1307
  arg = args[0]
1330
1308
 
1331
1309
  return Function(
@@ -1339,17 +1317,17 @@ class ParseToObjects(Transformer):
1339
1317
 
1340
1318
  @v_args(meta=True)
1341
1319
  def max(self, meta, args):
1342
- args = self.process_function_args(args, meta=meta)
1320
+ args = process_function_args(args, meta=meta, environment=self.environment)
1343
1321
  return Max(args)
1344
1322
 
1345
1323
  @v_args(meta=True)
1346
1324
  def min(self, meta, args):
1347
- args = self.process_function_args(args, meta=meta)
1325
+ args = process_function_args(args, meta=meta, environment=self.environment)
1348
1326
  return Min(args)
1349
1327
 
1350
1328
  @v_args(meta=True)
1351
1329
  def len(self, meta, args):
1352
- args = self.process_function_args(args, meta=meta)
1330
+ args = process_function_args(args, meta=meta, environment=self.environment)
1353
1331
  return Function(
1354
1332
  operator=FunctionType.LENGTH,
1355
1333
  arguments=args,
@@ -1361,12 +1339,12 @@ class ParseToObjects(Transformer):
1361
1339
 
1362
1340
  @v_args(meta=True)
1363
1341
  def fsplit(self, meta, args):
1364
- args = self.process_function_args(args, meta=meta)
1342
+ args = process_function_args(args, meta=meta, environment=self.environment)
1365
1343
  return Split(args)
1366
1344
 
1367
1345
  @v_args(meta=True)
1368
1346
  def concat(self, meta, args):
1369
- args = self.process_function_args(args, meta=meta)
1347
+ args = process_function_args(args, meta=meta, environment=self.environment)
1370
1348
  return Function(
1371
1349
  operator=FunctionType.CONCAT,
1372
1350
  arguments=args,
@@ -1379,7 +1357,7 @@ class ParseToObjects(Transformer):
1379
1357
 
1380
1358
  @v_args(meta=True)
1381
1359
  def like(self, meta, args):
1382
- args = self.process_function_args(args, meta=meta)
1360
+ args = process_function_args(args, meta=meta, environment=self.environment)
1383
1361
  return Function(
1384
1362
  operator=FunctionType.LIKE,
1385
1363
  arguments=args,
@@ -1391,7 +1369,7 @@ class ParseToObjects(Transformer):
1391
1369
 
1392
1370
  @v_args(meta=True)
1393
1371
  def alt_like(self, meta, args):
1394
- args = self.process_function_args(args, meta=meta)
1372
+ args = process_function_args(args, meta=meta, environment=self.environment)
1395
1373
  return Function(
1396
1374
  operator=FunctionType.LIKE,
1397
1375
  arguments=args,
@@ -1403,7 +1381,7 @@ class ParseToObjects(Transformer):
1403
1381
 
1404
1382
  @v_args(meta=True)
1405
1383
  def ilike(self, meta, args):
1406
- args = self.process_function_args(args, meta=meta)
1384
+ args = process_function_args(args, meta=meta, environment=self.environment)
1407
1385
  return Function(
1408
1386
  operator=FunctionType.ILIKE,
1409
1387
  arguments=args,
@@ -1415,7 +1393,7 @@ class ParseToObjects(Transformer):
1415
1393
 
1416
1394
  @v_args(meta=True)
1417
1395
  def upper(self, meta, args):
1418
- args = self.process_function_args(args, meta=meta)
1396
+ args = process_function_args(args, meta=meta, environment=self.environment)
1419
1397
  return Function(
1420
1398
  operator=FunctionType.UPPER,
1421
1399
  arguments=args,
@@ -1427,15 +1405,12 @@ class ParseToObjects(Transformer):
1427
1405
 
1428
1406
  @v_args(meta=True)
1429
1407
  def fstrpos(self, meta, args):
1430
- args = self.process_function_args(args, meta=meta)
1408
+ args = process_function_args(args, meta=meta, environment=self.environment)
1431
1409
  return StrPos(args)
1432
1410
 
1433
1411
  @v_args(meta=True)
1434
1412
  def fsubstring(self, meta, args):
1435
- args = self.process_function_args(
1436
- args,
1437
- meta=meta,
1438
- )
1413
+ args = process_function_args(args, meta=meta, environment=self.environment)
1439
1414
  return SubString(args)
1440
1415
 
1441
1416
  def logical_operator(self, args):
@@ -1443,7 +1418,7 @@ class ParseToObjects(Transformer):
1443
1418
 
1444
1419
  @v_args(meta=True)
1445
1420
  def lower(self, meta, args):
1446
- args = self.process_function_args(args, meta=meta)
1421
+ args = process_function_args(args, meta=meta, environment=self.environment)
1447
1422
  return Function(
1448
1423
  operator=FunctionType.LOWER,
1449
1424
  arguments=args,
@@ -1456,7 +1431,7 @@ class ParseToObjects(Transformer):
1456
1431
  # date functions
1457
1432
  @v_args(meta=True)
1458
1433
  def fdate(self, meta, args):
1459
- args = self.process_function_args(args, meta=meta)
1434
+ args = process_function_args(args, meta=meta, environment=self.environment)
1460
1435
  return Function(
1461
1436
  operator=FunctionType.DATE,
1462
1437
  arguments=args,
@@ -1476,7 +1451,7 @@ class ParseToObjects(Transformer):
1476
1451
 
1477
1452
  @v_args(meta=True)
1478
1453
  def fdate_trunc(self, meta, args):
1479
- args = self.process_function_args(args, meta=meta)
1454
+ args = process_function_args(args, meta=meta, environment=self.environment)
1480
1455
  return Function(
1481
1456
  operator=FunctionType.DATE_TRUNCATE,
1482
1457
  arguments=args,
@@ -1496,7 +1471,7 @@ class ParseToObjects(Transformer):
1496
1471
 
1497
1472
  @v_args(meta=True)
1498
1473
  def fdate_part(self, meta, args):
1499
- args = self.process_function_args(args, meta=meta)
1474
+ args = process_function_args(args, meta=meta, environment=self.environment)
1500
1475
  return Function(
1501
1476
  operator=FunctionType.DATE_PART,
1502
1477
  arguments=args,
@@ -1516,7 +1491,7 @@ class ParseToObjects(Transformer):
1516
1491
 
1517
1492
  @v_args(meta=True)
1518
1493
  def fdate_add(self, meta, args):
1519
- args = self.process_function_args(args, meta=meta)
1494
+ args = process_function_args(args, meta=meta, environment=self.environment)
1520
1495
  return Function(
1521
1496
  operator=FunctionType.DATE_ADD,
1522
1497
  arguments=args,
@@ -1537,7 +1512,7 @@ class ParseToObjects(Transformer):
1537
1512
 
1538
1513
  @v_args(meta=True)
1539
1514
  def fdate_diff(self, meta, args):
1540
- args = self.process_function_args(args, meta=meta)
1515
+ args = process_function_args(args, meta=meta, environment=self.environment)
1541
1516
  purpose = function_args_to_output_purpose(args)
1542
1517
  return Function(
1543
1518
  operator=FunctionType.DATE_DIFF,
@@ -1562,7 +1537,7 @@ class ParseToObjects(Transformer):
1562
1537
 
1563
1538
  @v_args(meta=True)
1564
1539
  def fdatetime(self, meta, args):
1565
- args = self.process_function_args(args, meta=meta)
1540
+ args = process_function_args(args, meta=meta, environment=self.environment)
1566
1541
  return Function(
1567
1542
  operator=FunctionType.DATETIME,
1568
1543
  arguments=args,
@@ -1579,7 +1554,7 @@ class ParseToObjects(Transformer):
1579
1554
 
1580
1555
  @v_args(meta=True)
1581
1556
  def ftimestamp(self, meta, args):
1582
- args = self.process_function_args(args, meta=meta)
1557
+ args = process_function_args(args, meta=meta, environment=self.environment)
1583
1558
  return Function(
1584
1559
  operator=FunctionType.TIMESTAMP,
1585
1560
  arguments=args,
@@ -1591,7 +1566,7 @@ class ParseToObjects(Transformer):
1591
1566
 
1592
1567
  @v_args(meta=True)
1593
1568
  def fsecond(self, meta, args):
1594
- args = self.process_function_args(args, meta=meta)
1569
+ args = process_function_args(args, meta=meta, environment=self.environment)
1595
1570
  return Function(
1596
1571
  operator=FunctionType.SECOND,
1597
1572
  arguments=args,
@@ -1603,7 +1578,7 @@ class ParseToObjects(Transformer):
1603
1578
 
1604
1579
  @v_args(meta=True)
1605
1580
  def fminute(self, meta, args):
1606
- args = self.process_function_args(args, meta=meta)
1581
+ args = process_function_args(args, meta=meta, environment=self.environment)
1607
1582
  return Function(
1608
1583
  operator=FunctionType.MINUTE,
1609
1584
  arguments=args,
@@ -1615,7 +1590,7 @@ class ParseToObjects(Transformer):
1615
1590
 
1616
1591
  @v_args(meta=True)
1617
1592
  def fhour(self, meta, args):
1618
- args = self.process_function_args(args, meta=meta)
1593
+ args = process_function_args(args, meta=meta, environment=self.environment)
1619
1594
  return Function(
1620
1595
  operator=FunctionType.HOUR,
1621
1596
  arguments=args,
@@ -1627,7 +1602,7 @@ class ParseToObjects(Transformer):
1627
1602
 
1628
1603
  @v_args(meta=True)
1629
1604
  def fday(self, meta, args):
1630
- args = self.process_function_args(args, meta=meta)
1605
+ args = process_function_args(args, meta=meta, environment=self.environment)
1631
1606
  return Function(
1632
1607
  operator=FunctionType.DAY,
1633
1608
  arguments=args,
@@ -1639,7 +1614,7 @@ class ParseToObjects(Transformer):
1639
1614
 
1640
1615
  @v_args(meta=True)
1641
1616
  def fday_of_week(self, meta, args):
1642
- args = self.process_function_args(args, meta=meta)
1617
+ args = process_function_args(args, meta=meta, environment=self.environment)
1643
1618
  return Function(
1644
1619
  operator=FunctionType.DAY_OF_WEEK,
1645
1620
  arguments=args,
@@ -1651,7 +1626,7 @@ class ParseToObjects(Transformer):
1651
1626
 
1652
1627
  @v_args(meta=True)
1653
1628
  def fweek(self, meta, args):
1654
- args = self.process_function_args(args, meta=meta)
1629
+ args = process_function_args(args, meta=meta, environment=self.environment)
1655
1630
  return Function(
1656
1631
  operator=FunctionType.WEEK,
1657
1632
  arguments=args,
@@ -1663,7 +1638,7 @@ class ParseToObjects(Transformer):
1663
1638
 
1664
1639
  @v_args(meta=True)
1665
1640
  def fmonth(self, meta, args):
1666
- args = self.process_function_args(args, meta=meta)
1641
+ args = process_function_args(args, meta=meta, environment=self.environment)
1667
1642
  return Function(
1668
1643
  operator=FunctionType.MONTH,
1669
1644
  arguments=args,
@@ -1675,7 +1650,7 @@ class ParseToObjects(Transformer):
1675
1650
 
1676
1651
  @v_args(meta=True)
1677
1652
  def fquarter(self, meta, args):
1678
- args = self.process_function_args(args, meta=meta)
1653
+ args = process_function_args(args, meta=meta, environment=self.environment)
1679
1654
  return Function(
1680
1655
  operator=FunctionType.QUARTER,
1681
1656
  arguments=args,
@@ -1687,7 +1662,7 @@ class ParseToObjects(Transformer):
1687
1662
 
1688
1663
  @v_args(meta=True)
1689
1664
  def fyear(self, meta, args):
1690
- args = self.process_function_args(args, meta=meta)
1665
+ args = process_function_args(args, meta=meta, environment=self.environment)
1691
1666
  return Function(
1692
1667
  operator=FunctionType.YEAR,
1693
1668
  arguments=args,
@@ -1700,7 +1675,7 @@ class ParseToObjects(Transformer):
1700
1675
  # utility functions
1701
1676
  @v_args(meta=True)
1702
1677
  def fcast(self, meta, args) -> Function:
1703
- args = self.process_function_args(args, meta=meta)
1678
+ args = process_function_args(args, meta=meta, environment=self.environment)
1704
1679
  output_datatype = args[1]
1705
1680
  return Function(
1706
1681
  operator=FunctionType.CAST,
@@ -1721,7 +1696,7 @@ class ParseToObjects(Transformer):
1721
1696
  # math functions
1722
1697
  @v_args(meta=True)
1723
1698
  def fadd(self, meta, args) -> Function:
1724
- args = self.process_function_args(args, meta=meta)
1699
+ args = process_function_args(args, meta=meta, environment=self.environment)
1725
1700
  output_datatype = arg_to_datatype(args[0])
1726
1701
  # TODO: check for valid transforms?
1727
1702
  return Function(
@@ -1735,7 +1710,7 @@ class ParseToObjects(Transformer):
1735
1710
 
1736
1711
  @v_args(meta=True)
1737
1712
  def fsub(self, meta, args) -> Function:
1738
- args = self.process_function_args(args, meta=meta)
1713
+ args = process_function_args(args, meta=meta, environment=self.environment)
1739
1714
  output_datatype = arg_to_datatype(args[0])
1740
1715
  return Function(
1741
1716
  operator=FunctionType.SUBTRACT,
@@ -1748,7 +1723,7 @@ class ParseToObjects(Transformer):
1748
1723
 
1749
1724
  @v_args(meta=True)
1750
1725
  def fmul(self, meta, args) -> Function:
1751
- args = self.process_function_args(args, meta=meta)
1726
+ args = process_function_args(args, meta=meta, environment=self.environment)
1752
1727
  output_datatype = arg_to_datatype(args[0])
1753
1728
  return Function(
1754
1729
  operator=FunctionType.MULTIPLY,
@@ -1762,7 +1737,7 @@ class ParseToObjects(Transformer):
1762
1737
  @v_args(meta=True)
1763
1738
  def fdiv(self, meta: Meta, args):
1764
1739
  output_datatype = arg_to_datatype(args[0])
1765
- args = self.process_function_args(args, meta=meta)
1740
+ args = process_function_args(args, meta=meta, environment=self.environment)
1766
1741
  return Function(
1767
1742
  operator=FunctionType.DIVIDE,
1768
1743
  arguments=args,
@@ -1775,7 +1750,7 @@ class ParseToObjects(Transformer):
1775
1750
  @v_args(meta=True)
1776
1751
  def fmod(self, meta: Meta, args):
1777
1752
  output_datatype = arg_to_datatype(args[0])
1778
- args = self.process_function_args(args, meta=meta)
1753
+ args = process_function_args(args, meta=meta, environment=self.environment)
1779
1754
  return Function(
1780
1755
  operator=FunctionType.MOD,
1781
1756
  arguments=args,
@@ -1790,7 +1765,7 @@ class ParseToObjects(Transformer):
1790
1765
 
1791
1766
  @v_args(meta=True)
1792
1767
  def fround(self, meta, args) -> Function:
1793
- args = self.process_function_args(args, meta=meta)
1768
+ args = process_function_args(args, meta=meta, environment=self.environment)
1794
1769
  output_datatype = arg_to_datatype(args[0])
1795
1770
  return Function(
1796
1771
  operator=FunctionType.ROUND,
@@ -1824,27 +1799,27 @@ class ParseToObjects(Transformer):
1824
1799
 
1825
1800
  @v_args(meta=True)
1826
1801
  def fcase_when(self, meta, args) -> CaseWhen:
1827
- args = self.process_function_args(args, meta=meta)
1802
+ args = process_function_args(args, meta=meta, environment=self.environment)
1828
1803
  return CaseWhen(comparison=args[0], expr=args[1])
1829
1804
 
1830
1805
  @v_args(meta=True)
1831
1806
  def fcase_else(self, meta, args) -> CaseElse:
1832
- args = self.process_function_args(args, meta=meta)
1807
+ args = process_function_args(args, meta=meta, environment=self.environment)
1833
1808
  return CaseElse(expr=args[0])
1834
1809
 
1835
1810
  @v_args(meta=True)
1836
1811
  def fcurrent_date(self, meta, args):
1837
- args = self.process_function_args(args, meta=meta)
1812
+ args = process_function_args(args, meta=meta, environment=self.environment)
1838
1813
  return CurrentDate([])
1839
1814
 
1840
1815
  @v_args(meta=True)
1841
1816
  def fcurrent_datetime(self, meta, args):
1842
- args = self.process_function_args(args, meta=meta)
1817
+ args = process_function_args(args, meta=meta, environment=self.environment)
1843
1818
  return CurrentDatetime([])
1844
1819
 
1845
1820
  @v_args(meta=True)
1846
1821
  def fnot(self, meta, args):
1847
- args = self.process_function_args(args, meta=meta)
1822
+ args = process_function_args(args, meta=meta, environment=self.environment)
1848
1823
  return IsNull(args)
1849
1824
 
1850
1825
 
@@ -83,7 +83,11 @@
83
83
  raw_function: "bind" "sql" IDENTIFIER "(" function_binding_list ")" "->" data_type "as"i MULTILINE_STRING
84
84
 
85
85
  // user_id where state = Mexico
86
- filter_item: "filter"i IDENTIFIER where
86
+ _filter_alt: IDENTIFIER "?" conditional
87
+ _filter_base: "filter"i IDENTIFIER where
88
+ filter_item: _filter_base | _filter_alt
89
+
90
+
87
91
 
88
92
  // rank/lag/lead
89
93
  WINDOW_TYPE: ("row_number"i|"rank"i|"lag"i|"lead"i | "sum"i) /[\s]+/