pytrilogy 0.0.3.54__py3-none-any.whl → 0.0.3.56__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 (37) hide show
  1. {pytrilogy-0.0.3.54.dist-info → pytrilogy-0.0.3.56.dist-info}/METADATA +1 -1
  2. {pytrilogy-0.0.3.54.dist-info → pytrilogy-0.0.3.56.dist-info}/RECORD +37 -30
  3. trilogy/__init__.py +1 -1
  4. trilogy/constants.py +2 -0
  5. trilogy/core/enums.py +6 -0
  6. trilogy/core/functions.py +3 -0
  7. trilogy/core/models/author.py +12 -4
  8. trilogy/core/models/execute.py +207 -2
  9. trilogy/core/optimization.py +3 -3
  10. trilogy/core/optimizations/inline_datasource.py +5 -7
  11. trilogy/core/processing/concept_strategies_v3.py +323 -878
  12. trilogy/core/processing/discovery_loop.py +0 -0
  13. trilogy/core/processing/discovery_node_factory.py +469 -0
  14. trilogy/core/processing/discovery_utility.py +123 -0
  15. trilogy/core/processing/discovery_validation.py +155 -0
  16. trilogy/core/processing/node_generators/__init__.py +2 -0
  17. trilogy/core/processing/node_generators/recursive_node.py +87 -0
  18. trilogy/core/processing/node_generators/select_node.py +6 -8
  19. trilogy/core/processing/nodes/__init__.py +4 -4
  20. trilogy/core/processing/nodes/recursive_node.py +46 -0
  21. trilogy/core/query_processor.py +7 -1
  22. trilogy/dialect/base.py +11 -2
  23. trilogy/dialect/bigquery.py +5 -6
  24. trilogy/dialect/common.py +19 -3
  25. trilogy/dialect/duckdb.py +1 -1
  26. trilogy/dialect/snowflake.py +8 -8
  27. trilogy/parsing/common.py +4 -3
  28. trilogy/parsing/parse_engine.py +12 -0
  29. trilogy/parsing/trilogy.lark +3 -1
  30. trilogy/std/date.preql +3 -1
  31. trilogy/std/geography.preql +4 -0
  32. trilogy/std/money.preql +65 -4
  33. trilogy/std/net.preql +8 -0
  34. {pytrilogy-0.0.3.54.dist-info → pytrilogy-0.0.3.56.dist-info}/WHEEL +0 -0
  35. {pytrilogy-0.0.3.54.dist-info → pytrilogy-0.0.3.56.dist-info}/entry_points.txt +0 -0
  36. {pytrilogy-0.0.3.54.dist-info → pytrilogy-0.0.3.56.dist-info}/licenses/LICENSE.md +0 -0
  37. {pytrilogy-0.0.3.54.dist-info → pytrilogy-0.0.3.56.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.54
3
+ Version: 0.0.3.56
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -1,7 +1,7 @@
1
- pytrilogy-0.0.3.54.dist-info/licenses/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
2
- trilogy/__init__.py,sha256=Wz4e3LWZ4MWyBm3EuLrz5-n5-yyu96rHR7k-4JPA4RE,303
1
+ pytrilogy-0.0.3.56.dist-info/licenses/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
2
+ trilogy/__init__.py,sha256=E6tZFZr367OLf8N5bIFQ-PZJTvXpcgVF1NGc8rJZXsk,303
3
3
  trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- trilogy/constants.py,sha256=5eQxk1A0pv-TQk3CCvgZCFA9_K-6nxrOm7E5Lxd7KIY,1652
4
+ trilogy/constants.py,sha256=lv_aJWP6dn6e2aF4BAE72jbnNtceFddfqtiDSsvzno0,1692
5
5
  trilogy/engine.py,sha256=OK2RuqCIUId6yZ5hfF8J1nxGP0AJqHRZiafcowmW0xc,1728
6
6
  trilogy/executor.py,sha256=GwNhP9UW4565dxnpHbw-VWNE2lX8uroQJQtSpC_j2pI,16298
7
7
  trilogy/parser.py,sha256=o4cfk3j3yhUFoiDKq9ZX_GjBF3dKhDjXEwb63rcBkBM,293
@@ -11,34 +11,38 @@ trilogy/utility.py,sha256=euQccZLKoYBz0LNg5tzLlvv2YHvXh9HArnYp1V3uXsM,763
11
11
  trilogy/authoring/__init__.py,sha256=v9PRuZs4fTnxhpXAnwTxCDwlLasUax6g2FONidcujR4,2369
12
12
  trilogy/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  trilogy/core/constants.py,sha256=7XaCpZn5mQmjTobbeBn56SzPWq9eMNDfzfsRU-fP0VE,171
14
- trilogy/core/enums.py,sha256=QVylGAe6epdGGpOKkeJ4cbx0mIZb0aARAKhsoZaGhoA,7576
14
+ trilogy/core/enums.py,sha256=9thKx6u-Z3vzT3iGBBUtHsHCXaU-8L4IaqGJp1G7It0,7737
15
15
  trilogy/core/env_processor.py,sha256=pFsxnluKIusGKx1z7tTnfsd_xZcPy9pZDungkjkyvI0,3170
16
16
  trilogy/core/environment_helpers.py,sha256=VvPIiFemqaLLpIpLIqprfu63K7muZ1YzNg7UZIUph8w,8267
17
17
  trilogy/core/ergonomics.py,sha256=e-7gE29vPLFdg0_A1smQ7eOrUwKl5VYdxRSTddHweRA,1631
18
18
  trilogy/core/exceptions.py,sha256=JPYyBcit3T_pRtlHdtKSeVJkIyWUTozW2aaut25A2xI,673
19
- trilogy/core/functions.py,sha256=IvqHyuO__o6Th8tkDWjb9cDxQDly6l3ZEfJ9y8YrTRU,29227
19
+ trilogy/core/functions.py,sha256=poVfAwet1xdxTkC7WL38UmGRDpUVO9iSMNWSagl9_r4,29302
20
20
  trilogy/core/graph_models.py,sha256=z17EoO8oky2QOuO6E2aMWoVNKEVJFhLdsQZOhC4fNLU,2079
21
21
  trilogy/core/internal.py,sha256=iicDBlC6nM8d7e7jqzf_ZOmpUsW8yrr2AA8AqEiLx-s,1577
22
- trilogy/core/optimization.py,sha256=ClDPMuuLBjuZCHdRGsuNhKNNTkbev1I22SbnLMzHT60,8839
23
- trilogy/core/query_processor.py,sha256=NNzYPKN5HzivQFXugSbJC_MaupkwOYii7A_vnXuBIK4,20063
22
+ trilogy/core/optimization.py,sha256=ChIAv0kRmw9RKyDGDCdSdbIN5fJGMkIlE6eVfTFsxg4,8867
23
+ trilogy/core/query_processor.py,sha256=jSS1xZFDqBuI0sZBbuYAAuuVGwas7W-mV_v5oFZJFpA,20275
24
24
  trilogy/core/utility.py,sha256=3VC13uSQWcZNghgt7Ot0ZTeEmNqs__cx122abVq9qhM,410
25
25
  trilogy/core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
- trilogy/core/models/author.py,sha256=KKW_3A1hdwq7D2dFwI6xZanukPuCQQ23R4GzE5VRJ6c,77206
26
+ trilogy/core/models/author.py,sha256=8XbIsQr6cQrgo9uzee5qRoYiMdEG7yKF4FiiWImW7U0,77490
27
27
  trilogy/core/models/build.py,sha256=yBiOQ4Bhjz09pSD1jSGhhf9QFFQuplrvZ0JQB5-iXHk,63104
28
28
  trilogy/core/models/build_environment.py,sha256=s_C9xAHuD3yZ26T15pWVBvoqvlp2LdZ8yjsv2_HdXLk,5363
29
29
  trilogy/core/models/core.py,sha256=wx6hJcFECMG-Ij972ADNkr-3nFXkYESr82ObPiC46_U,10875
30
30
  trilogy/core/models/datasource.py,sha256=6RjJUd2u4nYmEwFBpJlM9LbHVYDv8iHJxqiBMZqUrwI,9422
31
31
  trilogy/core/models/environment.py,sha256=AVSrvjNcNX535GhCPtYhCRY2Lp_Hj0tdY3VVt_kZb9Q,27260
32
- trilogy/core/models/execute.py,sha256=F7-9VyUz5MC__VUSXd4U7gUb23Dc5PH5FdMUt6FqCPM,35214
32
+ trilogy/core/models/execute.py,sha256=_JC93S5tpCQM9jpgmmbd6wkLMEfPvaMZwWZBVcgehlI,42931
33
33
  trilogy/core/optimizations/__init__.py,sha256=YH2-mGXZnVDnBcWVi8vTbrdw7Qs5TivG4h38rH3js_I,290
34
34
  trilogy/core/optimizations/base_optimization.py,sha256=gzDOKImoFn36k7XBD3ysEYDnbnb6vdVIztUfFQZsGnM,513
35
- trilogy/core/optimizations/inline_datasource.py,sha256=AHuTGh2x0GQ8usOe0NiFncfTFQ_KogdgDl4uucmhIbI,4241
35
+ trilogy/core/optimizations/inline_datasource.py,sha256=2sWNRpoRInnTgo9wExVT_r9RfLAQHI57reEV5cGHUcg,4329
36
36
  trilogy/core/optimizations/predicate_pushdown.py,sha256=g4AYE8Aw_iMlAh68TjNXGP754NTurrDduFECkUjoBnc,9399
37
37
  trilogy/core/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
- trilogy/core/processing/concept_strategies_v3.py,sha256=8Wos5d9_tzfnzSbejb36QL4uoGPQ3GiwP27u_a4JrcE,44097
38
+ trilogy/core/processing/concept_strategies_v3.py,sha256=COK6rpKwhXxfawKhliz6DryqZa7FSAXQ6eD1eMMq1JI,22005
39
+ trilogy/core/processing/discovery_loop.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
+ trilogy/core/processing/discovery_node_factory.py,sha256=CFQPaqsJPqe0ZGnU1a81R1ZjlRNihbiR0qQtakcUEqI,14639
41
+ trilogy/core/processing/discovery_utility.py,sha256=hF3aUbRHHZFeFT5aBjE6TuSeU60I90gzmj512QXG_t8,4856
42
+ trilogy/core/processing/discovery_validation.py,sha256=Ek9jviFgimLMUMYLXBChUQmOD94ihhwQ3NDVe6RTdWg,4930
39
43
  trilogy/core/processing/graph_utils.py,sha256=8QUVrkE9j-9C1AyrCb1nQEh8daCe0u1HuXl-Te85lag,1205
40
44
  trilogy/core/processing/utility.py,sha256=rfzdgl-vWkCyhLzXNNuWgPLK59eiYypQb6TdZKymUqk,21469
41
- trilogy/core/processing/node_generators/__init__.py,sha256=o8rOFHPSo-s_59hREwXMW6gjUJCsiXumdbJNozHUf-Y,800
45
+ trilogy/core/processing/node_generators/__init__.py,sha256=w8TQQgNhyAra6JQHdg1_Ags4BGyxjXYruu6UeC5yOkI,873
42
46
  trilogy/core/processing/node_generators/basic_node.py,sha256=UVsXMn6jTjm_ofVFt218jAS11s4RV4zD781vP4im-GI,3371
43
47
  trilogy/core/processing/node_generators/common.py,sha256=PdysdroW9DUADP7f5Wv_GKPUyCTROZV1g3L45fawxi8,9443
44
48
  trilogy/core/processing/node_generators/filter_node.py,sha256=0hdfiS2I-Jvr6P-il3jnAJK-g-DMG7_cFbZGCnLnJAo,10032
@@ -46,20 +50,22 @@ trilogy/core/processing/node_generators/group_node.py,sha256=nIfiMrJQEksUfqAeeA3
46
50
  trilogy/core/processing/node_generators/group_to_node.py,sha256=jKcNCDOY6fNblrdZwaRU0sbUSr9H0moQbAxrGgX6iGA,3832
47
51
  trilogy/core/processing/node_generators/multiselect_node.py,sha256=GWV5yLmKTe1yyPhN60RG1Rnrn4ktfn9lYYXi_FVU4UI,7061
48
52
  trilogy/core/processing/node_generators/node_merge_node.py,sha256=sv55oynfqgpHEpo1OEtVDri-5fywzPhDlR85qaWikvY,16195
53
+ trilogy/core/processing/node_generators/recursive_node.py,sha256=l5zdh0dURKwmAy8kK4OpMtZfyUEQRk6N-PwSWIyBpSM,2468
49
54
  trilogy/core/processing/node_generators/rowset_node.py,sha256=2BiSsegbRF9csJ_Xl8P_CxIm4dAAb7dF29u6v_Odr-A,6709
50
55
  trilogy/core/processing/node_generators/select_merge_node.py,sha256=lxXhMhDKGbu67QFNbbAT-BO8gbWppIvjn_hAXpLEPe0,19953
51
- trilogy/core/processing/node_generators/select_node.py,sha256=Y-zO0AFkTrpi2LyebjpyHU7WWANr7nKZSS9rY7DH4Wo,1888
56
+ trilogy/core/processing/node_generators/select_node.py,sha256=3dvw0d53eUtCRCUPN6J48I3qBEX1Wha7saQ_ndPu6_I,1777
52
57
  trilogy/core/processing/node_generators/synonym_node.py,sha256=9LHK2XHDjbyTLjmDQieskG8fqbiSpRnFOkfrutDnOTE,2258
53
58
  trilogy/core/processing/node_generators/union_node.py,sha256=VNo6Oey4p8etU9xrOh2oTT2lIOTvY6PULUPRvVa2uxU,2877
54
59
  trilogy/core/processing/node_generators/unnest_node.py,sha256=cOEKnMRzXUW3bwmiOlgn3E1-B38osng0dh2pDykwITY,2410
55
60
  trilogy/core/processing/node_generators/window_node.py,sha256=GP3Hvkbb0TDA6ef7W7bmvQEHVH-NRIfBT_0W4fcH3g4,6529
56
61
  trilogy/core/processing/node_generators/select_helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
62
  trilogy/core/processing/node_generators/select_helpers/datasource_injection.py,sha256=GMW07bb6hXurhF0hZLYoMAKSIS65tat5hwBjvqqPeSA,6516
58
- trilogy/core/processing/nodes/__init__.py,sha256=oHDknqAZFm6KSDDbzJXj8HDGDh-dn-YjHDGqiXc8Psw,6054
63
+ trilogy/core/processing/nodes/__init__.py,sha256=97eFwBa9vBhhXszgO-9JVxUzejKKeSHG6DilxRCWRm0,6083
59
64
  trilogy/core/processing/nodes/base_node.py,sha256=IdKR2yaQGY1iRgKXgxF1UtlyuJEmPXWRh0rGFXv7Z_U,18111
60
65
  trilogy/core/processing/nodes/filter_node.py,sha256=5VtRfKbCORx0dV-vQfgy3gOEkmmscL9f31ExvlODwvY,2461
61
66
  trilogy/core/processing/nodes/group_node.py,sha256=MUvcOg9U5J6TnWBel8eht9PdI9BfAKjUxmfjP_ZXx9o,10484
62
67
  trilogy/core/processing/nodes/merge_node.py,sha256=02oWRca0ba41U6PSAB14jwnWWxoyrvxRPLwkli259SY,15865
68
+ trilogy/core/processing/nodes/recursive_node.py,sha256=k0rizxR8KE64ievfHx_GPfQmU8QAP118Laeyq5BLUOk,1526
63
69
  trilogy/core/processing/nodes/select_node_v2.py,sha256=Xyfq8lU7rP7JTAd8VV0ATDNal64n4xIBgWQsOuMe_Ak,8824
64
70
  trilogy/core/processing/nodes/union_node.py,sha256=fDFzLAUh5876X6_NM7nkhoMvHEdGJ_LpvPokpZKOhx4,1425
65
71
  trilogy/core/processing/nodes/unnest_node.py,sha256=oLKMMNMx6PLDPlt2V5neFMFrFWxET8r6XZElAhSNkO0,2181
@@ -70,16 +76,16 @@ trilogy/core/statements/build.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
70
76
  trilogy/core/statements/common.py,sha256=KxEmz2ySySyZ6CTPzn0fJl5NX2KOk1RPyuUSwWhnK1g,759
71
77
  trilogy/core/statements/execute.py,sha256=cSlvpHFOqpiZ89pPZ5GDp9Hu6j6uj-5_h21FWm_L-KM,1248
72
78
  trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
- trilogy/dialect/base.py,sha256=Y4m4RQdYI3usjeTLJKUM_SIIyuxXZfe2hboG5JSxDLU,42412
74
- trilogy/dialect/bigquery.py,sha256=MyUumO8CeyPLh2JquoKPp6yQSZYEzUQ2mM07LCps-CA,3526
75
- trilogy/dialect/common.py,sha256=EFf2Ye7XcwTti7IsFRwMo_4AW2CF8eaxSk8XA0mA5qw,5400
79
+ trilogy/dialect/base.py,sha256=SwYg3aCLmam70mlkJURYN42IggmbxviFnMUJ72WYE4g,42940
80
+ trilogy/dialect/bigquery.py,sha256=4u4SuQ67_Zwyu0czyQnBMDUVlegqir0SA30iEbZEAwU,3575
81
+ trilogy/dialect/common.py,sha256=IhW0v5zATvZ2K0vr4Ab4TWpYMKKkGangSpIyqaPYEkw,5762
76
82
  trilogy/dialect/config.py,sha256=olnyeVU5W5T6b9-dMeNAnvxuPlyc2uefb7FRME094Ec,3834
77
83
  trilogy/dialect/dataframe.py,sha256=RUbNgReEa9g3pL6H7fP9lPTrAij5pkqedpZ99D8_5AE,1522
78
- trilogy/dialect/duckdb.py,sha256=IQzaRaCv5c6TUDERhbsLM4uTW0aGkO_DrAMR5k_j7TU,3861
84
+ trilogy/dialect/duckdb.py,sha256=C5TovwacDXo9YDpMTpPxkH7D0AxQERa7JL1RUkDGVng,3898
79
85
  trilogy/dialect/enums.py,sha256=FRNYQ5-w-B6-X0yXKNU5g9GowsMlERFogTC5u2nxL_s,4740
80
86
  trilogy/dialect/postgres.py,sha256=VH4EB4myjIeZTHeFU6vK00GxY9c53rCBjg2mLbdaCEE,3254
81
87
  trilogy/dialect/presto.py,sha256=Mw7_F8h19mWfuZHkHQJizQWbpu1lIHe6t2PA0r88gsY,3392
82
- trilogy/dialect/snowflake.py,sha256=vc0374Og0O5OIB7-Z7jbwoJJg0iomjvnUqHlxM8B0rg,3120
88
+ trilogy/dialect/snowflake.py,sha256=LQIcHuyuGZXbxrv6sH17aLXLzw7yFVuRoE9M4doNk5k,3187
83
89
  trilogy/dialect/sql_server.py,sha256=z2Vg7Qvw83rbGiEFIvHHLqVWJTWiz2xs76kpQj4HdTU,3131
84
90
  trilogy/hooks/__init__.py,sha256=T3SF3phuUDPLXKGRVE_Lf9mzuwoXWyaLolncR_1kY30,144
85
91
  trilogy/hooks/base_hook.py,sha256=I_l-NBMNC7hKTDx1JgHZPVOOCvLQ36m2oIGaR5EUMXY,1180
@@ -87,23 +93,24 @@ trilogy/hooks/graph_hook.py,sha256=c-vC-IXoJ_jDmKQjxQyIxyXPOuUcLIURB573gCsAfzQ,2
87
93
  trilogy/hooks/query_debugger.py,sha256=1npRjww94sPV5RRBBlLqMJRaFkH9vhEY6o828MeoEcw,5583
88
94
  trilogy/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
89
95
  trilogy/parsing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
90
- trilogy/parsing/common.py,sha256=g1RmQF4fS_OgkcC6j4hnKIcn_ap0fFa_kzNUlH5D0nA,29760
96
+ trilogy/parsing/common.py,sha256=kjA0-14mgrr1smOjt01h0nk6iatLj9tXXC8cMsir084,29782
91
97
  trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
92
98
  trilogy/parsing/exceptions.py,sha256=Xwwsv2C9kSNv2q-HrrKC1f60JNHShXcCMzstTSEbiCw,154
93
99
  trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
94
- trilogy/parsing/parse_engine.py,sha256=mQzUSWOX2QdUng2ozAkqLDfMLI_NoqPjAiauhe_mHz4,70606
100
+ trilogy/parsing/parse_engine.py,sha256=Fjjh6YpLS1PluEymkNtDe698EIgtzZqqPb0kfDEenQc,71080
95
101
  trilogy/parsing/render.py,sha256=hI4y-xjXrEXvHslY2l2TQ8ic0zAOpN41ADH37J2_FZY,19047
96
- trilogy/parsing/trilogy.lark,sha256=ybs65Ckb89PCitK4hcwy6znqElcWvIeMDQzsI2p_3YI,14197
102
+ trilogy/parsing/trilogy.lark,sha256=se-gnL3UfrdznVvhNbzzcE5VZxZ18iNMbNMFvRjr30I,14304
97
103
  trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
104
  trilogy/scripts/trilogy.py,sha256=1L0XrH4mVHRt1C9T1HnaDv2_kYEfbWTb5_-cBBke79w,3774
99
105
  trilogy/std/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
100
- trilogy/std/date.preql,sha256=0MHeGLp2mG4QBKtmozcBZ7qVjOAdWOtrliIKn6hz1Pc,95
106
+ trilogy/std/date.preql,sha256=Ki4M-dG2xUIT_U16kOBXdaZb62S3P7iDrMBY93I4I3Q,132
101
107
  trilogy/std/display.preql,sha256=2BbhvqR4rcltyAbOXAUo7SZ_yGFYZgFnurglHMbjW2g,40
102
- trilogy/std/geography.preql,sha256=-fqAGnBL6tR-UtT8DbSek3iMFg66ECR_B_41pODxv-k,504
103
- trilogy/std/money.preql,sha256=ZHW-csTX-kYbOLmKSO-TcGGgQ-_DMrUXy0BjfuJSFxM,80
108
+ trilogy/std/geography.preql,sha256=qLnHmDU5EnvjTbfqZF-NEclSYM5_e9rZra7QjV01rZ4,582
109
+ trilogy/std/money.preql,sha256=XWwvAV3WxBsHX9zfptoYRnBigcfYwrYtBHXTME0xJuQ,2082
110
+ trilogy/std/net.preql,sha256=-bMV6dyofskl4Kvows-iQ4JCxjVUwsZOeWCy8JO5Ftw,135
104
111
  trilogy/std/report.preql,sha256=LbV-XlHdfw0jgnQ8pV7acG95xrd1-p65fVpiIc-S7W4,202
105
- pytrilogy-0.0.3.54.dist-info/METADATA,sha256=_Bv_Q8dZSrH750iNkW7KtpUP1vSAwZRnBzsG8KDXdXE,9095
106
- pytrilogy-0.0.3.54.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
107
- pytrilogy-0.0.3.54.dist-info/entry_points.txt,sha256=ewBPU2vLnVexZVnB-NrVj-p3E-4vukg83Zk8A55Wp2w,56
108
- pytrilogy-0.0.3.54.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
109
- pytrilogy-0.0.3.54.dist-info/RECORD,,
112
+ pytrilogy-0.0.3.56.dist-info/METADATA,sha256=f1YsxdSUDeoSLE8O430eEFxgXPs5DZpnmLNhab9f9U4,9095
113
+ pytrilogy-0.0.3.56.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
114
+ pytrilogy-0.0.3.56.dist-info/entry_points.txt,sha256=ewBPU2vLnVexZVnB-NrVj-p3E-4vukg83Zk8A55Wp2w,56
115
+ pytrilogy-0.0.3.56.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
116
+ pytrilogy-0.0.3.56.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.3.54"
7
+ __version__ = "0.0.3.56"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
trilogy/constants.py CHANGED
@@ -7,6 +7,8 @@ logger = getLogger("trilogy")
7
7
 
8
8
  DEFAULT_NAMESPACE = "local"
9
9
 
10
+ RECURSIVE_GATING_CONCEPT = "_terminal"
11
+
10
12
  VIRTUAL_CONCEPT_PREFIX = "_virt"
11
13
 
12
14
  ENV_CACHE_NAME = ".preql_cache.json"
trilogy/core/enums.py CHANGED
@@ -42,6 +42,7 @@ class Purpose(Enum):
42
42
 
43
43
  class Derivation(Enum):
44
44
  BASIC = "basic"
45
+ GROUP_TO = "group_to"
45
46
  WINDOW = "window"
46
47
  AGGREGATE = "aggregate"
47
48
  FILTER = "filter"
@@ -51,6 +52,7 @@ class Derivation(Enum):
51
52
  ROOT = "root"
52
53
  ROWSET = "rowset"
53
54
  MULTISELECT = "multiselect"
55
+ RECURSIVE = "recursive"
54
56
 
55
57
 
56
58
  class Granularity(Enum):
@@ -117,6 +119,7 @@ class FunctionType(Enum):
117
119
 
118
120
  # structural
119
121
  UNNEST = "unnest"
122
+ RECURSE_EDGE = "recurse_edge"
120
123
 
121
124
  UNION = "union"
122
125
 
@@ -233,6 +236,8 @@ class FunctionClass(Enum):
233
236
 
234
237
  ONE_TO_MANY = [FunctionType.UNNEST]
235
238
 
239
+ RECURSIVE = [FunctionType.RECURSE_EDGE]
240
+
236
241
 
237
242
  class Boolean(Enum):
238
243
  TRUE = "true"
@@ -333,6 +338,7 @@ class SourceType(Enum):
333
338
  MERGE = "merge"
334
339
  BASIC = "basic"
335
340
  UNION = "union"
341
+ RECURSIVE = "recursive"
336
342
 
337
343
 
338
344
  class ShowCategory(Enum):
trilogy/core/functions.py CHANGED
@@ -190,6 +190,9 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
190
190
  output_type_function=get_unnest_output_type,
191
191
  arg_count=1,
192
192
  ),
193
+ FunctionType.RECURSE_EDGE: FunctionConfig(
194
+ arg_count=2,
195
+ ),
193
196
  FunctionType.GROUP: FunctionConfig(
194
197
  arg_count=-1,
195
198
  output_type_function=lambda args: get_output_type_at_index(args, 0),
@@ -1164,12 +1164,24 @@ class Concept(Addressable, DataTyped, ConceptArgs, Mergeable, Namespaced, BaseMo
1164
1164
  and lineage.operator == FunctionType.UNNEST
1165
1165
  ):
1166
1166
  return Derivation.UNNEST
1167
+ elif (
1168
+ lineage
1169
+ and isinstance(lineage, (BuildFunction, Function))
1170
+ and lineage.operator == FunctionType.RECURSE_EDGE
1171
+ ):
1172
+ return Derivation.RECURSIVE
1167
1173
  elif (
1168
1174
  lineage
1169
1175
  and isinstance(lineage, (BuildFunction, Function))
1170
1176
  and lineage.operator == FunctionType.UNION
1171
1177
  ):
1172
1178
  return Derivation.UNION
1179
+ elif (
1180
+ lineage
1181
+ and isinstance(lineage, (BuildFunction, Function))
1182
+ and lineage.operator == FunctionType.GROUP
1183
+ ):
1184
+ return Derivation.GROUP_TO
1173
1185
  elif (
1174
1186
  lineage
1175
1187
  and isinstance(lineage, (BuildFunction, Function))
@@ -1189,10 +1201,6 @@ class Concept(Addressable, DataTyped, ConceptArgs, Mergeable, Namespaced, BaseMo
1189
1201
  return Derivation.CONSTANT
1190
1202
  return Derivation.ROOT
1191
1203
 
1192
- # @property
1193
- # def derivation(self) -> Derivation:
1194
- # return self.calculate_derivation(self.lineage, self.purpose)
1195
-
1196
1204
  @classmethod
1197
1205
  def calculate_granularity(cls, derivation: Derivation, grain: Grain, lineage):
1198
1206
  from trilogy.core.models.build import BuildFunction
@@ -12,9 +12,16 @@ from pydantic import (
12
12
  model_validator,
13
13
  )
14
14
 
15
- from trilogy.constants import CONFIG, logger
15
+ from trilogy.constants import (
16
+ CONFIG,
17
+ DEFAULT_NAMESPACE,
18
+ RECURSIVE_GATING_CONCEPT,
19
+ MagicConstants,
20
+ logger,
21
+ )
16
22
  from trilogy.core.constants import CONSTANT_DATASET
17
23
  from trilogy.core.enums import (
24
+ ComparisonOperator,
18
25
  Derivation,
19
26
  FunctionType,
20
27
  Granularity,
@@ -24,16 +31,20 @@ from trilogy.core.enums import (
24
31
  SourceType,
25
32
  )
26
33
  from trilogy.core.models.build import (
34
+ BuildCaseElse,
35
+ BuildCaseWhen,
27
36
  BuildComparison,
28
37
  BuildConcept,
29
38
  BuildConditional,
30
39
  BuildDatasource,
40
+ BuildExpr,
31
41
  BuildFunction,
32
42
  BuildGrain,
33
43
  BuildOrderBy,
34
44
  BuildParamaterizedConceptReference,
35
45
  BuildParenthetical,
36
46
  BuildRowsetItem,
47
+ DataType,
37
48
  LooseBuildConceptList,
38
49
  )
39
50
  from trilogy.core.models.datasource import Address
@@ -841,6 +852,195 @@ class QueryDatasource(BaseModel):
841
852
  return self.identifier
842
853
 
843
854
 
855
+ class AliasedExpression(BaseModel):
856
+ expr: BuildExpr
857
+ alias: str
858
+
859
+
860
+ class RecursiveCTE(CTE):
861
+
862
+ def generate_loop_functions(
863
+ self,
864
+ recursive_derived: BuildConcept,
865
+ left_recurse_concept: BuildConcept,
866
+ right_recurse_concept: BuildConcept,
867
+ ) -> tuple[BuildConcept, BuildConcept, BuildConcept]:
868
+
869
+ join_gate = BuildConcept(
870
+ name=RECURSIVE_GATING_CONCEPT,
871
+ namespace=DEFAULT_NAMESPACE,
872
+ grain=recursive_derived.grain,
873
+ build_is_aggregate=False,
874
+ datatype=DataType.BOOL,
875
+ purpose=Purpose.KEY,
876
+ derivation=Derivation.BASIC,
877
+ lineage=BuildFunction(
878
+ operator=FunctionType.CASE,
879
+ arguments=[
880
+ BuildCaseWhen(
881
+ comparison=BuildComparison(
882
+ left=right_recurse_concept,
883
+ right=MagicConstants.NULL,
884
+ operator=ComparisonOperator.IS,
885
+ ),
886
+ expr=True,
887
+ ),
888
+ BuildCaseElse(expr=False),
889
+ ],
890
+ output_datatype=DataType.BOOL,
891
+ output_purpose=Purpose.KEY,
892
+ ),
893
+ )
894
+ bottom_join_gate = BuildConcept(
895
+ name=f"{RECURSIVE_GATING_CONCEPT}_two",
896
+ namespace=DEFAULT_NAMESPACE,
897
+ grain=recursive_derived.grain,
898
+ build_is_aggregate=False,
899
+ datatype=DataType.BOOL,
900
+ purpose=Purpose.KEY,
901
+ derivation=Derivation.BASIC,
902
+ lineage=BuildFunction(
903
+ operator=FunctionType.CASE,
904
+ arguments=[
905
+ BuildCaseWhen(
906
+ comparison=BuildComparison(
907
+ left=right_recurse_concept,
908
+ right=MagicConstants.NULL,
909
+ operator=ComparisonOperator.IS,
910
+ ),
911
+ expr=True,
912
+ ),
913
+ BuildCaseElse(expr=False),
914
+ ],
915
+ output_datatype=DataType.BOOL,
916
+ output_purpose=Purpose.KEY,
917
+ ),
918
+ )
919
+ bottom_derivation = BuildConcept(
920
+ name=recursive_derived.name + "_bottom",
921
+ namespace=recursive_derived.namespace,
922
+ grain=recursive_derived.grain,
923
+ build_is_aggregate=False,
924
+ datatype=recursive_derived.datatype,
925
+ purpose=recursive_derived.purpose,
926
+ derivation=Derivation.RECURSIVE,
927
+ lineage=BuildFunction(
928
+ operator=FunctionType.CASE,
929
+ arguments=[
930
+ BuildCaseWhen(
931
+ comparison=BuildComparison(
932
+ left=right_recurse_concept,
933
+ right=MagicConstants.NULL,
934
+ operator=ComparisonOperator.IS,
935
+ ),
936
+ expr=recursive_derived,
937
+ ),
938
+ BuildCaseElse(expr=right_recurse_concept),
939
+ ],
940
+ output_datatype=recursive_derived.datatype,
941
+ output_purpose=recursive_derived.purpose,
942
+ ),
943
+ )
944
+ return bottom_derivation, join_gate, bottom_join_gate
945
+
946
+ @property
947
+ def internal_ctes(self) -> List[CTE]:
948
+ filtered_output = [
949
+ x for x in self.output_columns if x.name != RECURSIVE_GATING_CONCEPT
950
+ ]
951
+ recursive_derived = [
952
+ x for x in self.output_columns if x.derivation == Derivation.RECURSIVE
953
+ ][0]
954
+ if not isinstance(recursive_derived.lineage, BuildFunction):
955
+ raise SyntaxError(
956
+ "Recursive CTEs must have a function lineage, found"
957
+ f" {recursive_derived.lineage}"
958
+ )
959
+ left_recurse_concept = recursive_derived.lineage.concept_arguments[0]
960
+ right_recurse_concept = recursive_derived.lineage.concept_arguments[1]
961
+ parent_ctes: List[CTE | UnionCTE]
962
+ if self.parent_ctes:
963
+ base = self.parent_ctes[0]
964
+ loop_input_cte = base
965
+ parent_ctes = [base]
966
+ parent_identifier = base.identifier
967
+ else:
968
+ raise SyntaxError("Recursive CTEs must have a parent CTE currently")
969
+ bottom_derivation, join_gate, bottom_join_gate = self.generate_loop_functions(
970
+ recursive_derived, left_recurse_concept, right_recurse_concept
971
+ )
972
+ base_output = [*filtered_output, join_gate]
973
+ bottom_output = []
974
+ for x in filtered_output:
975
+ if x.address == recursive_derived.address:
976
+ bottom_output.append(bottom_derivation)
977
+ else:
978
+ bottom_output.append(x)
979
+
980
+ bottom_output = [*bottom_output, bottom_join_gate]
981
+ top = CTE(
982
+ name=self.name,
983
+ source=self.source,
984
+ output_columns=base_output,
985
+ source_map=self.source_map,
986
+ grain=self.grain,
987
+ existence_source_map=self.existence_source_map,
988
+ parent_ctes=self.parent_ctes,
989
+ joins=self.joins,
990
+ condition=self.condition,
991
+ partial_concepts=self.partial_concepts,
992
+ hidden_concepts=self.hidden_concepts,
993
+ nullable_concepts=self.nullable_concepts,
994
+ join_derived_concepts=self.join_derived_concepts,
995
+ group_to_grain=self.group_to_grain,
996
+ order_by=self.order_by,
997
+ limit=self.limit,
998
+ )
999
+ top_cte_array: list[CTE | UnionCTE] = [top]
1000
+ bottom_source_map = {
1001
+ left_recurse_concept.address: [top.identifier],
1002
+ right_recurse_concept.address: [parent_identifier],
1003
+ # recursive_derived.address: self.source_map[recursive_derived.address],
1004
+ join_gate.address: [top.identifier],
1005
+ recursive_derived.address: [top.identifier],
1006
+ }
1007
+ bottom = CTE(
1008
+ name=self.name,
1009
+ source=self.source,
1010
+ output_columns=bottom_output,
1011
+ source_map=bottom_source_map,
1012
+ grain=self.grain,
1013
+ existence_source_map=self.existence_source_map,
1014
+ parent_ctes=top_cte_array + parent_ctes,
1015
+ joins=[
1016
+ Join(
1017
+ right_cte=loop_input_cte,
1018
+ jointype=JoinType.INNER,
1019
+ joinkey_pairs=[
1020
+ CTEConceptPair(
1021
+ left=recursive_derived,
1022
+ right=left_recurse_concept,
1023
+ existing_datasource=loop_input_cte.source,
1024
+ modifiers=[],
1025
+ cte=top,
1026
+ )
1027
+ ],
1028
+ condition=BuildComparison(
1029
+ left=join_gate, right=True, operator=ComparisonOperator.IS_NOT
1030
+ ),
1031
+ )
1032
+ ],
1033
+ partial_concepts=self.partial_concepts,
1034
+ hidden_concepts=self.hidden_concepts,
1035
+ nullable_concepts=self.nullable_concepts,
1036
+ join_derived_concepts=self.join_derived_concepts,
1037
+ group_to_grain=self.group_to_grain,
1038
+ order_by=self.order_by,
1039
+ limit=self.limit,
1040
+ )
1041
+ return [top, bottom]
1042
+
1043
+
844
1044
  class UnionCTE(BaseModel):
845
1045
  name: str
846
1046
  source: QueryDatasource
@@ -891,6 +1091,10 @@ class UnionCTE(BaseModel):
891
1091
  def condition(self, value):
892
1092
  raise NotImplementedError
893
1093
 
1094
+ @property
1095
+ def identifier(self) -> str:
1096
+ return self.name
1097
+
894
1098
  @property
895
1099
  def safe_identifier(self):
896
1100
  return self.name
@@ -906,12 +1110,13 @@ class UnionCTE(BaseModel):
906
1110
 
907
1111
 
908
1112
  class Join(BaseModel):
909
- right_cte: CTE
1113
+ right_cte: CTE | UnionCTE
910
1114
  jointype: JoinType
911
1115
  left_cte: CTE | None = None
912
1116
  joinkey_pairs: List[CTEConceptPair] | None = None
913
1117
  inlined_ctes: set[str] = Field(default_factory=set)
914
1118
  quote: str | None = None
1119
+ condition: BuildConditional | BuildComparison | BuildParenthetical | None = None
915
1120
 
916
1121
  def inline_cte(self, cte: CTE):
917
1122
  self.inlined_ctes.add(cte.name)
@@ -3,7 +3,7 @@ from trilogy.core.enums import BooleanOperator, Derivation
3
3
  from trilogy.core.models.build import (
4
4
  BuildConditional,
5
5
  )
6
- from trilogy.core.models.execute import CTE, UnionCTE
6
+ from trilogy.core.models.execute import CTE, RecursiveCTE, UnionCTE
7
7
  from trilogy.core.optimizations import (
8
8
  InlineDatasource,
9
9
  OptimizationRule,
@@ -123,7 +123,7 @@ def gen_inverse_map(input: list[CTE | UnionCTE]) -> dict[str, list[CTE | UnionCT
123
123
  SENSITIVE_DERIVATIONS = [
124
124
  Derivation.UNNEST,
125
125
  Derivation.WINDOW,
126
- # Derivation.AGGREGATE,
126
+ Derivation.RECURSIVE,
127
127
  ]
128
128
 
129
129
 
@@ -133,7 +133,7 @@ def is_direct_return_eligible(cte: CTE | UnionCTE) -> CTE | UnionCTE | None:
133
133
  if len(cte.parent_ctes) != 1:
134
134
  return None
135
135
  direct_parent = cte.parent_ctes[0]
136
- if isinstance(direct_parent, UnionCTE):
136
+ if isinstance(direct_parent, (UnionCTE, RecursiveCTE)):
137
137
  return None
138
138
 
139
139
  output_addresses = set([x.address for x in cte.output_columns])
@@ -1,13 +1,8 @@
1
1
  from collections import defaultdict
2
2
 
3
3
  from trilogy.constants import CONFIG
4
-
5
- # from trilogy.core.models.datasource import Datasource
6
4
  from trilogy.core.models.build import BuildDatasource
7
- from trilogy.core.models.execute import (
8
- CTE,
9
- UnionCTE,
10
- )
5
+ from trilogy.core.models.execute import CTE, RecursiveCTE, UnionCTE
11
6
  from trilogy.core.optimizations.base_optimization import OptimizationRule
12
7
 
13
8
 
@@ -24,7 +19,8 @@ class InlineDatasource(OptimizationRule):
24
19
  return any(
25
20
  self.optimize(x, inverse_map=inverse_map) for x in cte.internal_ctes
26
21
  )
27
-
22
+ if isinstance(cte, RecursiveCTE):
23
+ return False
28
24
  if not cte.parent_ctes:
29
25
  return False
30
26
 
@@ -36,6 +32,8 @@ class InlineDatasource(OptimizationRule):
36
32
  for parent_cte in cte.parent_ctes:
37
33
  if isinstance(parent_cte, UnionCTE):
38
34
  continue
35
+ if isinstance(parent_cte, RecursiveCTE):
36
+ continue
39
37
  if not parent_cte.is_root_datasource:
40
38
  self.debug(f"Cannot inline: parent {parent_cte.name} is not root")
41
39
  continue