pytrilogy 0.0.2.48__py3-none-any.whl → 0.0.2.50__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 (38) hide show
  1. {pytrilogy-0.0.2.48.dist-info → pytrilogy-0.0.2.50.dist-info}/METADATA +1 -1
  2. {pytrilogy-0.0.2.48.dist-info → pytrilogy-0.0.2.50.dist-info}/RECORD +38 -38
  3. trilogy/__init__.py +1 -1
  4. trilogy/core/enums.py +11 -0
  5. trilogy/core/functions.py +4 -1
  6. trilogy/core/models.py +29 -14
  7. trilogy/core/processing/concept_strategies_v3.py +3 -3
  8. trilogy/core/processing/node_generators/common.py +0 -2
  9. trilogy/core/processing/node_generators/filter_node.py +0 -3
  10. trilogy/core/processing/node_generators/group_node.py +0 -1
  11. trilogy/core/processing/node_generators/group_to_node.py +0 -2
  12. trilogy/core/processing/node_generators/multiselect_node.py +0 -2
  13. trilogy/core/processing/node_generators/node_merge_node.py +0 -1
  14. trilogy/core/processing/node_generators/rowset_node.py +27 -8
  15. trilogy/core/processing/node_generators/select_merge_node.py +138 -59
  16. trilogy/core/processing/node_generators/union_node.py +0 -1
  17. trilogy/core/processing/node_generators/unnest_node.py +0 -2
  18. trilogy/core/processing/node_generators/window_node.py +0 -2
  19. trilogy/core/processing/nodes/base_node.py +28 -3
  20. trilogy/core/processing/nodes/filter_node.py +0 -3
  21. trilogy/core/processing/nodes/group_node.py +9 -6
  22. trilogy/core/processing/nodes/merge_node.py +3 -4
  23. trilogy/core/processing/nodes/select_node_v2.py +5 -4
  24. trilogy/core/processing/nodes/union_node.py +0 -3
  25. trilogy/core/processing/nodes/unnest_node.py +0 -3
  26. trilogy/core/processing/nodes/window_node.py +0 -3
  27. trilogy/core/processing/utility.py +4 -1
  28. trilogy/core/query_processor.py +3 -8
  29. trilogy/dialect/base.py +14 -2
  30. trilogy/dialect/duckdb.py +7 -0
  31. trilogy/hooks/graph_hook.py +14 -0
  32. trilogy/parsing/common.py +14 -5
  33. trilogy/parsing/parse_engine.py +32 -0
  34. trilogy/parsing/trilogy.lark +3 -1
  35. {pytrilogy-0.0.2.48.dist-info → pytrilogy-0.0.2.50.dist-info}/LICENSE.md +0 -0
  36. {pytrilogy-0.0.2.48.dist-info → pytrilogy-0.0.2.50.dist-info}/WHEEL +0 -0
  37. {pytrilogy-0.0.2.48.dist-info → pytrilogy-0.0.2.50.dist-info}/entry_points.txt +0 -0
  38. {pytrilogy-0.0.2.48.dist-info → pytrilogy-0.0.2.50.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytrilogy
3
- Version: 0.0.2.48
3
+ Version: 0.0.2.50
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -1,4 +1,4 @@
1
- trilogy/__init__.py,sha256=rBXQoKLExpvOodgSnjarZ5SG_tlNVQvyadW0PFK1aFs,291
1
+ trilogy/__init__.py,sha256=IN9QOl63ICFDvmAtr97Xo-KPeIdHaN9JuYuIIsxV0Mk,291
2
2
  trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  trilogy/constants.py,sha256=qZ1d0hoKPPV2HHCoFwPYTVB7b6bXjpWvXd3lE-zEhy8,1494
4
4
  trilogy/engine.py,sha256=yOPnR7XCjWG82Gym_LLZBkYKKJdLCvqdCyt8zguNcnM,1103
@@ -8,55 +8,55 @@ trilogy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  trilogy/utility.py,sha256=eguES83XhmSOAQSBu5xq4aAXimiZFrxcUu81zDL22ug,707
9
9
  trilogy/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  trilogy/core/constants.py,sha256=7XaCpZn5mQmjTobbeBn56SzPWq9eMNDfzfsRU-fP0VE,171
11
- trilogy/core/enums.py,sha256=iBrgUSGhGX865mV784KIU4qKmg6d7bZV71CgdZh20VI,6944
11
+ trilogy/core/enums.py,sha256=6pGjEXNJPB1ngbDQRJjxRi4NmKM8NZQ5-iwnZhrdo5U,7281
12
12
  trilogy/core/env_processor.py,sha256=Pt4lmJfbShBbeSe5M7_FrTk5krrOziiAA__Slnettvc,2585
13
13
  trilogy/core/environment_helpers.py,sha256=CSmQyEXE6EZ4XFYuQQITUHuWXxXGo9AL4UsTnu0404A,7159
14
14
  trilogy/core/ergonomics.py,sha256=ASLDd0RqKWrZiG3XcKHo8nyTjaB_8xfE9t4NZ1UvGpc,1639
15
15
  trilogy/core/exceptions.py,sha256=1c1lQCwSw4_5CQS3q7scOkXU8GQvullJXfPHubprl90,617
16
- trilogy/core/functions.py,sha256=qpVLwTNU_qHQyIvNish5O2AlbpRMQQOqZWEUiSMnpqE,10721
16
+ trilogy/core/functions.py,sha256=hDlwLxQUskT9iRcIic1lfACQnxMLNM5ASdHRPi0ghyw,10835
17
17
  trilogy/core/graph_models.py,sha256=mameUTiuCajtihDw_2-W218xyJlvTusOWrEKP1yAWgk,2003
18
18
  trilogy/core/internal.py,sha256=-CykZknaWieFh5begaQJ4EgGP9qJccGg4XXdmBirxEc,1074
19
- trilogy/core/models.py,sha256=UjuDuda6TWk_y5Pq3mx_BVfmLP3U6WH4EHhd88ddp4E,166378
19
+ trilogy/core/models.py,sha256=WE75DKSyqx-hFUxIuc4oPlq1VV4eyN-pLeHuKfhlsWc,166832
20
20
  trilogy/core/optimization.py,sha256=Jy3tVJNeqhpK6VSyTvgIWKCao6y-VCZ7mYA69MIF6L0,7989
21
- trilogy/core/query_processor.py,sha256=eIRV7WEeEI-3OICEdXjJoQe2DhCimJfyFVW9CI6tU-Q,18845
21
+ trilogy/core/query_processor.py,sha256=V-TqybYO0kCY8O7Nk58OBhb7_eRPs_EqAwaQv-EYLSY,18615
22
22
  trilogy/core/optimizations/__init__.py,sha256=EBanqTXEzf1ZEYjAneIWoIcxtMDite5-n2dQ5xcfUtg,356
23
23
  trilogy/core/optimizations/base_optimization.py,sha256=P4kF-eCXkBxO-5c6tLHhMZ4ODRH1A04hb_6ovkaVyLw,505
24
24
  trilogy/core/optimizations/inline_constant.py,sha256=c-YHOg6eAufL4EaCf4-0PbY_D4skBHW0ldR55_phsMA,1277
25
25
  trilogy/core/optimizations/inline_datasource.py,sha256=LsngRKBy-LYcx1sfo1-rnDym_ly73YV9WkEngSjpFx8,3943
26
26
  trilogy/core/optimizations/predicate_pushdown.py,sha256=XPWEBv8jXnc0OL2JDPNwFvJ5AtOE7dLzJK0LzdmdZMo,9252
27
27
  trilogy/core/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- trilogy/core/processing/concept_strategies_v3.py,sha256=tODAJjYyIwR1RII_4GjZ8f0TP18GvOe49aF1x8MxXto,36985
28
+ trilogy/core/processing/concept_strategies_v3.py,sha256=Uxi9OMg52OLrYNW76SAYXIvnI9UFAFauao34ZO7uD3o,37053
29
29
  trilogy/core/processing/graph_utils.py,sha256=stbYnDxnK-1kbo9L4XNU85FQhWCP-oZYO7LCXhAdC5M,1198
30
- trilogy/core/processing/utility.py,sha256=kwv-eEnFxZTLbZvJxhVxK-IUPBa83VII3gqXmXMBzBM,18709
30
+ trilogy/core/processing/utility.py,sha256=STqSHP8fWTVmaIUCfHAb9Hke_fzOG2pTbmWIdYS4cvc,18787
31
31
  trilogy/core/processing/node_generators/__init__.py,sha256=s_YV1OYc336DuS9591259qjI_K_CtOCuhkf4t2aOgYs,733
32
32
  trilogy/core/processing/node_generators/basic_node.py,sha256=VqVyb4wXI_B2OmfwtpsypimzcevoPe_pnstlKLU3S5s,2878
33
- trilogy/core/processing/node_generators/common.py,sha256=kETikLR2fWbrKywPL0TXXj6YY4rpOA8PjsUSyx_mNyE,8907
34
- trilogy/core/processing/node_generators/filter_node.py,sha256=Br10q3yHtQbA337dR8JwzQMCGqo_H0kjF1vprK7PPns,7610
35
- trilogy/core/processing/node_generators/group_node.py,sha256=wlj8N4Nd1_8cpmccoe0BocM9jUEYsc-1WEMDCoh1WSw,4876
36
- trilogy/core/processing/node_generators/group_to_node.py,sha256=RNvDo0x1TNFCDi97IAZ4taLMEe9Wv0XzNtuCCM9vjvw,2537
37
- trilogy/core/processing/node_generators/multiselect_node.py,sha256=abS8mWWoTxRXYdjKTgRgdfeLiWcJjZ7qgESYwDv5e_o,6510
38
- trilogy/core/processing/node_generators/node_merge_node.py,sha256=IYDS5DNF-5_dpgwre_n1Kh7RBnt4srzgYkaUahe_K_o,14001
39
- trilogy/core/processing/node_generators/rowset_node.py,sha256=C5aPc-KIcedTepv9HyG5kth2fUkMwLs_uQy5YEgZsVo,4584
40
- trilogy/core/processing/node_generators/select_merge_node.py,sha256=JFoBKETwhmd2KdmoNq4wT2SOrd3Jh-GGcO5qMiUh8JE,12691
33
+ trilogy/core/processing/node_generators/common.py,sha256=4rFEBWUpZ01WcdQEi_8fa9QbyxHIiQ781W4nuhVLaxc,8881
34
+ trilogy/core/processing/node_generators/filter_node.py,sha256=2ucE8shC3gyKjPilkfkA0FW0ZHhfcGy2wBQfquuHNlM,7548
35
+ trilogy/core/processing/node_generators/group_node.py,sha256=dD2qlFzLRxYni9_1fHbewoe8AzKExyrDJRfeTwy7XQ4,4863
36
+ trilogy/core/processing/node_generators/group_to_node.py,sha256=8ToptIWQoJttquEPrRTMvU33jCJQI-VJxVObN8W8QJk,2511
37
+ trilogy/core/processing/node_generators/multiselect_node.py,sha256=jOaSOX80tprgYAG9XQ8lL93lt8QbdoAgFhTqF6lgdPY,6484
38
+ trilogy/core/processing/node_generators/node_merge_node.py,sha256=p0NrUxXVsQSoFuP2JCmNZg4muaQV7TXwW11ECEe7pjA,13988
39
+ trilogy/core/processing/node_generators/rowset_node.py,sha256=a9FxQb1qobeewrRNd-X_fFJ_aRLP1WcytK5-Bgu6wjs,5284
40
+ trilogy/core/processing/node_generators/select_merge_node.py,sha256=7jp8byYFoeglBinXtQLKrGoJ6VEQPDCR4R7lMbIh634,15288
41
41
  trilogy/core/processing/node_generators/select_node.py,sha256=bjTylBa-vYbmzpuSpphmIo_Oi78YZpI8ppHnN9KDYDk,1795
42
- trilogy/core/processing/node_generators/union_node.py,sha256=MVmLqOZbCEVqZYVZxxWxtDMvyEdSnAg7pU9NzoOXy1I,2517
43
- trilogy/core/processing/node_generators/unnest_node.py,sha256=MNNjWW7Dp3A_Xv_XGjzdHU1PHQBauZHMBVKRJhqRZJY,2255
44
- trilogy/core/processing/node_generators/window_node.py,sha256=x4n5NWEouMsOS0V9myyJNmEg2e3kUDPLWXQhq3PyUdY,3510
42
+ trilogy/core/processing/node_generators/union_node.py,sha256=MfJjF2m0ARl0oUH9QT1awzPv0e3yA3mXK1XqAvUTgKw,2504
43
+ trilogy/core/processing/node_generators/unnest_node.py,sha256=8El2B1mzC9vIUSk-m94xHvaJwAf5GtCAGfTxGDSiqmU,2229
44
+ trilogy/core/processing/node_generators/window_node.py,sha256=5htRRxaxw6EnS-2TVoQIiy4bkNSoBefBpj2DVBtBo-w,3484
45
45
  trilogy/core/processing/nodes/__init__.py,sha256=WNUmYmZF3uqF2qiJ1L7y0u9qiVD9YnluKds0wA5opJE,4813
46
- trilogy/core/processing/nodes/base_node.py,sha256=A7Kx_2KlEjE3jcsvvFcwMmvCJiIRFS7jDjePTCpNU9E,15573
47
- trilogy/core/processing/nodes/filter_node.py,sha256=metDcI7b2QsONOy5l0Mx7by1OhXac0N8yKUDoL_2WWo,2342
48
- trilogy/core/processing/nodes/group_node.py,sha256=j6uiHmAA01ByhZmeJQrAm4ophdvo517b-OibEZSQFLg,7249
49
- trilogy/core/processing/nodes/merge_node.py,sha256=Nc0nV56C-1DzanTg54llvlkuHyK05A17XMa2ut0OeK0,14921
50
- trilogy/core/processing/nodes/select_node_v2.py,sha256=Hk_fQnI8NzpDSaPDNu_C-2QWktf3ZORhzbx0TeOK5Q8,8144
51
- trilogy/core/processing/nodes/union_node.py,sha256=WHycDepNr16flkgQdwyZRo1g-kzYKWVUb6CZ7N_U4OA,1402
52
- trilogy/core/processing/nodes/unnest_node.py,sha256=aR1XKa-bT7f45QYKUOS0EUuc0t4GbvYAEG8ZYFJ67sI,2151
53
- trilogy/core/processing/nodes/window_node.py,sha256=kXHhOZ9CZ8AQvUbJXCIxUPQ-NF3ooZT7VBgNUyM3VM8,1213
46
+ trilogy/core/processing/nodes/base_node.py,sha256=izspnhnzyGKF1KuUpAQmZByxE85bPrrrUj3Q18EDwxM,16515
47
+ trilogy/core/processing/nodes/filter_node.py,sha256=j7icDAXJ7oFPkHTOQVmm9QbZxrhhYEUGJj2lSiguXKA,2292
48
+ trilogy/core/processing/nodes/group_node.py,sha256=g67rsj5DK9-fna0ppVpfuTkwaQzwhKwAur4HNnpNwgU,7438
49
+ trilogy/core/processing/nodes/merge_node.py,sha256=eiqGEvO8UgN-YJ7mlkNlodR4vAGsUJ7d5y2hytvcgDU,14866
50
+ trilogy/core/processing/nodes/select_node_v2.py,sha256=t3ln9Kxeml8mVTnLgtNPvavb5TLTRtfkJ0nyxh7UYUs,8212
51
+ trilogy/core/processing/nodes/union_node.py,sha256=1QgOWkjJ-ADFdanoRzi0EM5buhuzJbmlda9BAUGp4mM,1352
52
+ trilogy/core/processing/nodes/unnest_node.py,sha256=0TFANwqVPaVpUR6SF5uweGTlXfEnagXRBBZU6dUwtcY,2101
53
+ trilogy/core/processing/nodes/window_node.py,sha256=yYwWuOq1Uwm-xEl8lFH_urm-YXaAGAgNhE20MEoD5QQ,1163
54
54
  trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
- trilogy/dialect/base.py,sha256=KZwtnni34pfghrBH2nBfa8ZDf-BH_cEuQKxBB3JvZWo,38003
55
+ trilogy/dialect/base.py,sha256=DR7cHoL5rbRBnsj6PCq5wK8GHH-l5szpKXUaxMqx1Mw,38568
56
56
  trilogy/dialect/bigquery.py,sha256=mKC3zoEU232h9RtIXJjqiZ72lWH8a6S28p6wAZKrAfg,2952
57
57
  trilogy/dialect/common.py,sha256=b0E6JqdKaaSzThLiFa9jwUg4YnXahf-3bqmzOn5z-6E,3827
58
58
  trilogy/dialect/config.py,sha256=UiBY2tBbNk9owx-zxP_3lN9lErEUXhXIU_bcXA18AvU,2992
59
- trilogy/dialect/duckdb.py,sha256=qh5XMgtl9LBUZ8DJ65GLui_nk0Iq9n11bbA6Ek9sum0,3419
59
+ trilogy/dialect/duckdb.py,sha256=O-2k0zaJKnr_McdU6iqBHcufCtHwsIKanAnpBD5o33A,3685
60
60
  trilogy/dialect/enums.py,sha256=iaghGgOl6zRr4RxRn4TxRnxZU9iSYJG6hN5wqYiBRNQ,3948
61
61
  trilogy/dialect/postgres.py,sha256=VH4EB4myjIeZTHeFU6vK00GxY9c53rCBjg2mLbdaCEE,3254
62
62
  trilogy/dialect/presto.py,sha256=y2BMOXvpKh1_cXnpGhG0sjhGP-pNVLkf760Hz_pNw_s,3386
@@ -64,22 +64,22 @@ trilogy/dialect/snowflake.py,sha256=wmao9p26jX5yIX5SC8sRAZTXkPGTvq6ixO693QTfhz8,
64
64
  trilogy/dialect/sql_server.py,sha256=7iFpo2xztQ4ZJVwJ5n8kntWreymRzz035iClGZp3Nyc,3117
65
65
  trilogy/hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
66
  trilogy/hooks/base_hook.py,sha256=gD6_sjzTzchpLIn3CvJzkM9IvaWNfQUra3yDh9-s8qQ,1125
67
- trilogy/hooks/graph_hook.py,sha256=wljLY-Ac22vgn7PlsVlRy9HswrapRvVzHrFMlD8qhOY,2468
67
+ trilogy/hooks/graph_hook.py,sha256=6YAHlVnak03JtWEox2oAroMdRdN7ETUN7SqwQXhdTdE,2870
68
68
  trilogy/hooks/query_debugger.py,sha256=FoDh2bu2NiwLusVhKa5El_l8EKaqfET7zn55GP0TkOE,4644
69
69
  trilogy/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
70
  trilogy/parsing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
- trilogy/parsing/common.py,sha256=haPZbJrola5Fvwp940A-MJ1o-EhGXKsRFa-Y2e7OsjU,10370
71
+ trilogy/parsing/common.py,sha256=Cm8GPznLphvc44K9EVpo_iVBRtWuH0zFMa8ekYfmVBg,10887
72
72
  trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
73
73
  trilogy/parsing/exceptions.py,sha256=92E5i2frv5hj9wxObJZsZqj5T6bglvPzvdvco_vW1Zk,38
74
74
  trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
75
- trilogy/parsing/parse_engine.py,sha256=M2CAqqA-JlR6TK17jkPlcOmy4YhPVlH8YByVTDP3cCI,67122
75
+ trilogy/parsing/parse_engine.py,sha256=BLO79wqweLptVq66VKAHjF68ggE_gd4XFtsWv9HTtGU,68671
76
76
  trilogy/parsing/render.py,sha256=Dr0QKIaAUi9uxfZZJVNV-todKoTA-tsWXNXPJ4Ohjn0,15650
77
- trilogy/parsing/trilogy.lark,sha256=d_d3H8ExBcrVffPLq1TgTcEyWDppPJO2zB6cC6mdq9I,12489
77
+ trilogy/parsing/trilogy.lark,sha256=EazfEvYPuvkPkNjUnVzFi0uD9baavugbSI8CyfawShk,12573
78
78
  trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
79
  trilogy/scripts/trilogy.py,sha256=DQDW81E5mDMWFP8oPw8q-IyrR2JGxQSDWgUWe2VTSRQ,3731
80
- pytrilogy-0.0.2.48.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
81
- pytrilogy-0.0.2.48.dist-info/METADATA,sha256=Rcj4LfUCQoMs2K3dtgpBeFRpNOonJ9A0Q7kstGsMKnk,8426
82
- pytrilogy-0.0.2.48.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
83
- pytrilogy-0.0.2.48.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
84
- pytrilogy-0.0.2.48.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
85
- pytrilogy-0.0.2.48.dist-info/RECORD,,
80
+ pytrilogy-0.0.2.50.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
81
+ pytrilogy-0.0.2.50.dist-info/METADATA,sha256=uqgnhuCqk3kTbmMRDbHps-acUl4qTZoGJUMDLhALK4w,8426
82
+ pytrilogy-0.0.2.50.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
83
+ pytrilogy-0.0.2.50.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
84
+ pytrilogy-0.0.2.50.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
85
+ pytrilogy-0.0.2.50.dist-info/RECORD,,
trilogy/__init__.py CHANGED
@@ -4,6 +4,6 @@ from trilogy.dialect.enums import Dialects
4
4
  from trilogy.executor import Executor
5
5
  from trilogy.parser import parse
6
6
 
7
- __version__ = "0.0.2.48"
7
+ __version__ = "0.0.2.50"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
trilogy/core/enums.py CHANGED
@@ -120,6 +120,8 @@ class FunctionType(Enum):
120
120
 
121
121
  ALIAS = "alias"
122
122
 
123
+ PARENTHETICAL = "parenthetical"
124
+
123
125
  # Generic
124
126
  CASE = "case"
125
127
  CAST = "cast"
@@ -135,6 +137,8 @@ class FunctionType(Enum):
135
137
  ATTR_ACCESS = "attr_access"
136
138
  STRUCT = "struct"
137
139
  ARRAY = "array"
140
+ DATE_LITERAL = "date_literal"
141
+ DATETIME_LITERAL = "datetime_literal"
138
142
 
139
143
  # TEXT AND MAYBE MORE
140
144
  SPLIT = "split"
@@ -260,6 +264,13 @@ class ComparisonOperator(Enum):
260
264
  CONTAINS = "contains"
261
265
  ELSE = "else"
262
266
 
267
+ def __eq__(self, other):
268
+ if isinstance(other, str):
269
+ return self.value == other
270
+ if not isinstance(other, ComparisonOperator):
271
+ return False
272
+ return self.value == other.value
273
+
263
274
  @classmethod
264
275
  def _missing_(cls, value):
265
276
  if not isinstance(value, list) and " " in str(value):
trilogy/core/functions.py CHANGED
@@ -1,3 +1,4 @@
1
+ from datetime import date, datetime
1
2
  from typing import Optional
2
3
 
3
4
  from trilogy.constants import MagicConstants
@@ -17,6 +18,8 @@ from trilogy.core.models import (
17
18
  arg_to_datatype,
18
19
  )
19
20
 
21
+ GENERIC_ARGS = Concept | Function | str | int | float | date | datetime
22
+
20
23
 
21
24
  def create_function_derived_concept(
22
25
  name: str,
@@ -262,7 +265,7 @@ def get_attr_datatype(
262
265
  return arg.datatype
263
266
 
264
267
 
265
- def AttrAccess(args: list[Concept]):
268
+ def AttrAccess(args: list[GENERIC_ARGS]):
266
269
  return Function(
267
270
  operator=FunctionType.ATTR_ACCESS,
268
271
  arguments=args,
trilogy/core/models.py CHANGED
@@ -5,6 +5,7 @@ import hashlib
5
5
  import os
6
6
  from abc import ABC
7
7
  from collections import UserDict, UserList, defaultdict
8
+ from datetime import date, datetime
8
9
  from enum import Enum
9
10
  from functools import cached_property
10
11
  from pathlib import Path
@@ -467,7 +468,7 @@ class Concept(Mergeable, Namespaced, SelectContext, BaseModel):
467
468
  )
468
469
 
469
470
  def __repr__(self):
470
- base = f"{self.namespace}.{self.address}@{self.grain}"
471
+ base = f"{self.address}@{self.grain}"
471
472
  return base
472
473
 
473
474
  @property
@@ -662,11 +663,24 @@ class Concept(Mergeable, Namespaced, SelectContext, BaseModel):
662
663
  local_concepts=local_concepts, grain=grain, environment=environment
663
664
  )
664
665
  final_grain = self.grain
665
-
666
+ keys = (
667
+ tuple(
668
+ [
669
+ x.with_select_context(local_concepts, grain, environment)
670
+ for x in self.keys
671
+ ]
672
+ )
673
+ if self.keys
674
+ else None
675
+ )
666
676
  if self.is_aggregate and isinstance(new_lineage, Function):
667
677
  new_lineage = AggregateWrapper(function=new_lineage, by=grain.components)
668
678
  final_grain = grain
669
-
679
+ keys = tuple(grain.components)
680
+ elif (
681
+ self.is_aggregate and not keys and isinstance(new_lineage, AggregateWrapper)
682
+ ):
683
+ keys = tuple(new_lineage.by)
670
684
  return self.__class__(
671
685
  name=self.name,
672
686
  datatype=self.datatype,
@@ -675,16 +689,7 @@ class Concept(Mergeable, Namespaced, SelectContext, BaseModel):
675
689
  lineage=new_lineage,
676
690
  grain=final_grain,
677
691
  namespace=self.namespace,
678
- keys=(
679
- tuple(
680
- [
681
- x.with_select_context(local_concepts, grain, environment)
682
- for x in self.keys
683
- ]
684
- )
685
- if self.keys
686
- else None
687
- ),
692
+ keys=keys,
688
693
  modifiers=self.modifiers,
689
694
  # a select needs to always defer to the environment for pseudonyms
690
695
  # TODO: evaluate if this should be cached
@@ -1260,6 +1265,8 @@ class Function(Mergeable, Namespaced, SelectContext, BaseModel):
1260
1265
  int,
1261
1266
  float,
1262
1267
  str,
1268
+ date,
1269
+ datetime,
1263
1270
  MapWrapper[Any, Any],
1264
1271
  DataType,
1265
1272
  ListType,
@@ -2626,7 +2633,7 @@ class QueryDatasource(BaseModel):
2626
2633
  and CONFIG.validate_missing
2627
2634
  ):
2628
2635
  raise SyntaxError(
2629
- f"Missing source map for {concept.address} on {key}, have {v}"
2636
+ f"On query datasource missing source map for {concept.address} on {key}, have {v}"
2630
2637
  )
2631
2638
  return v
2632
2639
 
@@ -3864,6 +3871,8 @@ class Comparison(
3864
3871
  float,
3865
3872
  list,
3866
3873
  bool,
3874
+ datetime,
3875
+ date,
3867
3876
  Function,
3868
3877
  Concept,
3869
3878
  "Conditional",
@@ -3880,6 +3889,8 @@ class Comparison(
3880
3889
  float,
3881
3890
  list,
3882
3891
  bool,
3892
+ date,
3893
+ datetime,
3883
3894
  Concept,
3884
3895
  Function,
3885
3896
  "Conditional",
@@ -5004,5 +5015,9 @@ def arg_to_datatype(arg) -> DataType | ListType | StructType | MapType | Numeric
5004
5015
  return ListType(type=wrapper.type)
5005
5016
  elif isinstance(arg, MapWrapper):
5006
5017
  return MapType(key_type=arg.key_type, value_type=arg.value_type)
5018
+ elif isinstance(arg, datetime):
5019
+ return DataType.DATETIME
5020
+ elif isinstance(arg, date):
5021
+ return DataType.DATE
5007
5022
  else:
5008
5023
  raise ValueError(f"Cannot parse arg datatype for arg of raw type {type(arg)}")
@@ -359,7 +359,6 @@ def generate_node(
359
359
  input_concepts=[],
360
360
  output_concepts=constant_targets,
361
361
  environment=environment,
362
- g=g,
363
362
  parents=[],
364
363
  depth=depth + 1,
365
364
  )
@@ -569,6 +568,8 @@ def validate_stack(
569
568
  resolved = node.resolve()
570
569
 
571
570
  for concept in resolved.output_concepts:
571
+ if concept in resolved.hidden_concepts:
572
+ continue
572
573
  validate_concept(
573
574
  concept,
574
575
  node,
@@ -836,6 +837,7 @@ def _search_concepts(
836
837
  PurposeLineage.ROWSET,
837
838
  PurposeLineage.BASIC,
838
839
  PurposeLineage.MULTISELECT,
840
+ PurposeLineage.UNION,
839
841
  ]:
840
842
  skip.add(priority_concept.address)
841
843
  break
@@ -903,7 +905,6 @@ def _search_concepts(
903
905
  input_concepts=non_virtual,
904
906
  output_concepts=non_virtual,
905
907
  environment=environment,
906
- g=g,
907
908
  parents=stack,
908
909
  depth=depth,
909
910
  )
@@ -984,7 +985,6 @@ def source_query_concepts(
984
985
  x for x in root.output_concepts if x.address not in root.hidden_concepts
985
986
  ],
986
987
  environment=environment,
987
- g=g,
988
988
  parents=[root],
989
989
  partial_concepts=root.partial_concepts,
990
990
  )
@@ -130,7 +130,6 @@ def gen_property_enrichment_node(
130
130
  ),
131
131
  output_concepts=base_node.output_concepts + extra_properties,
132
132
  environment=environment,
133
- g=g,
134
133
  parents=[
135
134
  base_node,
136
135
  ]
@@ -209,7 +208,6 @@ def gen_enrichment_node(
209
208
  input_concepts=unique(join_keys + extra_required + non_hidden, "address"),
210
209
  output_concepts=unique(join_keys + extra_required + non_hidden, "address"),
211
210
  environment=environment,
212
- g=g,
213
211
  parents=[enrich_node, base_node],
214
212
  force_group=False,
215
213
  preexisting_conditions=conditions.conditional if conditions else None,
@@ -117,7 +117,6 @@ def gen_filter_node(
117
117
  input_concepts=row_parent.output_concepts,
118
118
  output_concepts=[concept] + row_parent.output_concepts,
119
119
  environment=row_parent.environment,
120
- g=row_parent.g,
121
120
  parents=[row_parent],
122
121
  depth=row_parent.depth,
123
122
  partial_concepts=row_parent.partial_concepts,
@@ -161,7 +160,6 @@ def gen_filter_node(
161
160
  ),
162
161
  output_concepts=[concept, immediate_parent] + parent_row_concepts,
163
162
  environment=environment,
164
- g=g,
165
163
  parents=core_parents,
166
164
  grain=Grain(
167
165
  components=[immediate_parent] + parent_row_concepts,
@@ -202,7 +200,6 @@ def gen_filter_node(
202
200
  ]
203
201
  + local_optional,
204
202
  environment=environment,
205
- g=g,
206
203
  parents=[
207
204
  # this node fetches only what we need to filter
208
205
  filter_node,
@@ -100,7 +100,6 @@ def gen_group_node(
100
100
  output_concepts=output_concepts,
101
101
  input_concepts=parent_concepts,
102
102
  environment=environment,
103
- g=g,
104
103
  parents=parents,
105
104
  depth=depth,
106
105
  preexisting_conditions=conditions.conditional if conditions else None,
@@ -45,7 +45,6 @@ def gen_group_to_node(
45
45
  output_concepts=parent_concepts + [concept],
46
46
  input_concepts=parent_concepts,
47
47
  environment=environment,
48
- g=g,
49
48
  parents=parents,
50
49
  depth=depth,
51
50
  )
@@ -76,7 +75,6 @@ def gen_group_to_node(
76
75
  + [x for x in parent_concepts if x.address != concept.address],
77
76
  output_concepts=[concept] + local_optional,
78
77
  environment=environment,
79
- g=g,
80
78
  parents=[
81
79
  # this node gets the group
82
80
  group_node,
@@ -108,7 +108,6 @@ def gen_multiselect_node(
108
108
  input_concepts=[x for y in base_parents for x in y.output_concepts],
109
109
  output_concepts=[x for y in base_parents for x in y.output_concepts],
110
110
  environment=environment,
111
- g=g,
112
111
  depth=depth,
113
112
  parents=base_parents,
114
113
  node_joins=node_joins,
@@ -178,7 +177,6 @@ def gen_multiselect_node(
178
177
  input_concepts=enrich_node.output_concepts + node.output_concepts,
179
178
  output_concepts=node.output_concepts + local_optional,
180
179
  environment=environment,
181
- g=g,
182
180
  depth=depth,
183
181
  parents=[
184
182
  # this node gets the multiselect
@@ -333,7 +333,6 @@ def subgraphs_to_merge_node(
333
333
  input_concepts=unique(input_c, "address"),
334
334
  output_concepts=[x for x in all_concepts],
335
335
  environment=environment,
336
- g=g,
337
336
  parents=parents,
338
337
  depth=depth,
339
338
  # conditions=conditions,
@@ -38,7 +38,7 @@ def gen_rowset_node(
38
38
  rowset: RowsetDerivationStatement = lineage.rowset
39
39
  select: SelectStatement | MultiSelectStatement = lineage.rowset.select
40
40
 
41
- node = get_query_node(environment, select, graph=g, history=history)
41
+ node = get_query_node(environment, select)
42
42
 
43
43
  if not node:
44
44
  logger.info(
@@ -94,15 +94,22 @@ def gen_rowset_node(
94
94
  logger.info(
95
95
  f"{padding(depth)}{LOGGER_PREFIX} no enrichment required for rowset node as all optional found or no optional; exiting early."
96
96
  )
97
- # node.set_preexisting_conditions(conditions.conditional if conditions else None)
98
97
  return node
99
-
100
- possible_joins = concept_to_relevant_joins(node.output_concepts)
98
+ possible_joins = concept_to_relevant_joins(
99
+ [x for x in node.output_concepts if x.derivation != PurposeLineage.ROWSET]
100
+ )
101
+ logger.info({x.address: x.keys for x in possible_joins})
101
102
  if not possible_joins:
102
103
  logger.info(
103
104
  f"{padding(depth)}{LOGGER_PREFIX} no possible joins for rowset node to get {[x.address for x in local_optional]}; have {[x.address for x in node.output_concepts]}"
104
105
  )
105
106
  return node
107
+ if any(x.derivation == PurposeLineage.ROWSET for x in possible_joins):
108
+ logger.info(
109
+ f"{padding(depth)}{LOGGER_PREFIX} cannot enrich rowset node with rowset concepts; exiting early"
110
+ )
111
+ return node
112
+ logger.info([x.address for x in possible_joins + local_optional])
106
113
  enrich_node: MergeNode = source_concepts( # this fetches the parent + join keys
107
114
  # to then connect to the rest of the query
108
115
  mandatory_list=possible_joins + local_optional,
@@ -110,22 +117,34 @@ def gen_rowset_node(
110
117
  g=g,
111
118
  depth=depth + 1,
112
119
  conditions=conditions,
120
+ history=history,
113
121
  )
114
122
  if not enrich_node:
115
123
  logger.info(
116
124
  f"{padding(depth)}{LOGGER_PREFIX} Cannot generate rowset enrichment node for {concept} with optional {local_optional}, returning just rowset node"
117
125
  )
118
126
  return node
127
+
128
+ non_hidden = [
129
+ x for x in node.output_concepts if x.address not in node.hidden_concepts
130
+ ]
131
+ for x in possible_joins:
132
+ if x.address in node.hidden_concepts:
133
+ node.unhide_output_concepts([x])
134
+ non_hidden_enrich = [
135
+ x
136
+ for x in enrich_node.output_concepts
137
+ if x.address not in enrich_node.hidden_concepts
138
+ ]
119
139
  return MergeNode(
120
- input_concepts=enrich_node.output_concepts + node.output_concepts,
121
- output_concepts=node.output_concepts + local_optional,
140
+ input_concepts=non_hidden + non_hidden_enrich,
141
+ output_concepts=non_hidden + local_optional,
122
142
  environment=environment,
123
- g=g,
124
143
  depth=depth,
125
144
  parents=[
126
145
  node,
127
146
  enrich_node,
128
147
  ],
129
- partial_concepts=node.partial_concepts,
148
+ partial_concepts=node.partial_concepts + enrich_node.partial_concepts,
130
149
  preexisting_conditions=conditions.conditional if conditions else None,
131
150
  )