pytrilogy 0.0.3.8__py3-none-any.whl → 0.0.3.10__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.8.dist-info → pytrilogy-0.0.3.10.dist-info}/METADATA +1 -1
- {pytrilogy-0.0.3.8.dist-info → pytrilogy-0.0.3.10.dist-info}/RECORD +20 -20
- trilogy/__init__.py +1 -1
- trilogy/authoring/__init__.py +6 -0
- trilogy/core/enums.py +1 -0
- trilogy/core/functions.py +9 -0
- trilogy/core/models/author.py +65 -32
- trilogy/core/models/build.py +14 -1
- trilogy/core/models/core.py +13 -0
- trilogy/core/models/environment.py +2 -1
- trilogy/core/statements/author.py +13 -0
- trilogy/dialect/base.py +1 -0
- trilogy/executor.py +5 -2
- trilogy/parsing/common.py +32 -9
- trilogy/parsing/parse_engine.py +24 -5
- trilogy/parsing/trilogy.lark +12 -8
- {pytrilogy-0.0.3.8.dist-info → pytrilogy-0.0.3.10.dist-info}/LICENSE.md +0 -0
- {pytrilogy-0.0.3.8.dist-info → pytrilogy-0.0.3.10.dist-info}/WHEEL +0 -0
- {pytrilogy-0.0.3.8.dist-info → pytrilogy-0.0.3.10.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.3.8.dist-info → pytrilogy-0.0.3.10.dist-info}/top_level.txt +0 -0
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
trilogy/__init__.py,sha256=
|
|
1
|
+
trilogy/__init__.py,sha256=vUdxo3nPFBARzvUHLzXRZLQKmcfdfzLaKOQTAayfTYE,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=9HhdLQoou1Cy9KSDgpdYxK6uyg-UPkgx9jXJBuK5ITc,17271
|
|
6
6
|
trilogy/parser.py,sha256=o4cfk3j3yhUFoiDKq9ZX_GjBF3dKhDjXEwb63rcBkBM,293
|
|
7
7
|
trilogy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
trilogy/utility.py,sha256=euQccZLKoYBz0LNg5tzLlvv2YHvXh9HArnYp1V3uXsM,763
|
|
9
|
-
trilogy/authoring/__init__.py,sha256=
|
|
9
|
+
trilogy/authoring/__init__.py,sha256=fP4oIRG41yW-gqpMjIOL0jBffh6Wlw8nR3HXhaPkKxc,2066
|
|
10
10
|
trilogy/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
trilogy/core/constants.py,sha256=7XaCpZn5mQmjTobbeBn56SzPWq9eMNDfzfsRU-fP0VE,171
|
|
12
|
-
trilogy/core/enums.py,sha256=
|
|
12
|
+
trilogy/core/enums.py,sha256=jOgUyoLGgC5-8SLBWP0jQDMxptBJbN0J48VsCa1EMYo,7111
|
|
13
13
|
trilogy/core/env_processor.py,sha256=pFsxnluKIusGKx1z7tTnfsd_xZcPy9pZDungkjkyvI0,3170
|
|
14
14
|
trilogy/core/environment_helpers.py,sha256=oOpewPwMp8xOtx2ayeeyuLNUwr-cli7UanHKot5ebNY,7627
|
|
15
15
|
trilogy/core/ergonomics.py,sha256=ASLDd0RqKWrZiG3XcKHo8nyTjaB_8xfE9t4NZ1UvGpc,1639
|
|
16
16
|
trilogy/core/exceptions.py,sha256=JPYyBcit3T_pRtlHdtKSeVJkIyWUTozW2aaut25A2xI,673
|
|
17
|
-
trilogy/core/functions.py,sha256=
|
|
17
|
+
trilogy/core/functions.py,sha256=EsRYHE2kg_FckceVgYGPPs1ylrXvBjr3l1Wa6r0SvL8,25027
|
|
18
18
|
trilogy/core/graph_models.py,sha256=z17EoO8oky2QOuO6E2aMWoVNKEVJFhLdsQZOhC4fNLU,2079
|
|
19
19
|
trilogy/core/internal.py,sha256=iicDBlC6nM8d7e7jqzf_ZOmpUsW8yrr2AA8AqEiLx-s,1577
|
|
20
20
|
trilogy/core/optimization.py,sha256=xGO8piVsLrpqrx-Aid_Y56_5slSv4eZmlP64hCHRiEc,7957
|
|
21
21
|
trilogy/core/query_processor.py,sha256=Do8YpdPBdsbKtl9n37hobzk8SORMGqH-e_zNNxd-BE4,19456
|
|
22
22
|
trilogy/core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
-
trilogy/core/models/author.py,sha256=
|
|
24
|
-
trilogy/core/models/build.py,sha256=
|
|
23
|
+
trilogy/core/models/author.py,sha256=CHVnj-GW_gjGDHaAUg60VGOfPSRr_5n5LbHvocOhQj8,70371
|
|
24
|
+
trilogy/core/models/build.py,sha256=bO1qYvuGl6LeNGgsfS6ZHAzZBR2lBPLg-QJymp9hgkU,57235
|
|
25
25
|
trilogy/core/models/build_environment.py,sha256=8UggvlPU708GZWYPJMc_ou2r7M3TY2g69eqGvz03YX0,5528
|
|
26
|
-
trilogy/core/models/core.py,sha256=
|
|
26
|
+
trilogy/core/models/core.py,sha256=00opIUXwgJy9OF-cwI883zQpArNeh6wkTpSqUszDU78,9909
|
|
27
27
|
trilogy/core/models/datasource.py,sha256=6RjJUd2u4nYmEwFBpJlM9LbHVYDv8iHJxqiBMZqUrwI,9422
|
|
28
|
-
trilogy/core/models/environment.py,sha256=
|
|
28
|
+
trilogy/core/models/environment.py,sha256=BpmHeSfIz_uNlx4IJ7LnDbQrQwEjNU7QoYcJn0uhpeo,26009
|
|
29
29
|
trilogy/core/models/execute.py,sha256=ABylFQgtavjjCfFkEsFdUwfMB4UBQLHjdzQ9E67QlAE,33521
|
|
30
30
|
trilogy/core/optimizations/__init__.py,sha256=EBanqTXEzf1ZEYjAneIWoIcxtMDite5-n2dQ5xcfUtg,356
|
|
31
31
|
trilogy/core/optimizations/base_optimization.py,sha256=gzDOKImoFn36k7XBD3ysEYDnbnb6vdVIztUfFQZsGnM,513
|
|
@@ -63,12 +63,12 @@ trilogy/core/processing/nodes/union_node.py,sha256=fDFzLAUh5876X6_NM7nkhoMvHEdGJ
|
|
|
63
63
|
trilogy/core/processing/nodes/unnest_node.py,sha256=oLKMMNMx6PLDPlt2V5neFMFrFWxET8r6XZElAhSNkO0,2181
|
|
64
64
|
trilogy/core/processing/nodes/window_node.py,sha256=STvwheVttxSWVHB-yUQUSo-Pyz7Uk8G1txFDAbWMp-s,1380
|
|
65
65
|
trilogy/core/statements/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
66
|
-
trilogy/core/statements/author.py,sha256=
|
|
66
|
+
trilogy/core/statements/author.py,sha256=X3NdGlWTUCNdQQw9EGI1kccgsLJMazwNAIsqpUSr_ZY,14443
|
|
67
67
|
trilogy/core/statements/build.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
68
68
|
trilogy/core/statements/common.py,sha256=KxEmz2ySySyZ6CTPzn0fJl5NX2KOk1RPyuUSwWhnK1g,759
|
|
69
69
|
trilogy/core/statements/execute.py,sha256=cSlvpHFOqpiZ89pPZ5GDp9Hu6j6uj-5_h21FWm_L-KM,1248
|
|
70
70
|
trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
71
|
-
trilogy/dialect/base.py,sha256=
|
|
71
|
+
trilogy/dialect/base.py,sha256=gEbbqll98nfhxs_JWK0h_9M9fh4nWnon2Ntlxp_s_lI,40287
|
|
72
72
|
trilogy/dialect/bigquery.py,sha256=mKC3zoEU232h9RtIXJjqiZ72lWH8a6S28p6wAZKrAfg,2952
|
|
73
73
|
trilogy/dialect/common.py,sha256=cbTo_vamdp8pj9spSjGSH-bSZpy4FpNJ12k5vMvyT2Y,3942
|
|
74
74
|
trilogy/dialect/config.py,sha256=EGYRQIbrkeMuud5Bkds7jSD5dCJR5hEYZUYcy-lYZl4,3308
|
|
@@ -85,18 +85,18 @@ trilogy/hooks/graph_hook.py,sha256=c-vC-IXoJ_jDmKQjxQyIxyXPOuUcLIURB573gCsAfzQ,2
|
|
|
85
85
|
trilogy/hooks/query_debugger.py,sha256=1npRjww94sPV5RRBBlLqMJRaFkH9vhEY6o828MeoEcw,5583
|
|
86
86
|
trilogy/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
87
87
|
trilogy/parsing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
88
|
-
trilogy/parsing/common.py,sha256=
|
|
88
|
+
trilogy/parsing/common.py,sha256=IgZ2K3LzJ0usLIwxRCRmS-4luP6uwmM-f1oqGNyGbm0,21306
|
|
89
89
|
trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
|
|
90
90
|
trilogy/parsing/exceptions.py,sha256=92E5i2frv5hj9wxObJZsZqj5T6bglvPzvdvco_vW1Zk,38
|
|
91
91
|
trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
92
|
-
trilogy/parsing/parse_engine.py,sha256=
|
|
92
|
+
trilogy/parsing/parse_engine.py,sha256=MiH5Kw6U512oseE-7XMyDUJRmUtUqCCzjS8MKsywNoQ,56375
|
|
93
93
|
trilogy/parsing/render.py,sha256=o_XuQWhcwx1lD9eGVqkqZEwkmQK0HdmWWokGBtdeH4I,17837
|
|
94
|
-
trilogy/parsing/trilogy.lark,sha256=
|
|
94
|
+
trilogy/parsing/trilogy.lark,sha256=zehaPaYKuJZQ335sgCjH8Q6u_hy5A6A02XcdwziZdWE,12817
|
|
95
95
|
trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
96
96
|
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.
|
|
97
|
+
pytrilogy-0.0.3.10.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
|
|
98
|
+
pytrilogy-0.0.3.10.dist-info/METADATA,sha256=LpLZFxaYTstBO1oc2-pil2pQNH-P7hrTkOQ35PWPm8A,8984
|
|
99
|
+
pytrilogy-0.0.3.10.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
100
|
+
pytrilogy-0.0.3.10.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
|
|
101
|
+
pytrilogy-0.0.3.10.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
|
|
102
|
+
pytrilogy-0.0.3.10.dist-info/RECORD,,
|
trilogy/__init__.py
CHANGED
trilogy/authoring/__init__.py
CHANGED
|
@@ -38,6 +38,9 @@ from trilogy.core.models.environment import Environment
|
|
|
38
38
|
from trilogy.core.statements.author import (
|
|
39
39
|
ConceptDeclarationStatement,
|
|
40
40
|
ConceptTransform,
|
|
41
|
+
MultiSelectStatement,
|
|
42
|
+
PersistStatement,
|
|
43
|
+
RawSQLStatement,
|
|
41
44
|
SelectItem,
|
|
42
45
|
SelectStatement,
|
|
43
46
|
)
|
|
@@ -87,4 +90,7 @@ __all__ = [
|
|
|
87
90
|
"DEFAULT_NAMESPACE",
|
|
88
91
|
"arbitrary_to_concept",
|
|
89
92
|
"arg_to_datatype",
|
|
93
|
+
"MultiSelectStatement",
|
|
94
|
+
"PersistStatement",
|
|
95
|
+
"RawSQLStatement",
|
|
90
96
|
]
|
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
|
|
@@ -547,6 +548,7 @@ class Comparison(ConceptArgs, Mergeable, Namespaced, BaseModel):
|
|
|
547
548
|
MagicConstants,
|
|
548
549
|
WindowItem,
|
|
549
550
|
AggregateWrapper,
|
|
551
|
+
FilterItem,
|
|
550
552
|
]
|
|
551
553
|
right: Union[
|
|
552
554
|
int,
|
|
@@ -566,6 +568,7 @@ class Comparison(ConceptArgs, Mergeable, Namespaced, BaseModel):
|
|
|
566
568
|
WindowItem,
|
|
567
569
|
AggregateWrapper,
|
|
568
570
|
TupleWrapper,
|
|
571
|
+
FilterItem,
|
|
569
572
|
]
|
|
570
573
|
operator: ComparisonOperator
|
|
571
574
|
|
|
@@ -754,7 +757,7 @@ class Concept(Addressable, DataTyped, ConceptArgs, Mergeable, Namespaced, BaseMo
|
|
|
754
757
|
extra="forbid",
|
|
755
758
|
)
|
|
756
759
|
name: str
|
|
757
|
-
datatype: DataType | ListType | StructType | MapType | NumericType
|
|
760
|
+
datatype: DataType | TraitDataType | ListType | StructType | MapType | NumericType
|
|
758
761
|
purpose: Purpose
|
|
759
762
|
derivation: Derivation = Derivation.ROOT
|
|
760
763
|
granularity: Granularity = Granularity.MULTI_ROW
|
|
@@ -1215,9 +1218,9 @@ class UndefinedConceptFull(Concept, Mergeable, Namespaced):
|
|
|
1215
1218
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
1216
1219
|
name: str
|
|
1217
1220
|
line_no: int | None = None
|
|
1218
|
-
datatype:
|
|
1219
|
-
DataType
|
|
1220
|
-
)
|
|
1221
|
+
datatype: (
|
|
1222
|
+
DataType | TraitDataType | ListType | StructType | MapType | NumericType
|
|
1223
|
+
) = DataType.UNKNOWN
|
|
1221
1224
|
purpose: Purpose = Purpose.UNKNOWN
|
|
1222
1225
|
|
|
1223
1226
|
@property
|
|
@@ -1249,7 +1252,7 @@ class OrderItem(Mergeable, ConceptArgs, Namespaced, BaseModel):
|
|
|
1249
1252
|
def with_merge(
|
|
1250
1253
|
self, source: Concept, target: Concept, modifiers: List[Modifier]
|
|
1251
1254
|
) -> "OrderItem":
|
|
1252
|
-
return OrderItem(
|
|
1255
|
+
return OrderItem.model_construct(
|
|
1253
1256
|
expr=(
|
|
1254
1257
|
self.expr.with_merge(source, target, modifiers)
|
|
1255
1258
|
if isinstance(self.expr, Mergeable)
|
|
@@ -1258,6 +1261,16 @@ class OrderItem(Mergeable, ConceptArgs, Namespaced, BaseModel):
|
|
|
1258
1261
|
order=self.order,
|
|
1259
1262
|
)
|
|
1260
1263
|
|
|
1264
|
+
def with_reference_replacement(self, source, target):
|
|
1265
|
+
return OrderItem.model_construct(
|
|
1266
|
+
expr=(
|
|
1267
|
+
self.expr.with_reference_replacement(source, target)
|
|
1268
|
+
if isinstance(self.expr, Mergeable)
|
|
1269
|
+
else self.expr
|
|
1270
|
+
),
|
|
1271
|
+
order=self.order,
|
|
1272
|
+
)
|
|
1273
|
+
|
|
1261
1274
|
@property
|
|
1262
1275
|
def concept_arguments(self) -> Sequence[ConceptRef]:
|
|
1263
1276
|
return get_concept_arguments(self.expr)
|
|
@@ -1320,6 +1333,17 @@ class WindowItem(DataTyped, ConceptArgs, Mergeable, Namespaced, BaseModel):
|
|
|
1320
1333
|
)
|
|
1321
1334
|
return output
|
|
1322
1335
|
|
|
1336
|
+
def with_reference_replacement(self, source, target):
|
|
1337
|
+
return WindowItem.model_construct(
|
|
1338
|
+
type=self.type,
|
|
1339
|
+
content=self.content.with_reference_replacement(source, target),
|
|
1340
|
+
over=[x.with_reference_replacement(source, target) for x in self.over],
|
|
1341
|
+
order_by=[
|
|
1342
|
+
x.with_reference_replacement(source, target) for x in self.order_by
|
|
1343
|
+
],
|
|
1344
|
+
index=self.index,
|
|
1345
|
+
)
|
|
1346
|
+
|
|
1323
1347
|
def with_namespace(self, namespace: str) -> "WindowItem":
|
|
1324
1348
|
return WindowItem.model_construct(
|
|
1325
1349
|
type=self.type,
|
|
@@ -1515,30 +1539,7 @@ class Function(DataTyped, ConceptArgs, Mergeable, Namespaced, BaseModel):
|
|
|
1515
1539
|
List[Set[DataType]],
|
|
1516
1540
|
]
|
|
1517
1541
|
] = None
|
|
1518
|
-
arguments: Sequence[
|
|
1519
|
-
Union[
|
|
1520
|
-
ConceptRef,
|
|
1521
|
-
AggregateWrapper,
|
|
1522
|
-
Function,
|
|
1523
|
-
Parenthetical,
|
|
1524
|
-
CaseWhen,
|
|
1525
|
-
CaseElse,
|
|
1526
|
-
WindowItem,
|
|
1527
|
-
int,
|
|
1528
|
-
float,
|
|
1529
|
-
str,
|
|
1530
|
-
date,
|
|
1531
|
-
datetime,
|
|
1532
|
-
MapWrapper[Any, Any],
|
|
1533
|
-
DataType,
|
|
1534
|
-
ListType,
|
|
1535
|
-
MapType,
|
|
1536
|
-
NumericType,
|
|
1537
|
-
DatePart,
|
|
1538
|
-
list,
|
|
1539
|
-
ListWrapper[Any],
|
|
1540
|
-
]
|
|
1541
|
-
]
|
|
1542
|
+
arguments: Sequence[FuncArgs]
|
|
1542
1543
|
|
|
1543
1544
|
def __init__(self, **kwargs):
|
|
1544
1545
|
super().__init__(**kwargs)
|
|
@@ -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
|
|
@@ -2164,6 +2170,7 @@ Expr = (
|
|
|
2164
2170
|
| datetime
|
|
2165
2171
|
| TupleWrapper
|
|
2166
2172
|
| ListWrapper
|
|
2173
|
+
| MapWrapper
|
|
2167
2174
|
| WindowItem
|
|
2168
2175
|
| FilterItem
|
|
2169
2176
|
| ConceptRef
|
|
@@ -2172,4 +2179,30 @@ Expr = (
|
|
|
2172
2179
|
| Parenthetical
|
|
2173
2180
|
| Function
|
|
2174
2181
|
| AggregateWrapper
|
|
2182
|
+
| CaseWhen
|
|
2183
|
+
| CaseElse
|
|
2184
|
+
)
|
|
2185
|
+
|
|
2186
|
+
FuncArgs = (
|
|
2187
|
+
ConceptRef
|
|
2188
|
+
| AggregateWrapper
|
|
2189
|
+
| Function
|
|
2190
|
+
| Parenthetical
|
|
2191
|
+
| CaseWhen
|
|
2192
|
+
| CaseElse
|
|
2193
|
+
| WindowItem
|
|
2194
|
+
| FilterItem
|
|
2195
|
+
| int
|
|
2196
|
+
| float
|
|
2197
|
+
| str
|
|
2198
|
+
| date
|
|
2199
|
+
| datetime
|
|
2200
|
+
| MapWrapper[Any, Any]
|
|
2201
|
+
| DataType
|
|
2202
|
+
| ListType
|
|
2203
|
+
| MapType
|
|
2204
|
+
| NumericType
|
|
2205
|
+
| DatePart
|
|
2206
|
+
| list
|
|
2207
|
+
| ListWrapper[Any]
|
|
2175
2208
|
)
|
trilogy/core/models/build.py
CHANGED
|
@@ -51,6 +51,7 @@ from trilogy.core.models.author import (
|
|
|
51
51
|
ConceptRef,
|
|
52
52
|
Conditional,
|
|
53
53
|
FilterItem,
|
|
54
|
+
FuncArgs,
|
|
54
55
|
Function,
|
|
55
56
|
Grain,
|
|
56
57
|
HavingClause,
|
|
@@ -1498,10 +1499,22 @@ class Factory:
|
|
|
1498
1499
|
|
|
1499
1500
|
@build.register
|
|
1500
1501
|
def _(self, base: Function) -> BuildFunction:
|
|
1502
|
+
from trilogy.parsing.common import arbitrary_to_concept
|
|
1501
1503
|
|
|
1504
|
+
raw_args: list[Concept | FuncArgs] = []
|
|
1505
|
+
for arg in base.arguments:
|
|
1506
|
+
# to do proper discovery, we need to inject virtual intermediate ocncepts
|
|
1507
|
+
if isinstance(arg, (AggregateWrapper, FilterItem, WindowItem)):
|
|
1508
|
+
narg = arbitrary_to_concept(
|
|
1509
|
+
arg,
|
|
1510
|
+
environment=self.environment,
|
|
1511
|
+
)
|
|
1512
|
+
raw_args.append(narg)
|
|
1513
|
+
else:
|
|
1514
|
+
raw_args.append(arg)
|
|
1502
1515
|
new = BuildFunction.model_construct(
|
|
1503
1516
|
operator=base.operator,
|
|
1504
|
-
arguments=[self.build(c) for c in
|
|
1517
|
+
arguments=[self.build(c) for c in raw_args],
|
|
1505
1518
|
output_datatype=base.output_datatype,
|
|
1506
1519
|
output_purpose=base.output_purpose,
|
|
1507
1520
|
valid_inputs=base.valid_inputs,
|
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,
|
|
@@ -191,7 +192,7 @@ class Environment(BaseModel):
|
|
|
191
192
|
EnvironmentDatasourceDict, PlainValidator(validate_datasources)
|
|
192
193
|
] = Field(default_factory=EnvironmentDatasourceDict)
|
|
193
194
|
functions: Dict[str, Callable[..., Any]] = Field(default_factory=dict)
|
|
194
|
-
data_types: Dict[str,
|
|
195
|
+
data_types: Dict[str, CustomType] = Field(default_factory=dict)
|
|
195
196
|
named_statements: Dict[str, SelectLineage] = Field(default_factory=dict)
|
|
196
197
|
imports: Dict[str, list[Import]] = Field(
|
|
197
198
|
default_factory=lambda: defaultdict(list) # type: ignore
|
|
@@ -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/executor.py
CHANGED
|
@@ -166,8 +166,11 @@ class Executor(object):
|
|
|
166
166
|
)
|
|
167
167
|
|
|
168
168
|
@execute_query.register
|
|
169
|
-
def _(self, query: str) -> CursorResult:
|
|
170
|
-
|
|
169
|
+
def _(self, query: str) -> CursorResult | None:
|
|
170
|
+
results = self.execute_text(query)
|
|
171
|
+
if results:
|
|
172
|
+
return results[-1]
|
|
173
|
+
return None
|
|
171
174
|
|
|
172
175
|
@execute_query.register
|
|
173
176
|
def _(self, query: SelectStatement) -> CursorResult:
|
trilogy/parsing/common.py
CHANGED
|
@@ -84,7 +84,8 @@ def process_function_arg(
|
|
|
84
84
|
environment.add_concept(concept, meta=meta)
|
|
85
85
|
return concept
|
|
86
86
|
elif isinstance(
|
|
87
|
-
arg,
|
|
87
|
+
arg,
|
|
88
|
+
(ListWrapper, MapWrapper),
|
|
88
89
|
):
|
|
89
90
|
id_hash = string_to_hash(str(arg))
|
|
90
91
|
name = f"{VIRTUAL_CONCEPT_PREFIX}_{id_hash}"
|
|
@@ -249,6 +250,24 @@ def concepts_to_grain_concepts(
|
|
|
249
250
|
return v2
|
|
250
251
|
|
|
251
252
|
|
|
253
|
+
def get_relevant_parent_concepts(arg) -> tuple[list[ConceptRef], bool]:
|
|
254
|
+
from trilogy.core.models.author import get_concept_arguments
|
|
255
|
+
|
|
256
|
+
is_metric = False
|
|
257
|
+
if isinstance(arg, Function):
|
|
258
|
+
all = []
|
|
259
|
+
for y in arg.arguments:
|
|
260
|
+
refs, local_flag = get_relevant_parent_concepts(y)
|
|
261
|
+
all += refs
|
|
262
|
+
is_metric = is_metric or local_flag
|
|
263
|
+
return all, is_metric
|
|
264
|
+
elif isinstance(arg, AggregateWrapper) and not arg.by:
|
|
265
|
+
return [], True
|
|
266
|
+
elif isinstance(arg, AggregateWrapper) and arg.by:
|
|
267
|
+
return arg.by, True
|
|
268
|
+
return get_concept_arguments(arg), False
|
|
269
|
+
|
|
270
|
+
|
|
252
271
|
def function_to_concept(
|
|
253
272
|
parent: Function,
|
|
254
273
|
name: str,
|
|
@@ -256,14 +275,12 @@ def function_to_concept(
|
|
|
256
275
|
namespace: str | None = None,
|
|
257
276
|
metadata: Metadata | None = None,
|
|
258
277
|
) -> Concept:
|
|
278
|
+
|
|
259
279
|
pkeys: List[Concept] = []
|
|
260
280
|
namespace = namespace or environment.namespace
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if not isinstance(x, UndefinedConcept)
|
|
265
|
-
]
|
|
266
|
-
|
|
281
|
+
is_metric = False
|
|
282
|
+
ref_args, is_metric = get_relevant_parent_concepts(parent)
|
|
283
|
+
concrete_args = [environment.concepts[c.address] for c in ref_args]
|
|
267
284
|
pkeys += [x for x in concrete_args if not x.derivation == Derivation.CONSTANT]
|
|
268
285
|
grain: Grain | None = Grain()
|
|
269
286
|
for x in pkeys:
|
|
@@ -274,12 +291,18 @@ def function_to_concept(
|
|
|
274
291
|
modifiers = get_upstream_modifiers(pkeys, environment)
|
|
275
292
|
key_grain: list[str] = []
|
|
276
293
|
for x in pkeys:
|
|
277
|
-
|
|
294
|
+
# metrics will group to keys, so do no do key traversal
|
|
295
|
+
if is_metric:
|
|
296
|
+
key_grain.append(x.address)
|
|
297
|
+
# otherwse, for row ops, assume keys are transitive
|
|
298
|
+
elif x.keys:
|
|
278
299
|
key_grain += [*x.keys]
|
|
279
300
|
else:
|
|
280
301
|
key_grain.append(x.address)
|
|
281
302
|
keys = set(key_grain)
|
|
282
|
-
if
|
|
303
|
+
if is_metric:
|
|
304
|
+
purpose = Purpose.METRIC
|
|
305
|
+
elif not pkeys:
|
|
283
306
|
purpose = Purpose.CONSTANT
|
|
284
307
|
else:
|
|
285
308
|
purpose = parent.output_purpose
|
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,
|
|
@@ -101,6 +103,7 @@ from trilogy.core.statements.author import (
|
|
|
101
103
|
ConceptDerivationStatement,
|
|
102
104
|
ConceptTransform,
|
|
103
105
|
CopyStatement,
|
|
106
|
+
FunctionDeclaration,
|
|
104
107
|
ImportStatement,
|
|
105
108
|
Limit,
|
|
106
109
|
MergeStatementV2,
|
|
@@ -111,6 +114,7 @@ from trilogy.core.statements.author import (
|
|
|
111
114
|
SelectItem,
|
|
112
115
|
SelectStatement,
|
|
113
116
|
ShowStatement,
|
|
117
|
+
TypeDeclaration,
|
|
114
118
|
)
|
|
115
119
|
from trilogy.parsing.common import (
|
|
116
120
|
align_item_to_concept,
|
|
@@ -365,8 +369,9 @@ class ParseToObjects(Transformer):
|
|
|
365
369
|
|
|
366
370
|
def data_type(
|
|
367
371
|
self, args
|
|
368
|
-
) -> DataType | ListType | StructType | MapType | NumericType:
|
|
372
|
+
) -> DataType | TraitDataType | ListType | StructType | MapType | NumericType:
|
|
369
373
|
resolved = args[0]
|
|
374
|
+
traits = args[2:]
|
|
370
375
|
if isinstance(resolved, StructType):
|
|
371
376
|
return resolved
|
|
372
377
|
elif isinstance(resolved, ListType):
|
|
@@ -375,7 +380,10 @@ class ParseToObjects(Transformer):
|
|
|
375
380
|
return resolved
|
|
376
381
|
elif isinstance(resolved, MapType):
|
|
377
382
|
return resolved
|
|
378
|
-
|
|
383
|
+
base = DataType(args[0].lower())
|
|
384
|
+
if traits:
|
|
385
|
+
return TraitDataType(type=base, traits=traits)
|
|
386
|
+
return base
|
|
379
387
|
|
|
380
388
|
def array_comparison(self, args) -> ComparisonOperator:
|
|
381
389
|
return ComparisonOperator([x.value.lower() for x in args])
|
|
@@ -1087,7 +1095,7 @@ class ParseToObjects(Transformer):
|
|
|
1087
1095
|
return ArgBinding(name=args[0], default=None)
|
|
1088
1096
|
|
|
1089
1097
|
@v_args(meta=True)
|
|
1090
|
-
def raw_function(self, meta: Meta, args) ->
|
|
1098
|
+
def raw_function(self, meta: Meta, args) -> FunctionDeclaration:
|
|
1091
1099
|
identity = args[0]
|
|
1092
1100
|
function_arguments: list[ArgBinding] = args[1]
|
|
1093
1101
|
output = args[2]
|
|
@@ -1109,7 +1117,7 @@ class ParseToObjects(Transformer):
|
|
|
1109
1117
|
return nout
|
|
1110
1118
|
|
|
1111
1119
|
self.environment.functions[identity] = function_factory
|
|
1112
|
-
return
|
|
1120
|
+
return FunctionDeclaration(name=identity, args=function_arguments, expr=output)
|
|
1113
1121
|
|
|
1114
1122
|
def custom_function(self, args):
|
|
1115
1123
|
name = args[0]
|
|
@@ -1121,6 +1129,13 @@ class ParseToObjects(Transformer):
|
|
|
1121
1129
|
def function(self, meta: Meta, args) -> Function:
|
|
1122
1130
|
return args[0]
|
|
1123
1131
|
|
|
1132
|
+
@v_args(meta=True)
|
|
1133
|
+
def type_declaration(self, meta: Meta, args) -> TypeDeclaration:
|
|
1134
|
+
key = args[0]
|
|
1135
|
+
datatype = args[1]
|
|
1136
|
+
self.environment.data_types[key] = datatype
|
|
1137
|
+
return TypeDeclaration(type=CustomType(name=key, type=datatype))
|
|
1138
|
+
|
|
1124
1139
|
def int_lit(self, args):
|
|
1125
1140
|
return int("".join(args))
|
|
1126
1141
|
|
|
@@ -1441,6 +1456,10 @@ class ParseToObjects(Transformer):
|
|
|
1441
1456
|
def fstrpos(self, meta, args):
|
|
1442
1457
|
return self.function_factory.create_function(args, FunctionType.STRPOS, meta)
|
|
1443
1458
|
|
|
1459
|
+
@v_args(meta=True)
|
|
1460
|
+
def fcontains(self, meta, args):
|
|
1461
|
+
return self.function_factory.create_function(args, FunctionType.CONTAINS, meta)
|
|
1462
|
+
|
|
1444
1463
|
@v_args(meta=True)
|
|
1445
1464
|
def fsubstring(self, meta, args):
|
|
1446
1465
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|