pytrilogy 0.0.3.9__py3-none-any.whl → 0.0.3.11__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.9.dist-info → pytrilogy-0.0.3.11.dist-info}/METADATA +1 -1
- {pytrilogy-0.0.3.9.dist-info → pytrilogy-0.0.3.11.dist-info}/RECORD +25 -24
- trilogy/__init__.py +1 -1
- trilogy/authoring/__init__.py +14 -1
- trilogy/core/enums.py +1 -0
- trilogy/core/functions.py +9 -0
- trilogy/core/models/author.py +13 -7
- trilogy/core/models/core.py +13 -0
- trilogy/core/models/environment.py +20 -4
- trilogy/core/processing/nodes/group_node.py +1 -1
- trilogy/core/statements/author.py +13 -0
- trilogy/dialect/base.py +1 -0
- trilogy/dialect/bigquery.py +2 -3
- trilogy/dialect/duckdb.py +2 -2
- trilogy/dialect/enums.py +5 -0
- trilogy/dialect/presto.py +1 -1
- trilogy/dialect/sql_server.py +1 -1
- trilogy/executor.py +2 -34
- trilogy/parsing/parse_engine.py +59 -13
- trilogy/parsing/trilogy.lark +12 -8
- trilogy/render.py +38 -0
- {pytrilogy-0.0.3.9.dist-info → pytrilogy-0.0.3.11.dist-info}/LICENSE.md +0 -0
- {pytrilogy-0.0.3.9.dist-info → pytrilogy-0.0.3.11.dist-info}/WHEEL +0 -0
- {pytrilogy-0.0.3.9.dist-info → pytrilogy-0.0.3.11.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.3.9.dist-info → pytrilogy-0.0.3.11.dist-info}/top_level.txt +0 -0
|
@@ -1,31 +1,32 @@
|
|
|
1
|
-
trilogy/__init__.py,sha256=
|
|
1
|
+
trilogy/__init__.py,sha256=M6pFqPgs_BEva-ceDAVIDbK_Am1BozUgGDoN-z6dnrk,303
|
|
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=3etkm2RSVKO0IkgPKkrcs33X5gN_fIMyqMNfChcsR1E,1318
|
|
5
|
-
trilogy/executor.py,sha256=
|
|
5
|
+
trilogy/executor.py,sha256=CU-T7hl5hQab17KkJz9XhwlyI4-7MQL-JGdTDMVsE4E,16025
|
|
6
6
|
trilogy/parser.py,sha256=o4cfk3j3yhUFoiDKq9ZX_GjBF3dKhDjXEwb63rcBkBM,293
|
|
7
7
|
trilogy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
trilogy/render.py,sha256=D6rI1RNtn0StJeSe4e18lnlc-U--cNu4lh5C_NkU_uM,1218
|
|
8
9
|
trilogy/utility.py,sha256=euQccZLKoYBz0LNg5tzLlvv2YHvXh9HArnYp1V3uXsM,763
|
|
9
|
-
trilogy/authoring/__init__.py,sha256=
|
|
10
|
+
trilogy/authoring/__init__.py,sha256=6KPn4uoPb_7t-i510M8UNXB7nrPpaKlxAXwuRbWBdLE,2115
|
|
10
11
|
trilogy/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
12
|
trilogy/core/constants.py,sha256=7XaCpZn5mQmjTobbeBn56SzPWq9eMNDfzfsRU-fP0VE,171
|
|
12
|
-
trilogy/core/enums.py,sha256=
|
|
13
|
+
trilogy/core/enums.py,sha256=jOgUyoLGgC5-8SLBWP0jQDMxptBJbN0J48VsCa1EMYo,7111
|
|
13
14
|
trilogy/core/env_processor.py,sha256=pFsxnluKIusGKx1z7tTnfsd_xZcPy9pZDungkjkyvI0,3170
|
|
14
15
|
trilogy/core/environment_helpers.py,sha256=oOpewPwMp8xOtx2ayeeyuLNUwr-cli7UanHKot5ebNY,7627
|
|
15
16
|
trilogy/core/ergonomics.py,sha256=ASLDd0RqKWrZiG3XcKHo8nyTjaB_8xfE9t4NZ1UvGpc,1639
|
|
16
17
|
trilogy/core/exceptions.py,sha256=JPYyBcit3T_pRtlHdtKSeVJkIyWUTozW2aaut25A2xI,673
|
|
17
|
-
trilogy/core/functions.py,sha256=
|
|
18
|
+
trilogy/core/functions.py,sha256=EsRYHE2kg_FckceVgYGPPs1ylrXvBjr3l1Wa6r0SvL8,25027
|
|
18
19
|
trilogy/core/graph_models.py,sha256=z17EoO8oky2QOuO6E2aMWoVNKEVJFhLdsQZOhC4fNLU,2079
|
|
19
20
|
trilogy/core/internal.py,sha256=iicDBlC6nM8d7e7jqzf_ZOmpUsW8yrr2AA8AqEiLx-s,1577
|
|
20
21
|
trilogy/core/optimization.py,sha256=xGO8piVsLrpqrx-Aid_Y56_5slSv4eZmlP64hCHRiEc,7957
|
|
21
22
|
trilogy/core/query_processor.py,sha256=Do8YpdPBdsbKtl9n37hobzk8SORMGqH-e_zNNxd-BE4,19456
|
|
22
23
|
trilogy/core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
-
trilogy/core/models/author.py,sha256=
|
|
24
|
+
trilogy/core/models/author.py,sha256=CHVnj-GW_gjGDHaAUg60VGOfPSRr_5n5LbHvocOhQj8,70371
|
|
24
25
|
trilogy/core/models/build.py,sha256=bO1qYvuGl6LeNGgsfS6ZHAzZBR2lBPLg-QJymp9hgkU,57235
|
|
25
26
|
trilogy/core/models/build_environment.py,sha256=8UggvlPU708GZWYPJMc_ou2r7M3TY2g69eqGvz03YX0,5528
|
|
26
|
-
trilogy/core/models/core.py,sha256=
|
|
27
|
+
trilogy/core/models/core.py,sha256=00opIUXwgJy9OF-cwI883zQpArNeh6wkTpSqUszDU78,9909
|
|
27
28
|
trilogy/core/models/datasource.py,sha256=6RjJUd2u4nYmEwFBpJlM9LbHVYDv8iHJxqiBMZqUrwI,9422
|
|
28
|
-
trilogy/core/models/environment.py,sha256=
|
|
29
|
+
trilogy/core/models/environment.py,sha256=WCVJNWUze37bxFSFWo_6Z7330OG5k0DDmb7a2Tz5gg4,26264
|
|
29
30
|
trilogy/core/models/execute.py,sha256=ABylFQgtavjjCfFkEsFdUwfMB4UBQLHjdzQ9E67QlAE,33521
|
|
30
31
|
trilogy/core/optimizations/__init__.py,sha256=EBanqTXEzf1ZEYjAneIWoIcxtMDite5-n2dQ5xcfUtg,356
|
|
31
32
|
trilogy/core/optimizations/base_optimization.py,sha256=gzDOKImoFn36k7XBD3ysEYDnbnb6vdVIztUfFQZsGnM,513
|
|
@@ -56,29 +57,29 @@ trilogy/core/processing/node_generators/select_helpers/datasource_injection.py,s
|
|
|
56
57
|
trilogy/core/processing/nodes/__init__.py,sha256=DqPG3Y8vl5-UTeox6hn1EE6iwPIJpsM-XeZALHSgLZQ,5058
|
|
57
58
|
trilogy/core/processing/nodes/base_node.py,sha256=FHrY8GsTKPuMJklOjILbhGqCt5s1nmlj62Z-molARDA,16835
|
|
58
59
|
trilogy/core/processing/nodes/filter_node.py,sha256=5VtRfKbCORx0dV-vQfgy3gOEkmmscL9f31ExvlODwvY,2461
|
|
59
|
-
trilogy/core/processing/nodes/group_node.py,sha256=
|
|
60
|
+
trilogy/core/processing/nodes/group_node.py,sha256=1caU36nHknnXS-dM6xmL9Mc7kK0wCq-IS3kL7_XYNlA,8024
|
|
60
61
|
trilogy/core/processing/nodes/merge_node.py,sha256=bEz1QU2o-fl_O-VotE5dN1GmlZPClufMvUOvL2-2Uo8,15262
|
|
61
62
|
trilogy/core/processing/nodes/select_node_v2.py,sha256=Xyfq8lU7rP7JTAd8VV0ATDNal64n4xIBgWQsOuMe_Ak,8824
|
|
62
63
|
trilogy/core/processing/nodes/union_node.py,sha256=fDFzLAUh5876X6_NM7nkhoMvHEdGJ_LpvPokpZKOhx4,1425
|
|
63
64
|
trilogy/core/processing/nodes/unnest_node.py,sha256=oLKMMNMx6PLDPlt2V5neFMFrFWxET8r6XZElAhSNkO0,2181
|
|
64
65
|
trilogy/core/processing/nodes/window_node.py,sha256=STvwheVttxSWVHB-yUQUSo-Pyz7Uk8G1txFDAbWMp-s,1380
|
|
65
66
|
trilogy/core/statements/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
66
|
-
trilogy/core/statements/author.py,sha256=
|
|
67
|
+
trilogy/core/statements/author.py,sha256=X3NdGlWTUCNdQQw9EGI1kccgsLJMazwNAIsqpUSr_ZY,14443
|
|
67
68
|
trilogy/core/statements/build.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
68
69
|
trilogy/core/statements/common.py,sha256=KxEmz2ySySyZ6CTPzn0fJl5NX2KOk1RPyuUSwWhnK1g,759
|
|
69
70
|
trilogy/core/statements/execute.py,sha256=cSlvpHFOqpiZ89pPZ5GDp9Hu6j6uj-5_h21FWm_L-KM,1248
|
|
70
71
|
trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
71
|
-
trilogy/dialect/base.py,sha256=
|
|
72
|
-
trilogy/dialect/bigquery.py,sha256=
|
|
72
|
+
trilogy/dialect/base.py,sha256=gEbbqll98nfhxs_JWK0h_9M9fh4nWnon2Ntlxp_s_lI,40287
|
|
73
|
+
trilogy/dialect/bigquery.py,sha256=PkjFcNGZHYOe655PmJhb8a0afdFULuovqP0qQVO8m0I,2953
|
|
73
74
|
trilogy/dialect/common.py,sha256=cbTo_vamdp8pj9spSjGSH-bSZpy4FpNJ12k5vMvyT2Y,3942
|
|
74
75
|
trilogy/dialect/config.py,sha256=EGYRQIbrkeMuud5Bkds7jSD5dCJR5hEYZUYcy-lYZl4,3308
|
|
75
76
|
trilogy/dialect/dataframe.py,sha256=RUbNgReEa9g3pL6H7fP9lPTrAij5pkqedpZ99D8_5AE,1522
|
|
76
|
-
trilogy/dialect/duckdb.py,sha256=
|
|
77
|
-
trilogy/dialect/enums.py,sha256=
|
|
77
|
+
trilogy/dialect/duckdb.py,sha256=7f4qzNKXnpXA9wkU2ouarB5u2tpBC51TwLyGmN3bEG8,3693
|
|
78
|
+
trilogy/dialect/enums.py,sha256=QYIcVr5RgpYMA1Wl0nWeojVVxJxy0V2_sn8uqSFNx20,4615
|
|
78
79
|
trilogy/dialect/postgres.py,sha256=VH4EB4myjIeZTHeFU6vK00GxY9c53rCBjg2mLbdaCEE,3254
|
|
79
|
-
trilogy/dialect/presto.py,sha256=
|
|
80
|
+
trilogy/dialect/presto.py,sha256=Mw7_F8h19mWfuZHkHQJizQWbpu1lIHe6t2PA0r88gsY,3392
|
|
80
81
|
trilogy/dialect/snowflake.py,sha256=wmao9p26jX5yIX5SC8sRAZTXkPGTvq6ixO693QTfhz8,2989
|
|
81
|
-
trilogy/dialect/sql_server.py,sha256=
|
|
82
|
+
trilogy/dialect/sql_server.py,sha256=z2Vg7Qvw83rbGiEFIvHHLqVWJTWiz2xs76kpQj4HdTU,3131
|
|
82
83
|
trilogy/hooks/__init__.py,sha256=T3SF3phuUDPLXKGRVE_Lf9mzuwoXWyaLolncR_1kY30,144
|
|
83
84
|
trilogy/hooks/base_hook.py,sha256=I_l-NBMNC7hKTDx1JgHZPVOOCvLQ36m2oIGaR5EUMXY,1180
|
|
84
85
|
trilogy/hooks/graph_hook.py,sha256=c-vC-IXoJ_jDmKQjxQyIxyXPOuUcLIURB573gCsAfzQ,2940
|
|
@@ -89,14 +90,14 @@ trilogy/parsing/common.py,sha256=IgZ2K3LzJ0usLIwxRCRmS-4luP6uwmM-f1oqGNyGbm0,213
|
|
|
89
90
|
trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
|
|
90
91
|
trilogy/parsing/exceptions.py,sha256=92E5i2frv5hj9wxObJZsZqj5T6bglvPzvdvco_vW1Zk,38
|
|
91
92
|
trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
92
|
-
trilogy/parsing/parse_engine.py,sha256=
|
|
93
|
+
trilogy/parsing/parse_engine.py,sha256=YjYe4cAxek3CceewGI1It-XEO_ZygCxY9IQzcJw0Y0Y,57555
|
|
93
94
|
trilogy/parsing/render.py,sha256=o_XuQWhcwx1lD9eGVqkqZEwkmQK0HdmWWokGBtdeH4I,17837
|
|
94
|
-
trilogy/parsing/trilogy.lark,sha256=
|
|
95
|
+
trilogy/parsing/trilogy.lark,sha256=zehaPaYKuJZQ335sgCjH8Q6u_hy5A6A02XcdwziZdWE,12817
|
|
95
96
|
trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
96
97
|
trilogy/scripts/trilogy.py,sha256=1L0XrH4mVHRt1C9T1HnaDv2_kYEfbWTb5_-cBBke79w,3774
|
|
97
|
-
pytrilogy-0.0.3.
|
|
98
|
-
pytrilogy-0.0.3.
|
|
99
|
-
pytrilogy-0.0.3.
|
|
100
|
-
pytrilogy-0.0.3.
|
|
101
|
-
pytrilogy-0.0.3.
|
|
102
|
-
pytrilogy-0.0.3.
|
|
98
|
+
pytrilogy-0.0.3.11.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
|
|
99
|
+
pytrilogy-0.0.3.11.dist-info/METADATA,sha256=xvuxEQpZ1puSOIBOM0_U1luF8pheKHrLQnTP3YDj-jA,8984
|
|
100
|
+
pytrilogy-0.0.3.11.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
101
|
+
pytrilogy-0.0.3.11.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
|
|
102
|
+
pytrilogy-0.0.3.11.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
|
|
103
|
+
pytrilogy-0.0.3.11.dist-info/RECORD,,
|
trilogy/__init__.py
CHANGED
trilogy/authoring/__init__.py
CHANGED
|
@@ -33,11 +33,20 @@ from trilogy.core.models.author import (
|
|
|
33
33
|
WindowOrder,
|
|
34
34
|
WindowType,
|
|
35
35
|
)
|
|
36
|
-
from trilogy.core.models.core import
|
|
36
|
+
from trilogy.core.models.core import (
|
|
37
|
+
DataType,
|
|
38
|
+
ListType,
|
|
39
|
+
ListWrapper,
|
|
40
|
+
MapType,
|
|
41
|
+
StructType,
|
|
42
|
+
)
|
|
37
43
|
from trilogy.core.models.environment import Environment
|
|
38
44
|
from trilogy.core.statements.author import (
|
|
39
45
|
ConceptDeclarationStatement,
|
|
40
46
|
ConceptTransform,
|
|
47
|
+
MultiSelectStatement,
|
|
48
|
+
PersistStatement,
|
|
49
|
+
RawSQLStatement,
|
|
41
50
|
SelectItem,
|
|
42
51
|
SelectStatement,
|
|
43
52
|
)
|
|
@@ -60,6 +69,7 @@ __all__ = [
|
|
|
60
69
|
"DataType",
|
|
61
70
|
"StructType",
|
|
62
71
|
"ListType",
|
|
72
|
+
"MapType",
|
|
63
73
|
"ListWrapper",
|
|
64
74
|
"FunctionType",
|
|
65
75
|
"FunctionFactory",
|
|
@@ -87,4 +97,7 @@ __all__ = [
|
|
|
87
97
|
"DEFAULT_NAMESPACE",
|
|
88
98
|
"arbitrary_to_concept",
|
|
89
99
|
"arg_to_datatype",
|
|
100
|
+
"MultiSelectStatement",
|
|
101
|
+
"PersistStatement",
|
|
102
|
+
"RawSQLStatement",
|
|
90
103
|
]
|
trilogy/core/enums.py
CHANGED
trilogy/core/functions.py
CHANGED
|
@@ -271,6 +271,15 @@ FUNCTION_REGISTRY: dict[FunctionType, FunctionConfig] = {
|
|
|
271
271
|
output_type=DataType.INTEGER,
|
|
272
272
|
arg_count=2,
|
|
273
273
|
),
|
|
274
|
+
FunctionType.CONTAINS: FunctionConfig(
|
|
275
|
+
valid_inputs=[
|
|
276
|
+
{DataType.STRING},
|
|
277
|
+
{DataType.STRING},
|
|
278
|
+
],
|
|
279
|
+
output_purpose=Purpose.PROPERTY,
|
|
280
|
+
output_type=DataType.BOOL,
|
|
281
|
+
arg_count=2,
|
|
282
|
+
),
|
|
274
283
|
FunctionType.SUBSTRING: FunctionConfig(
|
|
275
284
|
valid_inputs=[{DataType.STRING}, {DataType.INTEGER}, {DataType.INTEGER}],
|
|
276
285
|
output_purpose=Purpose.PROPERTY,
|
trilogy/core/models/author.py
CHANGED
|
@@ -55,6 +55,7 @@ from trilogy.core.models.core import (
|
|
|
55
55
|
MapWrapper,
|
|
56
56
|
NumericType,
|
|
57
57
|
StructType,
|
|
58
|
+
TraitDataType,
|
|
58
59
|
TupleWrapper,
|
|
59
60
|
arg_to_datatype,
|
|
60
61
|
is_compatible_datatype,
|
|
@@ -101,9 +102,9 @@ class HasUUID(ABC):
|
|
|
101
102
|
|
|
102
103
|
class ConceptRef(Addressable, Namespaced, DataTyped, Mergeable, BaseModel):
|
|
103
104
|
address: str
|
|
104
|
-
datatype:
|
|
105
|
-
DataType
|
|
106
|
-
)
|
|
105
|
+
datatype: (
|
|
106
|
+
DataType | TraitDataType | ListType | StructType | MapType | NumericType
|
|
107
|
+
) = DataType.UNKNOWN
|
|
107
108
|
metadata: Optional["Metadata"] = None
|
|
108
109
|
|
|
109
110
|
@property
|
|
@@ -756,7 +757,7 @@ class Concept(Addressable, DataTyped, ConceptArgs, Mergeable, Namespaced, BaseMo
|
|
|
756
757
|
extra="forbid",
|
|
757
758
|
)
|
|
758
759
|
name: str
|
|
759
|
-
datatype: DataType | ListType | StructType | MapType | NumericType
|
|
760
|
+
datatype: DataType | TraitDataType | ListType | StructType | MapType | NumericType
|
|
760
761
|
purpose: Purpose
|
|
761
762
|
derivation: Derivation = Derivation.ROOT
|
|
762
763
|
granularity: Granularity = Granularity.MULTI_ROW
|
|
@@ -1217,9 +1218,9 @@ class UndefinedConceptFull(Concept, Mergeable, Namespaced):
|
|
|
1217
1218
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
1218
1219
|
name: str
|
|
1219
1220
|
line_no: int | None = None
|
|
1220
|
-
datatype:
|
|
1221
|
-
DataType
|
|
1222
|
-
)
|
|
1221
|
+
datatype: (
|
|
1222
|
+
DataType | TraitDataType | ListType | StructType | MapType | NumericType
|
|
1223
|
+
) = DataType.UNKNOWN
|
|
1223
1224
|
purpose: Purpose = Purpose.UNKNOWN
|
|
1224
1225
|
|
|
1225
1226
|
@property
|
|
@@ -2153,6 +2154,11 @@ class ArgBinding(BaseModel):
|
|
|
2153
2154
|
default: Expr | None = None
|
|
2154
2155
|
|
|
2155
2156
|
|
|
2157
|
+
class CustomType(BaseModel):
|
|
2158
|
+
name: str
|
|
2159
|
+
type: DataType
|
|
2160
|
+
|
|
2161
|
+
|
|
2156
2162
|
Expr = (
|
|
2157
2163
|
MagicConstants
|
|
2158
2164
|
| bool
|
trilogy/core/models/core.py
CHANGED
|
@@ -97,6 +97,19 @@ class DataType(Enum):
|
|
|
97
97
|
return self
|
|
98
98
|
|
|
99
99
|
|
|
100
|
+
class TraitDataType(BaseModel):
|
|
101
|
+
type: DataType
|
|
102
|
+
traits: list[str]
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def data_type(self):
|
|
106
|
+
return self.type
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def value(self):
|
|
110
|
+
return self.data_type.value
|
|
111
|
+
|
|
112
|
+
|
|
100
113
|
class NumericType(BaseModel):
|
|
101
114
|
precision: int = 20
|
|
102
115
|
scale: int = 5
|
|
@@ -40,6 +40,7 @@ from trilogy.core.exceptions import (
|
|
|
40
40
|
from trilogy.core.models.author import (
|
|
41
41
|
Concept,
|
|
42
42
|
ConceptRef,
|
|
43
|
+
CustomType,
|
|
43
44
|
Function,
|
|
44
45
|
SelectLineage,
|
|
45
46
|
UndefinedConcept,
|
|
@@ -59,8 +60,23 @@ class Import:
|
|
|
59
60
|
path: Path
|
|
60
61
|
|
|
61
62
|
|
|
63
|
+
class BaseImportResolver(BaseModel):
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class FileSystemImportResolver(BaseImportResolver):
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class DictImportResolver(BaseImportResolver):
|
|
72
|
+
content: Dict[str, str]
|
|
73
|
+
|
|
74
|
+
|
|
62
75
|
class EnvironmentOptions(BaseModel):
|
|
63
76
|
allow_duplicate_declaration: bool = True
|
|
77
|
+
import_resolver: BaseImportResolver = Field(
|
|
78
|
+
default_factory=FileSystemImportResolver
|
|
79
|
+
)
|
|
64
80
|
|
|
65
81
|
|
|
66
82
|
class EnvironmentConceptDict(dict):
|
|
@@ -191,14 +207,14 @@ class Environment(BaseModel):
|
|
|
191
207
|
EnvironmentDatasourceDict, PlainValidator(validate_datasources)
|
|
192
208
|
] = Field(default_factory=EnvironmentDatasourceDict)
|
|
193
209
|
functions: Dict[str, Callable[..., Any]] = Field(default_factory=dict)
|
|
194
|
-
data_types: Dict[str,
|
|
210
|
+
data_types: Dict[str, CustomType] = Field(default_factory=dict)
|
|
195
211
|
named_statements: Dict[str, SelectLineage] = Field(default_factory=dict)
|
|
196
212
|
imports: Dict[str, list[Import]] = Field(
|
|
197
213
|
default_factory=lambda: defaultdict(list) # type: ignore
|
|
198
214
|
)
|
|
199
215
|
namespace: str = DEFAULT_NAMESPACE
|
|
200
216
|
working_path: str | Path = Field(default_factory=lambda: os.getcwd())
|
|
201
|
-
|
|
217
|
+
config: EnvironmentOptions = Field(default_factory=EnvironmentOptions)
|
|
202
218
|
version: str = Field(default_factory=get_version)
|
|
203
219
|
cte_name_map: Dict[str, str] = Field(default_factory=dict)
|
|
204
220
|
materialized_concepts: set[str] = Field(default_factory=set)
|
|
@@ -233,7 +249,7 @@ class Environment(BaseModel):
|
|
|
233
249
|
imports=dict(self.imports),
|
|
234
250
|
namespace=self.namespace,
|
|
235
251
|
working_path=self.working_path,
|
|
236
|
-
environment_config=self.
|
|
252
|
+
environment_config=self.config,
|
|
237
253
|
version=self.version,
|
|
238
254
|
cte_name_map=dict(self.cte_name_map),
|
|
239
255
|
materialized_concepts=set(self.materialized_concepts),
|
|
@@ -341,7 +357,7 @@ class Environment(BaseModel):
|
|
|
341
357
|
|
|
342
358
|
return None
|
|
343
359
|
|
|
344
|
-
if existing and self.
|
|
360
|
+
if existing and self.config.allow_duplicate_declaration:
|
|
345
361
|
if existing.metadata.concept_source == ConceptSource.PERSIST_STATEMENT:
|
|
346
362
|
return handle_persist()
|
|
347
363
|
return
|
|
@@ -92,7 +92,7 @@ class GroupNode(StrategyNode):
|
|
|
92
92
|
comp_grain += source.grain
|
|
93
93
|
for x in source.output_concepts:
|
|
94
94
|
concept_map[x.address] = x
|
|
95
|
-
lookups = [
|
|
95
|
+
lookups: list[BuildConcept | str] = [
|
|
96
96
|
concept_map[x] if x in concept_map else x for x in comp_grain.components
|
|
97
97
|
]
|
|
98
98
|
comp_grain = BuildGrain.from_concepts(lookups, environment=environment)
|
|
@@ -15,8 +15,11 @@ from trilogy.core.enums import (
|
|
|
15
15
|
from trilogy.core.models.author import (
|
|
16
16
|
AggregateWrapper,
|
|
17
17
|
AlignClause,
|
|
18
|
+
ArgBinding,
|
|
18
19
|
Concept,
|
|
19
20
|
ConceptRef,
|
|
21
|
+
CustomType,
|
|
22
|
+
Expr,
|
|
20
23
|
FilterItem,
|
|
21
24
|
Function,
|
|
22
25
|
Grain,
|
|
@@ -413,3 +416,13 @@ class ConceptDeclarationStatement(HasUUID, BaseModel):
|
|
|
413
416
|
|
|
414
417
|
class ConceptDerivationStatement(BaseModel):
|
|
415
418
|
concept: Concept
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
class TypeDeclaration(BaseModel):
|
|
422
|
+
type: CustomType
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
class FunctionDeclaration(BaseModel):
|
|
426
|
+
name: str
|
|
427
|
+
args: list[ArgBinding]
|
|
428
|
+
expr: Expr
|
trilogy/dialect/base.py
CHANGED
|
@@ -184,6 +184,7 @@ FUNCTION_MAP = {
|
|
|
184
184
|
FunctionType.LOWER: lambda x: f"LOWER({x[0]}) ",
|
|
185
185
|
FunctionType.SUBSTRING: lambda x: f"SUBSTRING({x[0]},{x[1]},{x[2]})",
|
|
186
186
|
FunctionType.STRPOS: lambda x: f"STRPOS({x[0]},{x[1]})",
|
|
187
|
+
FunctionType.CONTAINS: lambda x: f"CONTAINS({x[0]},{x[1]})",
|
|
187
188
|
# FunctionType.NOT_LIKE: lambda x: f" CASE WHEN {x[0]} like {x[1]} THEN 0 ELSE 1 END",
|
|
188
189
|
# date types
|
|
189
190
|
FunctionType.DATE_TRUNCATE: lambda x: f"date_trunc({x[0]},{x[1]})",
|
trilogy/dialect/bigquery.py
CHANGED
|
@@ -42,10 +42,9 @@ CREATE OR REPLACE TABLE {{ output.address.location }} AS
|
|
|
42
42
|
{% endif %}{%- if ctes %}
|
|
43
43
|
WITH {% for cte in ctes %}
|
|
44
44
|
{{cte.name}} as ({{cte.statement}}){% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
|
45
|
-
{%- if full_select
|
|
45
|
+
{%- if full_select -%}
|
|
46
46
|
{{full_select}}
|
|
47
|
-
{
|
|
48
|
-
|
|
47
|
+
{%- else -%}
|
|
49
48
|
SELECT
|
|
50
49
|
{%- for select in select_columns %}
|
|
51
50
|
{{ select }}{% if not loop.last %},{% endif %}{% endfor %}
|
trilogy/dialect/duckdb.py
CHANGED
|
@@ -57,8 +57,8 @@ CREATE OR REPLACE TABLE {{ output.address.location }} AS
|
|
|
57
57
|
WITH {% for cte in ctes %}
|
|
58
58
|
{{cte.name}} as ({{cte.statement}}){% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
|
59
59
|
{%- if full_select -%}{{full_select}}
|
|
60
|
-
{%- else -%}{%- if comment
|
|
61
|
-
-- {{ comment }}{
|
|
60
|
+
{%- else -%}{%- if comment -%}
|
|
61
|
+
-- {{ comment }}{%- endif -%}
|
|
62
62
|
SELECT
|
|
63
63
|
{%- for select in select_columns %}
|
|
64
64
|
{{ select }}{% if not loop.last %},{% endif %}{% endfor %}
|
trilogy/dialect/enums.py
CHANGED
|
@@ -41,6 +41,11 @@ class Dialects(Enum):
|
|
|
41
41
|
return cls.DUCK_DB
|
|
42
42
|
return super()._missing_(value)
|
|
43
43
|
|
|
44
|
+
def default_renderer(self, conf=None, _engine_factory: Callable = default_factory):
|
|
45
|
+
from trilogy.render import get_dialect_generator
|
|
46
|
+
|
|
47
|
+
return get_dialect_generator(self)
|
|
48
|
+
|
|
44
49
|
def default_engine(self, conf=None, _engine_factory: Callable = default_factory):
|
|
45
50
|
if self == Dialects.BIGQUERY:
|
|
46
51
|
from google.auth import default
|
trilogy/dialect/presto.py
CHANGED
|
@@ -50,7 +50,7 @@ WITH {% for cte in ctes %}
|
|
|
50
50
|
{{cte.name}} as ({{cte.statement}}){% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
|
51
51
|
{%- if full_select -%}
|
|
52
52
|
{{full_select}}
|
|
53
|
-
{%- else
|
|
53
|
+
{%- else -%}
|
|
54
54
|
SELECT
|
|
55
55
|
{%- for select in select_columns %}
|
|
56
56
|
{{ select }}{% if not loop.last %},{% endif %}{% endfor %}
|
trilogy/dialect/sql_server.py
CHANGED
|
@@ -42,7 +42,7 @@ WITH {% for cte in ctes %}
|
|
|
42
42
|
{{cte.name}} as ({{cte.statement}}){% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
|
43
43
|
{%- if full_select -%}{{full_select}}
|
|
44
44
|
{%- else -%}{%- if comment %}
|
|
45
|
-
-- {{ comment }}{
|
|
45
|
+
-- {{ comment }}{%- endif -%}
|
|
46
46
|
SELECT
|
|
47
47
|
{%- if limit is not none %}
|
|
48
48
|
TOP {{ limit }}{% endif %}
|
trilogy/executor.py
CHANGED
|
@@ -36,6 +36,7 @@ from trilogy.dialect.enums import Dialects
|
|
|
36
36
|
from trilogy.engine import ExecutionEngine
|
|
37
37
|
from trilogy.hooks.base_hook import BaseHook
|
|
38
38
|
from trilogy.parser import parse_text
|
|
39
|
+
from trilogy.render import get_dialect_generator
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
class ResultProtocol(Protocol):
|
|
@@ -82,40 +83,7 @@ class Executor(object):
|
|
|
82
83
|
self.generator: BaseDialect
|
|
83
84
|
self.logger = logger
|
|
84
85
|
self.hooks = hooks
|
|
85
|
-
|
|
86
|
-
from trilogy.dialect.bigquery import BigqueryDialect
|
|
87
|
-
|
|
88
|
-
self.generator = BigqueryDialect()
|
|
89
|
-
elif self.dialect == Dialects.SQL_SERVER:
|
|
90
|
-
from trilogy.dialect.sql_server import SqlServerDialect
|
|
91
|
-
|
|
92
|
-
self.generator = SqlServerDialect()
|
|
93
|
-
elif self.dialect == Dialects.DUCK_DB:
|
|
94
|
-
from trilogy.dialect.duckdb import DuckDBDialect
|
|
95
|
-
|
|
96
|
-
self.generator = DuckDBDialect()
|
|
97
|
-
elif self.dialect == Dialects.PRESTO:
|
|
98
|
-
from trilogy.dialect.presto import PrestoDialect
|
|
99
|
-
|
|
100
|
-
self.generator = PrestoDialect()
|
|
101
|
-
elif self.dialect == Dialects.TRINO:
|
|
102
|
-
from trilogy.dialect.presto import TrinoDialect
|
|
103
|
-
|
|
104
|
-
self.generator = TrinoDialect()
|
|
105
|
-
elif self.dialect == Dialects.POSTGRES:
|
|
106
|
-
from trilogy.dialect.postgres import PostgresDialect
|
|
107
|
-
|
|
108
|
-
self.generator = PostgresDialect()
|
|
109
|
-
elif self.dialect == Dialects.SNOWFLAKE:
|
|
110
|
-
from trilogy.dialect.snowflake import SnowflakeDialect
|
|
111
|
-
|
|
112
|
-
self.generator = SnowflakeDialect()
|
|
113
|
-
elif self.dialect == Dialects.DATAFRAME:
|
|
114
|
-
from trilogy.dialect.dataframe import DataframeDialect
|
|
115
|
-
|
|
116
|
-
self.generator = DataframeDialect()
|
|
117
|
-
else:
|
|
118
|
-
raise ValueError(f"Unsupported dialect {self.dialect}")
|
|
86
|
+
self.generator = get_dialect_generator(self.dialect)
|
|
119
87
|
self.connection = self.engine.connect()
|
|
120
88
|
# TODO: make generic
|
|
121
89
|
if self.dialect == Dialects.DATAFRAME:
|
trilogy/parsing/parse_engine.py
CHANGED
|
@@ -4,7 +4,7 @@ from enum import Enum
|
|
|
4
4
|
from os.path import dirname, join
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from re import IGNORECASE
|
|
7
|
-
from typing import
|
|
7
|
+
from typing import List, Optional, Tuple, Union
|
|
8
8
|
|
|
9
9
|
from lark import Lark, ParseTree, Transformer, Tree, v_args
|
|
10
10
|
from lark.exceptions import (
|
|
@@ -57,6 +57,7 @@ from trilogy.core.models.author import (
|
|
|
57
57
|
Concept,
|
|
58
58
|
ConceptRef,
|
|
59
59
|
Conditional,
|
|
60
|
+
CustomType,
|
|
60
61
|
Expr,
|
|
61
62
|
FilterItem,
|
|
62
63
|
Function,
|
|
@@ -82,6 +83,7 @@ from trilogy.core.models.core import (
|
|
|
82
83
|
MapWrapper,
|
|
83
84
|
NumericType,
|
|
84
85
|
StructType,
|
|
86
|
+
TraitDataType,
|
|
85
87
|
TupleWrapper,
|
|
86
88
|
arg_to_datatype,
|
|
87
89
|
dict_to_map_wrapper,
|
|
@@ -95,12 +97,18 @@ from trilogy.core.models.datasource import (
|
|
|
95
97
|
Query,
|
|
96
98
|
RawColumnExpr,
|
|
97
99
|
)
|
|
98
|
-
from trilogy.core.models.environment import
|
|
100
|
+
from trilogy.core.models.environment import (
|
|
101
|
+
DictImportResolver,
|
|
102
|
+
Environment,
|
|
103
|
+
FileSystemImportResolver,
|
|
104
|
+
Import,
|
|
105
|
+
)
|
|
99
106
|
from trilogy.core.statements.author import (
|
|
100
107
|
ConceptDeclarationStatement,
|
|
101
108
|
ConceptDerivationStatement,
|
|
102
109
|
ConceptTransform,
|
|
103
110
|
CopyStatement,
|
|
111
|
+
FunctionDeclaration,
|
|
104
112
|
ImportStatement,
|
|
105
113
|
Limit,
|
|
106
114
|
MergeStatementV2,
|
|
@@ -111,6 +119,7 @@ from trilogy.core.statements.author import (
|
|
|
111
119
|
SelectItem,
|
|
112
120
|
SelectStatement,
|
|
113
121
|
ShowStatement,
|
|
122
|
+
TypeDeclaration,
|
|
114
123
|
)
|
|
115
124
|
from trilogy.parsing.common import (
|
|
116
125
|
align_item_to_concept,
|
|
@@ -219,7 +228,7 @@ class ParseToObjects(Transformer):
|
|
|
219
228
|
self,
|
|
220
229
|
environment: Environment,
|
|
221
230
|
parse_address: str | None = None,
|
|
222
|
-
token_address: Path | None = None,
|
|
231
|
+
token_address: Path | str | None = None,
|
|
223
232
|
parsed: dict[str, "ParseToObjects"] | None = None,
|
|
224
233
|
tokens: dict[Path | str, ParseTree] | None = None,
|
|
225
234
|
text_lookup: dict[Path | str, str] | None = None,
|
|
@@ -365,8 +374,9 @@ class ParseToObjects(Transformer):
|
|
|
365
374
|
|
|
366
375
|
def data_type(
|
|
367
376
|
self, args
|
|
368
|
-
) -> DataType | ListType | StructType | MapType | NumericType:
|
|
377
|
+
) -> DataType | TraitDataType | ListType | StructType | MapType | NumericType:
|
|
369
378
|
resolved = args[0]
|
|
379
|
+
traits = args[2:]
|
|
370
380
|
if isinstance(resolved, StructType):
|
|
371
381
|
return resolved
|
|
372
382
|
elif isinstance(resolved, ListType):
|
|
@@ -375,7 +385,10 @@ class ParseToObjects(Transformer):
|
|
|
375
385
|
return resolved
|
|
376
386
|
elif isinstance(resolved, MapType):
|
|
377
387
|
return resolved
|
|
378
|
-
|
|
388
|
+
base = DataType(args[0].lower())
|
|
389
|
+
if traits:
|
|
390
|
+
return TraitDataType(type=base, traits=traits)
|
|
391
|
+
return base
|
|
379
392
|
|
|
380
393
|
def array_comparison(self, args) -> ComparisonOperator:
|
|
381
394
|
return ComparisonOperator([x.value.lower() for x in args])
|
|
@@ -846,8 +859,22 @@ class ParseToObjects(Transformer):
|
|
|
846
859
|
)
|
|
847
860
|
|
|
848
861
|
def resolve_import_address(self, address) -> str:
|
|
849
|
-
|
|
850
|
-
|
|
862
|
+
if isinstance(
|
|
863
|
+
self.environment.config.import_resolver, FileSystemImportResolver
|
|
864
|
+
):
|
|
865
|
+
with open(address, "r", encoding="utf-8") as f:
|
|
866
|
+
text = f.read()
|
|
867
|
+
elif isinstance(self.environment.config.import_resolver, DictImportResolver):
|
|
868
|
+
lookup = address
|
|
869
|
+
if lookup not in self.environment.config.import_resolver.content:
|
|
870
|
+
raise ImportError(
|
|
871
|
+
f"Unable to import file {lookup}, not found in import resolver"
|
|
872
|
+
)
|
|
873
|
+
text = self.environment.config.import_resolver.content[lookup]
|
|
874
|
+
else:
|
|
875
|
+
raise ImportError(
|
|
876
|
+
f"Unable to import file {address}, resolver type {type(self.environment.config.import_resolver)} not supported"
|
|
877
|
+
)
|
|
851
878
|
return text
|
|
852
879
|
|
|
853
880
|
def import_statement(self, args: list[str]) -> ImportStatement:
|
|
@@ -859,10 +886,17 @@ class ParseToObjects(Transformer):
|
|
|
859
886
|
cache_key = args[0]
|
|
860
887
|
path = args[0].split(".")
|
|
861
888
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
889
|
+
if isinstance(
|
|
890
|
+
self.environment.config.import_resolver, FileSystemImportResolver
|
|
891
|
+
):
|
|
892
|
+
target = join(self.environment.working_path, *path) + ".preql"
|
|
893
|
+
# tokens + text are cached by path
|
|
894
|
+
token_lookup: Path | str = Path(target)
|
|
895
|
+
elif isinstance(self.environment.config.import_resolver, DictImportResolver):
|
|
896
|
+
target = ".".join(path)
|
|
897
|
+
token_lookup = target
|
|
898
|
+
else:
|
|
899
|
+
raise NotImplementedError
|
|
866
900
|
|
|
867
901
|
# parser + env has to be cached by prior import path + current key
|
|
868
902
|
key_path = self.import_keys + [cache_key]
|
|
@@ -893,6 +927,7 @@ class ParseToObjects(Transformer):
|
|
|
893
927
|
new_env = Environment(
|
|
894
928
|
working_path=dirname(target),
|
|
895
929
|
env_file_path=token_lookup,
|
|
930
|
+
config=self.environment.config,
|
|
896
931
|
)
|
|
897
932
|
new_env.concepts.fail_on_missing = False
|
|
898
933
|
self.parsed[self.parse_address] = self
|
|
@@ -1087,7 +1122,7 @@ class ParseToObjects(Transformer):
|
|
|
1087
1122
|
return ArgBinding(name=args[0], default=None)
|
|
1088
1123
|
|
|
1089
1124
|
@v_args(meta=True)
|
|
1090
|
-
def raw_function(self, meta: Meta, args) ->
|
|
1125
|
+
def raw_function(self, meta: Meta, args) -> FunctionDeclaration:
|
|
1091
1126
|
identity = args[0]
|
|
1092
1127
|
function_arguments: list[ArgBinding] = args[1]
|
|
1093
1128
|
output = args[2]
|
|
@@ -1109,7 +1144,7 @@ class ParseToObjects(Transformer):
|
|
|
1109
1144
|
return nout
|
|
1110
1145
|
|
|
1111
1146
|
self.environment.functions[identity] = function_factory
|
|
1112
|
-
return
|
|
1147
|
+
return FunctionDeclaration(name=identity, args=function_arguments, expr=output)
|
|
1113
1148
|
|
|
1114
1149
|
def custom_function(self, args):
|
|
1115
1150
|
name = args[0]
|
|
@@ -1121,6 +1156,13 @@ class ParseToObjects(Transformer):
|
|
|
1121
1156
|
def function(self, meta: Meta, args) -> Function:
|
|
1122
1157
|
return args[0]
|
|
1123
1158
|
|
|
1159
|
+
@v_args(meta=True)
|
|
1160
|
+
def type_declaration(self, meta: Meta, args) -> TypeDeclaration:
|
|
1161
|
+
key = args[0]
|
|
1162
|
+
datatype = args[1]
|
|
1163
|
+
self.environment.data_types[key] = datatype
|
|
1164
|
+
return TypeDeclaration(type=CustomType(name=key, type=datatype))
|
|
1165
|
+
|
|
1124
1166
|
def int_lit(self, args):
|
|
1125
1167
|
return int("".join(args))
|
|
1126
1168
|
|
|
@@ -1441,6 +1483,10 @@ class ParseToObjects(Transformer):
|
|
|
1441
1483
|
def fstrpos(self, meta, args):
|
|
1442
1484
|
return self.function_factory.create_function(args, FunctionType.STRPOS, meta)
|
|
1443
1485
|
|
|
1486
|
+
@v_args(meta=True)
|
|
1487
|
+
def fcontains(self, meta, args):
|
|
1488
|
+
return self.function_factory.create_function(args, FunctionType.CONTAINS, meta)
|
|
1489
|
+
|
|
1444
1490
|
@v_args(meta=True)
|
|
1445
1491
|
def fsubstring(self, meta, args):
|
|
1446
1492
|
return self.function_factory.create_function(args, FunctionType.SUBSTRING, meta)
|
trilogy/parsing/trilogy.lark
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
?statement: concept
|
|
4
4
|
| datasource
|
|
5
5
|
| function
|
|
6
|
+
| type_declaration
|
|
6
7
|
| multi_select_statement
|
|
7
8
|
| select_statement
|
|
8
9
|
| persist_statement
|
|
@@ -92,14 +93,15 @@
|
|
|
92
93
|
function_binding_item: IDENTIFIER ("=" literal)?
|
|
93
94
|
function_binding_list: (function_binding_item ",")* function_binding_item ","?
|
|
94
95
|
raw_function: "def" IDENTIFIER "(" function_binding_list ")" "->" expr
|
|
95
|
-
|
|
96
|
+
|
|
97
|
+
// TYPE blocks
|
|
98
|
+
type_declaration: "type" IDENTIFIER data_type
|
|
99
|
+
|
|
96
100
|
// user_id where state = Mexico
|
|
97
101
|
_filter_alt: IDENTIFIER "?" conditional
|
|
98
102
|
_filter_base: "filter"i IDENTIFIER where
|
|
99
103
|
filter_item: _filter_base | _filter_alt
|
|
100
104
|
|
|
101
|
-
|
|
102
|
-
|
|
103
105
|
// rank/lag/lead
|
|
104
106
|
WINDOW_TYPE: ("row_number"i|"rank"i|"lag"i|"lead"i | "sum"i | "avg"i | "max"i | "min"i ) /[\s]+/
|
|
105
107
|
|
|
@@ -223,16 +225,18 @@
|
|
|
223
225
|
alt_like: expr "like"i expr
|
|
224
226
|
_UPPER.1: "upper("i
|
|
225
227
|
upper: _UPPER expr ")"
|
|
226
|
-
|
|
228
|
+
_LOWER.1: "lower("i
|
|
227
229
|
lower: _LOWER expr ")"
|
|
228
230
|
_SPLIT.1: "split("i
|
|
229
231
|
fsplit: _SPLIT expr "," string_lit ")"
|
|
230
|
-
|
|
232
|
+
_STRPOS.1: "strpos("i
|
|
231
233
|
fstrpos: _STRPOS expr "," expr ")"
|
|
234
|
+
_CONTAINS.1: "contains("i
|
|
235
|
+
fcontains: _CONTAINS expr "," expr ")"
|
|
232
236
|
_SUBSTRING.1: "substring("i
|
|
233
237
|
fsubstring: _SUBSTRING expr "," expr "," expr ")"
|
|
234
238
|
|
|
235
|
-
_string_functions: like | ilike | upper | lower | fsplit | fstrpos | fsubstring
|
|
239
|
+
_string_functions: like | ilike | upper | lower | fsplit | fstrpos | fsubstring | fcontains
|
|
236
240
|
|
|
237
241
|
// special aggregate
|
|
238
242
|
_GROUP.1: "group("i
|
|
@@ -348,7 +352,7 @@
|
|
|
348
352
|
|
|
349
353
|
map_type: "map"i "<" data_type "," data_type ">"
|
|
350
354
|
|
|
351
|
-
!data_type:
|
|
355
|
+
!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)?
|
|
352
356
|
|
|
353
357
|
PURPOSE: "key"i | "metric"i | CONST
|
|
354
358
|
PROPERTY: "property"i
|
|
@@ -361,7 +365,7 @@
|
|
|
361
365
|
show_category: CONCEPTS | DATASOURCES
|
|
362
366
|
|
|
363
367
|
show_statement: "show"i ( show_category | select_statement | persist_statement) _TERMINATOR
|
|
364
|
-
|
|
368
|
+
COMMENT: /#.*(\n|$)/ | /\/\/.*\n/
|
|
365
369
|
%import common.WS
|
|
366
370
|
%ignore WS
|
|
367
371
|
%ignore COMMENT
|
trilogy/render.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from trilogy.dialect.enums import Dialects
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def get_dialect_generator(dialect: Dialects):
|
|
5
|
+
if dialect == Dialects.BIGQUERY:
|
|
6
|
+
from trilogy.dialect.bigquery import BigqueryDialect
|
|
7
|
+
|
|
8
|
+
return BigqueryDialect()
|
|
9
|
+
elif dialect == Dialects.SQL_SERVER:
|
|
10
|
+
from trilogy.dialect.sql_server import SqlServerDialect
|
|
11
|
+
|
|
12
|
+
return SqlServerDialect()
|
|
13
|
+
elif dialect == Dialects.DUCK_DB:
|
|
14
|
+
from trilogy.dialect.duckdb import DuckDBDialect
|
|
15
|
+
|
|
16
|
+
return DuckDBDialect()
|
|
17
|
+
elif dialect == Dialects.PRESTO:
|
|
18
|
+
from trilogy.dialect.presto import PrestoDialect
|
|
19
|
+
|
|
20
|
+
return PrestoDialect()
|
|
21
|
+
elif dialect == Dialects.TRINO:
|
|
22
|
+
from trilogy.dialect.presto import TrinoDialect
|
|
23
|
+
|
|
24
|
+
return TrinoDialect()
|
|
25
|
+
elif dialect == Dialects.POSTGRES:
|
|
26
|
+
from trilogy.dialect.postgres import PostgresDialect
|
|
27
|
+
|
|
28
|
+
return PostgresDialect()
|
|
29
|
+
elif dialect == Dialects.SNOWFLAKE:
|
|
30
|
+
from trilogy.dialect.snowflake import SnowflakeDialect
|
|
31
|
+
|
|
32
|
+
return SnowflakeDialect()
|
|
33
|
+
elif dialect == Dialects.DATAFRAME:
|
|
34
|
+
from trilogy.dialect.dataframe import DataframeDialect
|
|
35
|
+
|
|
36
|
+
return DataframeDialect()
|
|
37
|
+
else:
|
|
38
|
+
raise ValueError(f"Unsupported dialect {dialect}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|