pytrilogy 0.0.3.57__py3-none-any.whl → 0.0.3.61__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.3.57.dist-info → pytrilogy-0.0.3.61.dist-info}/METADATA +1 -1
- {pytrilogy-0.0.3.57.dist-info → pytrilogy-0.0.3.61.dist-info}/RECORD +28 -27
- trilogy/__init__.py +1 -1
- trilogy/core/constants.py +1 -0
- trilogy/core/enums.py +2 -0
- trilogy/core/models/build.py +1 -1
- trilogy/core/models/core.py +5 -1
- trilogy/core/models/environment.py +3 -1
- trilogy/core/optimization.py +1 -1
- trilogy/core/processing/discovery_node_factory.py +1 -1
- trilogy/core/processing/node_generators/basic_node.py +12 -1
- trilogy/core/processing/node_generators/node_merge_node.py +15 -7
- trilogy/core/processing/node_generators/synonym_node.py +0 -1
- trilogy/core/processing/node_generators/unnest_node.py +1 -1
- trilogy/dialect/base.py +20 -0
- trilogy/dialect/bigquery.py +2 -2
- trilogy/dialect/common.py +12 -4
- trilogy/dialect/presto.py +8 -2
- trilogy/parsing/common.py +7 -2
- trilogy/parsing/parse_engine.py +34 -6
- trilogy/parsing/render.py +12 -0
- trilogy/parsing/trilogy.lark +2 -2
- trilogy/std/date.preql +4 -1
- trilogy/std/ranking.preql +6 -0
- {pytrilogy-0.0.3.57.dist-info → pytrilogy-0.0.3.61.dist-info}/WHEEL +0 -0
- {pytrilogy-0.0.3.57.dist-info → pytrilogy-0.0.3.61.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.3.57.dist-info → pytrilogy-0.0.3.61.dist-info}/licenses/LICENSE.md +0 -0
- {pytrilogy-0.0.3.57.dist-info → pytrilogy-0.0.3.61.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
pytrilogy-0.0.3.
|
|
2
|
-
trilogy/__init__.py,sha256=
|
|
1
|
+
pytrilogy-0.0.3.61.dist-info/licenses/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
|
|
2
|
+
trilogy/__init__.py,sha256=6pE1HEb6lBSW2ODExpQU2E4nDuvhlPqat8goqgVFph4,303
|
|
3
3
|
trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
trilogy/constants.py,sha256=lv_aJWP6dn6e2aF4BAE72jbnNtceFddfqtiDSsvzno0,1692
|
|
5
5
|
trilogy/engine.py,sha256=OK2RuqCIUId6yZ5hfF8J1nxGP0AJqHRZiafcowmW0xc,1728
|
|
@@ -10,8 +10,8 @@ trilogy/render.py,sha256=qQWwduymauOlB517UtM-VGbVe8Cswa4UJub5aGbSO6c,1512
|
|
|
10
10
|
trilogy/utility.py,sha256=euQccZLKoYBz0LNg5tzLlvv2YHvXh9HArnYp1V3uXsM,763
|
|
11
11
|
trilogy/authoring/__init__.py,sha256=h-Ag7vT76tsjib9BfjOgI-yVpuJDgpn2TSps-ibRAj8,2593
|
|
12
12
|
trilogy/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
trilogy/core/constants.py,sha256=
|
|
14
|
-
trilogy/core/enums.py,sha256=
|
|
13
|
+
trilogy/core/constants.py,sha256=nizWYDCJQ1bigQMtkNIEMNTcN0NoEAXiIHLzpelxQ24,201
|
|
14
|
+
trilogy/core/enums.py,sha256=2sgoVzHQpscIx_WUqJMH0oGxtcg41gN0l1qkRjzK2iI,7803
|
|
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
|
|
@@ -19,16 +19,16 @@ trilogy/core/exceptions.py,sha256=JPYyBcit3T_pRtlHdtKSeVJkIyWUTozW2aaut25A2xI,67
|
|
|
19
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=
|
|
22
|
+
trilogy/core/optimization.py,sha256=ojpn-p79lr03SSVQbbw74iPCyoYpDYBmj1dbZ3oXCjI,8860
|
|
23
23
|
trilogy/core/query_processor.py,sha256=QiE_w5HgheT4GLZFnaLssJ4plf4voK0TeTd6N3jhR6A,20188
|
|
24
24
|
trilogy/core/utility.py,sha256=3VC13uSQWcZNghgt7Ot0ZTeEmNqs__cx122abVq9qhM,410
|
|
25
25
|
trilogy/core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
26
|
trilogy/core/models/author.py,sha256=8XbIsQr6cQrgo9uzee5qRoYiMdEG7yKF4FiiWImW7U0,77490
|
|
27
|
-
trilogy/core/models/build.py,sha256=
|
|
27
|
+
trilogy/core/models/build.py,sha256=VAJpmk3GQCeJHpgjbFYHDXnFZlSD89sb0RvtIsZ58JE,63129
|
|
28
28
|
trilogy/core/models/build_environment.py,sha256=s_C9xAHuD3yZ26T15pWVBvoqvlp2LdZ8yjsv2_HdXLk,5363
|
|
29
|
-
trilogy/core/models/core.py,sha256=
|
|
29
|
+
trilogy/core/models/core.py,sha256=EMAuWTngoNVGCdfNrAY7_k6g528iodNQLwPRVip-8DA,10980
|
|
30
30
|
trilogy/core/models/datasource.py,sha256=6RjJUd2u4nYmEwFBpJlM9LbHVYDv8iHJxqiBMZqUrwI,9422
|
|
31
|
-
trilogy/core/models/environment.py,sha256=
|
|
31
|
+
trilogy/core/models/environment.py,sha256=tM8SwH9r1ZSc-F0Enod7r1NuqzGpQfLcPxnrtK5Hqpk,27398
|
|
32
32
|
trilogy/core/models/execute.py,sha256=hOilC-lka4W-C8Pakb0Vd1-T0oskeWdC8Ls0bm8_388,43109
|
|
33
33
|
trilogy/core/optimizations/__init__.py,sha256=YH2-mGXZnVDnBcWVi8vTbrdw7Qs5TivG4h38rH3js_I,290
|
|
34
34
|
trilogy/core/optimizations/base_optimization.py,sha256=gzDOKImoFn36k7XBD3ysEYDnbnb6vdVIztUfFQZsGnM,513
|
|
@@ -37,26 +37,26 @@ trilogy/core/optimizations/predicate_pushdown.py,sha256=g4AYE8Aw_iMlAh68TjNXGP75
|
|
|
37
37
|
trilogy/core/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
38
|
trilogy/core/processing/concept_strategies_v3.py,sha256=KHpSQyG5Ubb5H1dmzpDWI2ypJL_rxeS3zc3sjaeCq_s,21997
|
|
39
39
|
trilogy/core/processing/discovery_loop.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
|
-
trilogy/core/processing/discovery_node_factory.py,sha256=
|
|
40
|
+
trilogy/core/processing/discovery_node_factory.py,sha256=LFGHUznUz_kszcs8QywZ0pNaejbRoNVHv81gX6Mqm2Y,14909
|
|
41
41
|
trilogy/core/processing/discovery_utility.py,sha256=hF3aUbRHHZFeFT5aBjE6TuSeU60I90gzmj512QXG_t8,4856
|
|
42
42
|
trilogy/core/processing/discovery_validation.py,sha256=Ek9jviFgimLMUMYLXBChUQmOD94ihhwQ3NDVe6RTdWg,4930
|
|
43
43
|
trilogy/core/processing/graph_utils.py,sha256=8QUVrkE9j-9C1AyrCb1nQEh8daCe0u1HuXl-Te85lag,1205
|
|
44
44
|
trilogy/core/processing/utility.py,sha256=mrfR9pgek-xjxoDQSlvPqOW9dpmREjgzqn4AGoqpGeM,22774
|
|
45
45
|
trilogy/core/processing/node_generators/__init__.py,sha256=w8TQQgNhyAra6JQHdg1_Ags4BGyxjXYruu6UeC5yOkI,873
|
|
46
|
-
trilogy/core/processing/node_generators/basic_node.py,sha256=
|
|
46
|
+
trilogy/core/processing/node_generators/basic_node.py,sha256=8NtHZ99mJhJwDIib3xlcrn7oWmE42HHKuBpnwXIzpyo,4861
|
|
47
47
|
trilogy/core/processing/node_generators/common.py,sha256=PdysdroW9DUADP7f5Wv_GKPUyCTROZV1g3L45fawxi8,9443
|
|
48
48
|
trilogy/core/processing/node_generators/filter_node.py,sha256=0hdfiS2I-Jvr6P-il3jnAJK-g-DMG7_cFbZGCnLnJAo,10032
|
|
49
49
|
trilogy/core/processing/node_generators/group_node.py,sha256=nIfiMrJQEksUfqAeeA3X5PS1343y4lmPTipYuCa-rvs,6141
|
|
50
50
|
trilogy/core/processing/node_generators/group_to_node.py,sha256=jKcNCDOY6fNblrdZwaRU0sbUSr9H0moQbAxrGgX6iGA,3832
|
|
51
51
|
trilogy/core/processing/node_generators/multiselect_node.py,sha256=GWV5yLmKTe1yyPhN60RG1Rnrn4ktfn9lYYXi_FVU4UI,7061
|
|
52
|
-
trilogy/core/processing/node_generators/node_merge_node.py,sha256=
|
|
52
|
+
trilogy/core/processing/node_generators/node_merge_node.py,sha256=1vUmNE0qQQ1MYAvC6TO2dNsudIUytj9ZVcW4w1IGHXY,16734
|
|
53
53
|
trilogy/core/processing/node_generators/recursive_node.py,sha256=l5zdh0dURKwmAy8kK4OpMtZfyUEQRk6N-PwSWIyBpSM,2468
|
|
54
54
|
trilogy/core/processing/node_generators/rowset_node.py,sha256=2BiSsegbRF9csJ_Xl8P_CxIm4dAAb7dF29u6v_Odr-A,6709
|
|
55
55
|
trilogy/core/processing/node_generators/select_merge_node.py,sha256=lxXhMhDKGbu67QFNbbAT-BO8gbWppIvjn_hAXpLEPe0,19953
|
|
56
56
|
trilogy/core/processing/node_generators/select_node.py,sha256=3dvw0d53eUtCRCUPN6J48I3qBEX1Wha7saQ_ndPu6_I,1777
|
|
57
|
-
trilogy/core/processing/node_generators/synonym_node.py,sha256=
|
|
57
|
+
trilogy/core/processing/node_generators/synonym_node.py,sha256=BNfdwTunCerIzm7YLISI_XcfxxUzWLrZrRvZvayScSk,2257
|
|
58
58
|
trilogy/core/processing/node_generators/union_node.py,sha256=VNo6Oey4p8etU9xrOh2oTT2lIOTvY6PULUPRvVa2uxU,2877
|
|
59
|
-
trilogy/core/processing/node_generators/unnest_node.py,sha256=
|
|
59
|
+
trilogy/core/processing/node_generators/unnest_node.py,sha256=ueOQtoTf2iJHO09RzWHDFQ5iKZq2fVhGf2KAF2U2kU8,2677
|
|
60
60
|
trilogy/core/processing/node_generators/window_node.py,sha256=GP3Hvkbb0TDA6ef7W7bmvQEHVH-NRIfBT_0W4fcH3g4,6529
|
|
61
61
|
trilogy/core/processing/node_generators/select_helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
62
62
|
trilogy/core/processing/node_generators/select_helpers/datasource_injection.py,sha256=GMW07bb6hXurhF0hZLYoMAKSIS65tat5hwBjvqqPeSA,6516
|
|
@@ -76,15 +76,15 @@ trilogy/core/statements/build.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
|
|
|
76
76
|
trilogy/core/statements/common.py,sha256=KxEmz2ySySyZ6CTPzn0fJl5NX2KOk1RPyuUSwWhnK1g,759
|
|
77
77
|
trilogy/core/statements/execute.py,sha256=rqfuoMuXPcH7L7TmE1dSiZ_K_A1ohB8whVMfGimZBOk,1294
|
|
78
78
|
trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
79
|
-
trilogy/dialect/base.py,sha256=
|
|
80
|
-
trilogy/dialect/bigquery.py,sha256=
|
|
81
|
-
trilogy/dialect/common.py,sha256=
|
|
79
|
+
trilogy/dialect/base.py,sha256=CVOkIm3pwcuWlPGRqiimXjoKfns-2dAYlGsMCHGuzY4,43036
|
|
80
|
+
trilogy/dialect/bigquery.py,sha256=6ghCqy-k7UioIJc1EEQ7gRo_PHaO8Vm7yYbiQ-kgpzs,3629
|
|
81
|
+
trilogy/dialect/common.py,sha256=hhzuMTFW9QQIP7TKLT9BlJy6lw2R03a68jKQ-7t4-2c,6070
|
|
82
82
|
trilogy/dialect/config.py,sha256=olnyeVU5W5T6b9-dMeNAnvxuPlyc2uefb7FRME094Ec,3834
|
|
83
83
|
trilogy/dialect/dataframe.py,sha256=RUbNgReEa9g3pL6H7fP9lPTrAij5pkqedpZ99D8_5AE,1522
|
|
84
84
|
trilogy/dialect/duckdb.py,sha256=C5TovwacDXo9YDpMTpPxkH7D0AxQERa7JL1RUkDGVng,3898
|
|
85
85
|
trilogy/dialect/enums.py,sha256=FRNYQ5-w-B6-X0yXKNU5g9GowsMlERFogTC5u2nxL_s,4740
|
|
86
86
|
trilogy/dialect/postgres.py,sha256=VH4EB4myjIeZTHeFU6vK00GxY9c53rCBjg2mLbdaCEE,3254
|
|
87
|
-
trilogy/dialect/presto.py,sha256=
|
|
87
|
+
trilogy/dialect/presto.py,sha256=Wd0yHq3EOSfCOy7lWPfCr13JHO3olsm8qUXgml-oTm0,3529
|
|
88
88
|
trilogy/dialect/snowflake.py,sha256=LQIcHuyuGZXbxrv6sH17aLXLzw7yFVuRoE9M4doNk5k,3187
|
|
89
89
|
trilogy/dialect/sql_server.py,sha256=z2Vg7Qvw83rbGiEFIvHHLqVWJTWiz2xs76kpQj4HdTU,3131
|
|
90
90
|
trilogy/hooks/__init__.py,sha256=T3SF3phuUDPLXKGRVE_Lf9mzuwoXWyaLolncR_1kY30,144
|
|
@@ -93,24 +93,25 @@ trilogy/hooks/graph_hook.py,sha256=c-vC-IXoJ_jDmKQjxQyIxyXPOuUcLIURB573gCsAfzQ,2
|
|
|
93
93
|
trilogy/hooks/query_debugger.py,sha256=1npRjww94sPV5RRBBlLqMJRaFkH9vhEY6o828MeoEcw,5583
|
|
94
94
|
trilogy/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
95
95
|
trilogy/parsing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
96
|
-
trilogy/parsing/common.py,sha256=
|
|
96
|
+
trilogy/parsing/common.py,sha256=OOAssbo6Yp3L4u2OSGUYIuC_iAG_843vLpUtLkk1ub8,29960
|
|
97
97
|
trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
|
|
98
98
|
trilogy/parsing/exceptions.py,sha256=Xwwsv2C9kSNv2q-HrrKC1f60JNHShXcCMzstTSEbiCw,154
|
|
99
99
|
trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
100
|
-
trilogy/parsing/parse_engine.py,sha256=
|
|
101
|
-
trilogy/parsing/render.py,sha256=
|
|
102
|
-
trilogy/parsing/trilogy.lark,sha256=
|
|
100
|
+
trilogy/parsing/parse_engine.py,sha256=O7aM5nZ4SjKlqO2x8XWefI1BMCW06jYYLhABU4k1HCI,72430
|
|
101
|
+
trilogy/parsing/render.py,sha256=xUhG0gw4atYFO79kKL_U5UkHMma-oorN5vjPJ5zTBdU,19383
|
|
102
|
+
trilogy/parsing/trilogy.lark,sha256=x9D1BXtE1E9Kxatx5Kt7xCaid8zgedabwca_B7j7L7o,14331
|
|
103
103
|
trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
104
104
|
trilogy/scripts/trilogy.py,sha256=1L0XrH4mVHRt1C9T1HnaDv2_kYEfbWTb5_-cBBke79w,3774
|
|
105
105
|
trilogy/std/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
106
|
-
trilogy/std/date.preql,sha256=
|
|
106
|
+
trilogy/std/date.preql,sha256=HWZm4t4HWyxr5geWRsY05RnHBVDMci8z8YA2cu0-OOw,188
|
|
107
107
|
trilogy/std/display.preql,sha256=2BbhvqR4rcltyAbOXAUo7SZ_yGFYZgFnurglHMbjW2g,40
|
|
108
108
|
trilogy/std/geography.preql,sha256=qLnHmDU5EnvjTbfqZF-NEclSYM5_e9rZra7QjV01rZ4,582
|
|
109
109
|
trilogy/std/money.preql,sha256=XWwvAV3WxBsHX9zfptoYRnBigcfYwrYtBHXTME0xJuQ,2082
|
|
110
110
|
trilogy/std/net.preql,sha256=-bMV6dyofskl4Kvows-iQ4JCxjVUwsZOeWCy8JO5Ftw,135
|
|
111
|
+
trilogy/std/ranking.preql,sha256=LDoZrYyz4g3xsII9XwXfmstZD-_92i1Eox1UqkBIfi8,83
|
|
111
112
|
trilogy/std/report.preql,sha256=LbV-XlHdfw0jgnQ8pV7acG95xrd1-p65fVpiIc-S7W4,202
|
|
112
|
-
pytrilogy-0.0.3.
|
|
113
|
-
pytrilogy-0.0.3.
|
|
114
|
-
pytrilogy-0.0.3.
|
|
115
|
-
pytrilogy-0.0.3.
|
|
116
|
-
pytrilogy-0.0.3.
|
|
113
|
+
pytrilogy-0.0.3.61.dist-info/METADATA,sha256=rXq2NHO2bCO_JhPw5mu8Xj2lEOHcnX73fENl0m7-P2s,9095
|
|
114
|
+
pytrilogy-0.0.3.61.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
115
|
+
pytrilogy-0.0.3.61.dist-info/entry_points.txt,sha256=ewBPU2vLnVexZVnB-NrVj-p3E-4vukg83Zk8A55Wp2w,56
|
|
116
|
+
pytrilogy-0.0.3.61.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
|
|
117
|
+
pytrilogy-0.0.3.61.dist-info/RECORD,,
|
trilogy/__init__.py
CHANGED
trilogy/core/constants.py
CHANGED
trilogy/core/enums.py
CHANGED
trilogy/core/models/build.py
CHANGED
|
@@ -131,7 +131,7 @@ def concept_is_relevant(
|
|
|
131
131
|
if (
|
|
132
132
|
concept.purpose == Purpose.KEY
|
|
133
133
|
and concept.keys
|
|
134
|
-
and all([c in others for c in concept.keys])
|
|
134
|
+
and all([c in others and c != concept.address for c in concept.keys])
|
|
135
135
|
):
|
|
136
136
|
return False
|
|
137
137
|
if concept.purpose in (Purpose.METRIC,):
|
trilogy/core/models/core.py
CHANGED
|
@@ -175,13 +175,17 @@ class ListType(BaseModel):
|
|
|
175
175
|
|
|
176
176
|
|
|
177
177
|
class MapType(BaseModel):
|
|
178
|
-
key_type:
|
|
178
|
+
key_type: TYPEDEF_TYPES
|
|
179
179
|
value_type: TYPEDEF_TYPES
|
|
180
180
|
|
|
181
181
|
@field_validator("value_type", mode="plain")
|
|
182
182
|
def validate_type(cls, v):
|
|
183
183
|
return v
|
|
184
184
|
|
|
185
|
+
@field_validator("key_type", mode="plain")
|
|
186
|
+
def validate_key_type(cls, v):
|
|
187
|
+
return v
|
|
188
|
+
|
|
185
189
|
@property
|
|
186
190
|
def data_type(self):
|
|
187
191
|
return DataType.MAP
|
|
@@ -58,7 +58,9 @@ if TYPE_CHECKING:
|
|
|
58
58
|
class Import:
|
|
59
59
|
alias: str
|
|
60
60
|
path: Path
|
|
61
|
-
input_path:
|
|
61
|
+
input_path: Path | None = (
|
|
62
|
+
None # filepath where the text came from (path is the import path, but may be resolved from a dictionary for some resolvers)
|
|
63
|
+
)
|
|
62
64
|
|
|
63
65
|
|
|
64
66
|
class BaseImportResolver(BaseModel):
|
trilogy/core/optimization.py
CHANGED
|
@@ -373,7 +373,7 @@ class RootNodeHandler:
|
|
|
373
373
|
) -> Optional[StrategyNode]:
|
|
374
374
|
logger.info(
|
|
375
375
|
f"{depth_to_prefix(self.ctx.depth)}{LOGGER_PREFIX} "
|
|
376
|
-
f"Could not resolve root concepts, checking for synonyms"
|
|
376
|
+
f"Could not resolve root concepts, checking for synonyms for {root_targets}"
|
|
377
377
|
)
|
|
378
378
|
|
|
379
379
|
if not self.ctx.history.check_started(
|
|
@@ -21,6 +21,8 @@ def is_equivalent_basic_function_lineage(
|
|
|
21
21
|
y.lineage, BuildFunction
|
|
22
22
|
):
|
|
23
23
|
return False
|
|
24
|
+
if x.lineage.operator == y.lineage.operator == FunctionType.ATTR_ACCESS:
|
|
25
|
+
return x.lineage.concept_arguments == y.lineage.concept_arguments
|
|
24
26
|
if x.lineage.operator == y.lineage.operator:
|
|
25
27
|
return True
|
|
26
28
|
if (
|
|
@@ -55,9 +57,14 @@ def gen_basic_node(
|
|
|
55
57
|
f"{depth_prefix}{LOGGER_PREFIX} checking for synonyms for attribute access"
|
|
56
58
|
)
|
|
57
59
|
for x in local_optional:
|
|
60
|
+
found = False
|
|
58
61
|
for z in x.pseudonyms:
|
|
62
|
+
# gate to ensure we don't match to multiple synonyms
|
|
63
|
+
if found:
|
|
64
|
+
continue
|
|
59
65
|
s_concept = environment.alias_origin_lookup[z]
|
|
60
66
|
if is_equivalent_basic_function_lineage(concept, s_concept):
|
|
67
|
+
found = True
|
|
61
68
|
synonyms.append(s_concept)
|
|
62
69
|
ignored_optional.add(x.address)
|
|
63
70
|
equivalent_optional = [
|
|
@@ -72,7 +79,11 @@ def gen_basic_node(
|
|
|
72
79
|
f"{depth_prefix}{LOGGER_PREFIX} basic node for {concept} has equivalent optional {[x.address for x in equivalent_optional]}"
|
|
73
80
|
)
|
|
74
81
|
for eo in equivalent_optional:
|
|
75
|
-
|
|
82
|
+
new_parents = resolve_function_parent_concepts(eo, environment=environment)
|
|
83
|
+
logger.info(
|
|
84
|
+
f"{depth_prefix}{LOGGER_PREFIX} equivalent optional {eo.address} has parents {[x.address for x in new_parents]}"
|
|
85
|
+
)
|
|
86
|
+
parent_concepts += new_parents
|
|
76
87
|
non_equivalent_optional = [
|
|
77
88
|
x
|
|
78
89
|
for x in local_optional
|
|
@@ -88,7 +88,10 @@ def determine_induced_minimal_nodes(
|
|
|
88
88
|
for node in G.nodes:
|
|
89
89
|
if concepts.get(node):
|
|
90
90
|
lookup: BuildConcept = concepts[node]
|
|
91
|
-
|
|
91
|
+
# inclusion of aggregates can create ambiguous node relation chains
|
|
92
|
+
# there may be a better way to handle this
|
|
93
|
+
# can be revisited if we need to connect a derived synonym based on an aggregate
|
|
94
|
+
if lookup.derivation in (Derivation.CONSTANT, Derivation.AGGREGATE):
|
|
92
95
|
nodes_to_remove.append(node)
|
|
93
96
|
# purge a node if we're already looking for all it's parents
|
|
94
97
|
if filter_downstream and lookup.derivation not in (Derivation.ROOT,):
|
|
@@ -112,6 +115,7 @@ def determine_induced_minimal_nodes(
|
|
|
112
115
|
return None
|
|
113
116
|
H.remove_nodes_from(list(x for x in H.nodes if x not in paths))
|
|
114
117
|
sG: nx.Graph = ax.steinertree.steiner_tree(H, nodelist).copy()
|
|
118
|
+
logger.debug("Steiner tree found for nodes %s", nodelist)
|
|
115
119
|
final: nx.DiGraph = nx.subgraph(G, sG.nodes).copy()
|
|
116
120
|
|
|
117
121
|
for edge in G.edges:
|
|
@@ -228,11 +232,14 @@ def resolve_weak_components(
|
|
|
228
232
|
# to ensure there are not ambiguous discovery paths
|
|
229
233
|
# (if we did not care about raising ambiguity errors, we could just use the first one)
|
|
230
234
|
count = 0
|
|
231
|
-
node_list =
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
235
|
+
node_list = sorted(
|
|
236
|
+
[
|
|
237
|
+
concept_to_node(c.with_default_grain())
|
|
238
|
+
for c in all_concepts
|
|
239
|
+
if "__preql_internal" not in c.address
|
|
240
|
+
]
|
|
241
|
+
)
|
|
242
|
+
logger.debug(f"Resolving weak components for {node_list} in {search_graph.nodes}")
|
|
236
243
|
synonyms: set[str] = set()
|
|
237
244
|
for x in all_concepts:
|
|
238
245
|
synonyms = synonyms.union(x.pseudonyms)
|
|
@@ -354,7 +361,7 @@ def subgraphs_to_merge_node(
|
|
|
354
361
|
parents.append(parent)
|
|
355
362
|
input_c = []
|
|
356
363
|
for x in parents:
|
|
357
|
-
for y in x.
|
|
364
|
+
for y in x.usable_outputs:
|
|
358
365
|
input_c.append(y)
|
|
359
366
|
if len(parents) == 1 and enable_early_exit:
|
|
360
367
|
logger.info(
|
|
@@ -392,6 +399,7 @@ def gen_merge_node(
|
|
|
392
399
|
)
|
|
393
400
|
else:
|
|
394
401
|
all_search_concepts = all_concepts
|
|
402
|
+
all_search_concepts = sorted(all_search_concepts, key=lambda x: x.address)
|
|
395
403
|
for filter_downstream in [True, False]:
|
|
396
404
|
weak_resolve = resolve_weak_components(
|
|
397
405
|
all_search_concepts,
|
|
@@ -31,7 +31,7 @@ def gen_unnest_node(
|
|
|
31
31
|
]
|
|
32
32
|
all_parents = arguments + non_equivalent_optional
|
|
33
33
|
logger.info(
|
|
34
|
-
f"{depth_prefix}{LOGGER_PREFIX} unnest node for {concept} with lineage {concept.lineage} has parents {all_parents} and equivalent optional {equivalent_optional}"
|
|
34
|
+
f"{depth_prefix}{LOGGER_PREFIX} unnest node for {concept} with lineage {concept.lineage} has parents + optional {all_parents} and equivalent optional {equivalent_optional}"
|
|
35
35
|
)
|
|
36
36
|
if arguments or local_optional:
|
|
37
37
|
parent = source_concepts(
|
trilogy/dialect/base.py
CHANGED
|
@@ -10,6 +10,7 @@ from trilogy.constants import (
|
|
|
10
10
|
Rendering,
|
|
11
11
|
logger,
|
|
12
12
|
)
|
|
13
|
+
from trilogy.core.constants import UNNEST_NAME
|
|
13
14
|
from trilogy.core.enums import (
|
|
14
15
|
DatePart,
|
|
15
16
|
FunctionType,
|
|
@@ -756,6 +757,16 @@ class BaseDialect:
|
|
|
756
757
|
f"{self.QUOTE_CHARACTER}{c.safe_address}{self.QUOTE_CHARACTER}"
|
|
757
758
|
for c in cte.join_derived_concepts
|
|
758
759
|
]
|
|
760
|
+
elif self.UNNEST_MODE in (UnnestMode.CROSS_JOIN_UNNEST, UnnestMode.PRESTO):
|
|
761
|
+
select_columns = [
|
|
762
|
+
self.render_concept_sql(c, cte)
|
|
763
|
+
for c in cte.output_columns
|
|
764
|
+
if c.address not in [y.address for y in cte.join_derived_concepts]
|
|
765
|
+
and c.address not in cte.hidden_concepts
|
|
766
|
+
] + [
|
|
767
|
+
f"{UNNEST_NAME} as {self.QUOTE_CHARACTER}{c.safe_address}{self.QUOTE_CHARACTER}"
|
|
768
|
+
for c in cte.join_derived_concepts
|
|
769
|
+
]
|
|
759
770
|
else:
|
|
760
771
|
# otherwse, assume we are unnesting directly in the select
|
|
761
772
|
select_columns = [
|
|
@@ -770,11 +781,20 @@ class BaseDialect:
|
|
|
770
781
|
if len(cte.joins) > 0:
|
|
771
782
|
if cte.join_derived_concepts and self.UNNEST_MODE in (
|
|
772
783
|
UnnestMode.CROSS_JOIN_ALIAS,
|
|
784
|
+
# UnnestMode.CROSS_JOIN_UNNEST,
|
|
773
785
|
UnnestMode.CROSS_JOIN,
|
|
774
786
|
UnnestMode.CROSS_APPLY,
|
|
775
787
|
):
|
|
776
788
|
|
|
777
789
|
source = f"{render_unnest(self.UNNEST_MODE, self.QUOTE_CHARACTER, cte.join_derived_concepts[0], self.render_expr, cte)}"
|
|
790
|
+
elif cte.join_derived_concepts and self.UNNEST_MODE in (
|
|
791
|
+
UnnestMode.CROSS_JOIN_UNNEST,
|
|
792
|
+
):
|
|
793
|
+
source = f"{self.render_expr(cte.join_derived_concepts[0], cte)} as {self.QUOTE_CHARACTER}{UNNEST_NAME}{self.QUOTE_CHARACTER}"
|
|
794
|
+
elif cte.join_derived_concepts and self.UNNEST_MODE in (
|
|
795
|
+
UnnestMode.PRESTO,
|
|
796
|
+
):
|
|
797
|
+
source = f"{self.render_expr(cte.join_derived_concepts[0], cte)} as t({self.QUOTE_CHARACTER}{UNNEST_NAME}{self.QUOTE_CHARACTER})"
|
|
778
798
|
elif (
|
|
779
799
|
cte.join_derived_concepts
|
|
780
800
|
and self.UNNEST_MODE == UnnestMode.SNOWFLAKE
|
trilogy/dialect/bigquery.py
CHANGED
|
@@ -22,7 +22,7 @@ FUNCTION_MAP = {
|
|
|
22
22
|
FunctionType.MINUTE: lambda x: f"EXTRACT(MINUTE from {x[0]})",
|
|
23
23
|
FunctionType.SECOND: lambda x: f"EXTRACT(SECOND from {x[0]})",
|
|
24
24
|
FunctionType.HOUR: lambda x: f"EXTRACT(HOUR from {x[0]})",
|
|
25
|
-
FunctionType.DAY_OF_WEEK: lambda x: f"EXTRACT(DAYOFWEEK from {x[0]})",
|
|
25
|
+
FunctionType.DAY_OF_WEEK: lambda x: f"EXTRACT(DAYOFWEEK from {x[0]})-1", # BigQuery's DAYOFWEEK returns 1 for Sunday
|
|
26
26
|
FunctionType.DAY: lambda x: f"EXTRACT(DAY from {x[0]})",
|
|
27
27
|
FunctionType.YEAR: lambda x: f"EXTRACT(YEAR from {x[0]})",
|
|
28
28
|
FunctionType.MONTH: lambda x: f"EXTRACT(MONTH from {x[0]})",
|
|
@@ -97,5 +97,5 @@ class BigqueryDialect(BaseDialect):
|
|
|
97
97
|
}
|
|
98
98
|
QUOTE_CHARACTER = "`"
|
|
99
99
|
SQL_TEMPLATE = BQ_SQL_TEMPLATE
|
|
100
|
-
UNNEST_MODE = UnnestMode.
|
|
100
|
+
UNNEST_MODE = UnnestMode.CROSS_JOIN_UNNEST
|
|
101
101
|
DATATYPE_MAP = DATATYPE_MAP
|
trilogy/dialect/common.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from typing import Callable
|
|
2
2
|
|
|
3
|
+
from trilogy.core.constants import UNNEST_NAME
|
|
3
4
|
from trilogy.core.enums import Modifier, UnnestMode
|
|
4
5
|
from trilogy.core.models.build import (
|
|
5
6
|
BuildComparison,
|
|
@@ -34,11 +35,15 @@ def render_unnest(
|
|
|
34
35
|
cte: CTE,
|
|
35
36
|
):
|
|
36
37
|
if not isinstance(concept, (BuildConcept, BuildParamaterizedConceptReference)):
|
|
37
|
-
address =
|
|
38
|
+
address = UNNEST_NAME
|
|
38
39
|
else:
|
|
39
40
|
address = concept.safe_address
|
|
40
41
|
if unnest_mode == UnnestMode.CROSS_JOIN:
|
|
41
42
|
return f"{render_func(concept, cte)} as {quote_character}{address}{quote_character}"
|
|
43
|
+
elif unnest_mode == UnnestMode.CROSS_JOIN_UNNEST:
|
|
44
|
+
return f"unnest({render_func(concept, cte)}) as {quote_character}{address}{quote_character}"
|
|
45
|
+
elif unnest_mode == UnnestMode.PRESTO:
|
|
46
|
+
return f"unnest({render_func(concept, cte)}) as t({quote_character}{UNNEST_NAME}{quote_character})"
|
|
42
47
|
elif unnest_mode == UnnestMode.CROSS_JOIN_ALIAS:
|
|
43
48
|
return f"{render_func(concept, cte)} as unnest_wrapper ({quote_character}{address}{quote_character})"
|
|
44
49
|
elif unnest_mode == UnnestMode.SNOWFLAKE:
|
|
@@ -95,9 +100,12 @@ def render_join(
|
|
|
95
100
|
return None
|
|
96
101
|
if not cte:
|
|
97
102
|
raise ValueError("must provide a cte to build an unnest joins")
|
|
98
|
-
if unnest_mode
|
|
99
|
-
|
|
100
|
-
|
|
103
|
+
if unnest_mode in (
|
|
104
|
+
UnnestMode.CROSS_JOIN,
|
|
105
|
+
UnnestMode.CROSS_JOIN_UNNEST,
|
|
106
|
+
UnnestMode.CROSS_JOIN_ALIAS,
|
|
107
|
+
UnnestMode.PRESTO,
|
|
108
|
+
):
|
|
101
109
|
return f"CROSS JOIN {render_unnest(unnest_mode, quote_character, join.object_to_unnest, render_expr_func, cte)}"
|
|
102
110
|
if unnest_mode == UnnestMode.SNOWFLAKE:
|
|
103
111
|
return f"LEFT JOIN LATERAL {render_unnest(unnest_mode, quote_character, join.object_to_unnest, render_expr_func, cte)}"
|
trilogy/dialect/presto.py
CHANGED
|
@@ -33,6 +33,8 @@ FUNCTION_MAP = {
|
|
|
33
33
|
FunctionType.CURRENT_DATE: lambda x: "CURRENT_DATE",
|
|
34
34
|
FunctionType.CURRENT_DATETIME: lambda x: "CURRENT_TIMESTAMP",
|
|
35
35
|
FunctionType.ARRAY: lambda x: f"ARRAY[{', '.join(x)}]",
|
|
36
|
+
# regex
|
|
37
|
+
FunctionType.REGEXP_CONTAINS: lambda x: f"REGEXP_LIKE({x[0]}, {x[1]})",
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
FUNCTION_GRAIN_MATCH_MAP = {
|
|
@@ -85,8 +87,12 @@ class PrestoDialect(BaseDialect):
|
|
|
85
87
|
}
|
|
86
88
|
QUOTE_CHARACTER = '"'
|
|
87
89
|
SQL_TEMPLATE = SQL_TEMPLATE
|
|
88
|
-
DATATYPE_MAP = {
|
|
89
|
-
|
|
90
|
+
DATATYPE_MAP = {
|
|
91
|
+
**BaseDialect.DATATYPE_MAP,
|
|
92
|
+
DataType.NUMERIC: "DECIMAL",
|
|
93
|
+
DataType.STRING: "VARCHAR",
|
|
94
|
+
}
|
|
95
|
+
UNNEST_MODE = UnnestMode.PRESTO
|
|
90
96
|
|
|
91
97
|
|
|
92
98
|
class TrinoDialect(PrestoDialect):
|
trilogy/parsing/common.py
CHANGED
|
@@ -38,6 +38,7 @@ from trilogy.core.models.author import (
|
|
|
38
38
|
Parenthetical,
|
|
39
39
|
RowsetItem,
|
|
40
40
|
RowsetLineage,
|
|
41
|
+
TraitDataType,
|
|
41
42
|
UndefinedConcept,
|
|
42
43
|
WhereClause,
|
|
43
44
|
WindowItem,
|
|
@@ -608,6 +609,9 @@ def window_item_to_concept(
|
|
|
608
609
|
and set([x.address for x in item.expr.by]) == keys
|
|
609
610
|
):
|
|
610
611
|
continue
|
|
612
|
+
elif isinstance(item.expr, AggregateWrapper):
|
|
613
|
+
|
|
614
|
+
grain_components += item.expr.by
|
|
611
615
|
else:
|
|
612
616
|
grain_components += item.concept_arguments
|
|
613
617
|
else:
|
|
@@ -617,19 +621,20 @@ def window_item_to_concept(
|
|
|
617
621
|
modifiers = get_upstream_modifiers(bcontent.concept_arguments, environment)
|
|
618
622
|
datatype = parent.content.datatype
|
|
619
623
|
if parent.type in (
|
|
620
|
-
WindowType.RANK,
|
|
624
|
+
# WindowType.RANK,
|
|
621
625
|
WindowType.ROW_NUMBER,
|
|
622
626
|
WindowType.COUNT,
|
|
623
627
|
WindowType.COUNT_DISTINCT,
|
|
624
628
|
):
|
|
625
629
|
datatype = DataType.INTEGER
|
|
630
|
+
if parent.type == WindowType.RANK:
|
|
631
|
+
datatype = TraitDataType(type=DataType.INTEGER, traits=["rank"])
|
|
626
632
|
return Concept(
|
|
627
633
|
name=name,
|
|
628
634
|
datatype=datatype,
|
|
629
635
|
purpose=local_purpose,
|
|
630
636
|
lineage=parent,
|
|
631
637
|
metadata=fmetadata,
|
|
632
|
-
# filters are implicitly at the grain of the base item
|
|
633
638
|
grain=final_grain,
|
|
634
639
|
namespace=namespace,
|
|
635
640
|
keys=keys,
|
trilogy/parsing/parse_engine.py
CHANGED
|
@@ -460,13 +460,22 @@ class ParseToObjects(Transformer):
|
|
|
460
460
|
)
|
|
461
461
|
|
|
462
462
|
def list_type(self, args) -> ListType:
|
|
463
|
-
|
|
463
|
+
content = args[0]
|
|
464
|
+
if isinstance(content, str):
|
|
465
|
+
content = self.environment.concepts[content]
|
|
466
|
+
return ListType(type=content)
|
|
464
467
|
|
|
465
468
|
def numeric_type(self, args) -> NumericType:
|
|
466
469
|
return NumericType(precision=args[0], scale=args[1])
|
|
467
470
|
|
|
468
471
|
def map_type(self, args) -> MapType:
|
|
469
|
-
|
|
472
|
+
key = args[0]
|
|
473
|
+
value = args[1]
|
|
474
|
+
if isinstance(key, str):
|
|
475
|
+
key = self.environment.concepts[key]
|
|
476
|
+
elif isinstance(value, str):
|
|
477
|
+
value = self.environment.concepts[value]
|
|
478
|
+
return MapType(key_type=key, value_type=value)
|
|
470
479
|
|
|
471
480
|
@v_args(meta=True)
|
|
472
481
|
def data_type(
|
|
@@ -842,6 +851,17 @@ class ParseToObjects(Transformer):
|
|
|
842
851
|
continue
|
|
843
852
|
|
|
844
853
|
key_inputs = grain.components
|
|
854
|
+
eligible = True
|
|
855
|
+
for key in key_inputs:
|
|
856
|
+
# never overwrite a key with a dependency on a property
|
|
857
|
+
# for example - binding a datasource with a grain of <x>.fun should
|
|
858
|
+
# never override the grain of x to <fun>
|
|
859
|
+
if column.concept.address in (
|
|
860
|
+
self.environment.concepts[key].keys or set()
|
|
861
|
+
):
|
|
862
|
+
eligible = False
|
|
863
|
+
if not eligible:
|
|
864
|
+
continue
|
|
845
865
|
keys = [self.environment.concepts[grain] for grain in key_inputs]
|
|
846
866
|
# target_c.purpose = Purpose.PROPERTY
|
|
847
867
|
target_c.keys = set([x.address for x in keys])
|
|
@@ -1030,6 +1050,9 @@ class ParseToObjects(Transformer):
|
|
|
1030
1050
|
|
|
1031
1051
|
def import_statement(self, args: list[str]) -> ImportStatement:
|
|
1032
1052
|
start = datetime.now()
|
|
1053
|
+
is_file_resolver = isinstance(
|
|
1054
|
+
self.environment.config.import_resolver, FileSystemImportResolver
|
|
1055
|
+
)
|
|
1033
1056
|
if len(args) == 2:
|
|
1034
1057
|
alias = args[-1]
|
|
1035
1058
|
cache_key = args[-1]
|
|
@@ -1043,9 +1066,7 @@ class ParseToObjects(Transformer):
|
|
|
1043
1066
|
is_stdlib = True
|
|
1044
1067
|
target = join(STDLIB_ROOT, *path) + ".preql"
|
|
1045
1068
|
token_lookup: Path | str = Path(target)
|
|
1046
|
-
elif
|
|
1047
|
-
self.environment.config.import_resolver, FileSystemImportResolver
|
|
1048
|
-
):
|
|
1069
|
+
elif is_file_resolver:
|
|
1049
1070
|
target = join(self.environment.working_path, *path) + ".preql"
|
|
1050
1071
|
# tokens + text are cached by path
|
|
1051
1072
|
token_lookup = Path(target)
|
|
@@ -1125,7 +1146,13 @@ class ParseToObjects(Transformer):
|
|
|
1125
1146
|
imps = ImportStatement(alias=alias, input_path=input_path, path=parsed_path)
|
|
1126
1147
|
|
|
1127
1148
|
self.environment.add_import(
|
|
1128
|
-
alias,
|
|
1149
|
+
alias,
|
|
1150
|
+
new_env,
|
|
1151
|
+
Import(
|
|
1152
|
+
alias=alias,
|
|
1153
|
+
path=parsed_path,
|
|
1154
|
+
input_path=Path(target) if is_file_resolver else None,
|
|
1155
|
+
),
|
|
1129
1156
|
)
|
|
1130
1157
|
end = datetime.now()
|
|
1131
1158
|
perf_logger.debug(
|
|
@@ -1677,6 +1704,7 @@ class ParseToObjects(Transformer):
|
|
|
1677
1704
|
|
|
1678
1705
|
@v_args(meta=True)
|
|
1679
1706
|
def unnest(self, meta, args):
|
|
1707
|
+
|
|
1680
1708
|
return self.function_factory.create_function(args, FunctionType.UNNEST, meta)
|
|
1681
1709
|
|
|
1682
1710
|
@v_args(meta=True)
|
trilogy/parsing/render.py
CHANGED
|
@@ -31,6 +31,7 @@ from trilogy.core.models.core import (
|
|
|
31
31
|
DataType,
|
|
32
32
|
ListType,
|
|
33
33
|
ListWrapper,
|
|
34
|
+
MapWrapper,
|
|
34
35
|
NumericType,
|
|
35
36
|
TraitDataType,
|
|
36
37
|
TupleWrapper,
|
|
@@ -250,6 +251,17 @@ class Renderer:
|
|
|
250
251
|
def _(self, arg: TupleWrapper):
|
|
251
252
|
return "(" + ", ".join([self.to_string(x) for x in arg]) + ")"
|
|
252
253
|
|
|
254
|
+
@to_string.register
|
|
255
|
+
def _(self, arg: MapWrapper):
|
|
256
|
+
def process_key_value(key, value):
|
|
257
|
+
return f"{self.to_string(key)}: {self.to_string(value)}"
|
|
258
|
+
|
|
259
|
+
return (
|
|
260
|
+
"{"
|
|
261
|
+
+ ", ".join([process_key_value(key, value) for key, value in arg.items()])
|
|
262
|
+
+ "}"
|
|
263
|
+
)
|
|
264
|
+
|
|
253
265
|
@to_string.register
|
|
254
266
|
def _(self, arg: DatePart):
|
|
255
267
|
return arg.value
|
trilogy/parsing/trilogy.lark
CHANGED
|
@@ -402,11 +402,11 @@
|
|
|
402
402
|
|
|
403
403
|
struct_type: "struct"i "<" ((data_type | IDENTIFIER) ",")* (data_type | IDENTIFIER) ","? ">"
|
|
404
404
|
|
|
405
|
-
list_type: ("list"i
|
|
405
|
+
list_type: ("list"i | "array"i) "<" (data_type | IDENTIFIER) ">"
|
|
406
406
|
|
|
407
407
|
numeric_type: "numeric"i "(" int_lit "," int_lit ")"
|
|
408
408
|
|
|
409
|
-
map_type: "map"i "<" data_type "," data_type ">"
|
|
409
|
+
map_type: "map"i "<" (data_type | IDENTIFIER) "," (data_type | IDENTIFIER) ">"
|
|
410
410
|
|
|
411
411
|
!data_type: ("string"i | "number"i | "numeric"i | "map"i | "list"i | "array"i | "any"i | "int"i | "bigint"i | "date"i | "datetime"i | "timestamp"i | "float"i | "bool"i | numeric_type | map_type | struct_type | list_type) ("::" IDENTIFIER)?
|
|
412
412
|
|
trilogy/std/date.preql
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|