pytrilogy 0.0.3.92__py3-none-any.whl → 0.0.3.94__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.92.dist-info → pytrilogy-0.0.3.94.dist-info}/METADATA +1 -1
- {pytrilogy-0.0.3.92.dist-info → pytrilogy-0.0.3.94.dist-info}/RECORD +18 -18
- trilogy/__init__.py +1 -1
- trilogy/core/env_processor.py +4 -2
- trilogy/core/graph_models.py +63 -44
- trilogy/core/models/author.py +17 -26
- trilogy/core/models/build.py +141 -151
- trilogy/core/models/build_environment.py +2 -6
- trilogy/core/models/execute.py +3 -3
- trilogy/core/processing/node_generators/group_node.py +3 -7
- trilogy/core/processing/node_generators/node_merge_node.py +30 -28
- trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +25 -11
- trilogy/core/processing/node_generators/select_merge_node.py +66 -80
- trilogy/parsing/parse_engine.py +1 -1
- {pytrilogy-0.0.3.92.dist-info → pytrilogy-0.0.3.94.dist-info}/WHEEL +0 -0
- {pytrilogy-0.0.3.92.dist-info → pytrilogy-0.0.3.94.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.3.92.dist-info → pytrilogy-0.0.3.94.dist-info}/licenses/LICENSE.md +0 -0
- {pytrilogy-0.0.3.92.dist-info → pytrilogy-0.0.3.94.dist-info}/top_level.txt +0 -0
trilogy/core/models/build.py
CHANGED
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from abc import ABC
|
|
4
4
|
from collections import defaultdict
|
|
5
|
+
from dataclasses import dataclass, field
|
|
5
6
|
from datetime import date, datetime
|
|
6
7
|
from functools import cached_property, singledispatchmethod
|
|
7
8
|
from typing import (
|
|
@@ -18,12 +19,7 @@ from typing import (
|
|
|
18
19
|
)
|
|
19
20
|
|
|
20
21
|
from pydantic import (
|
|
21
|
-
BaseModel,
|
|
22
22
|
ConfigDict,
|
|
23
|
-
Field,
|
|
24
|
-
ValidationInfo,
|
|
25
|
-
computed_field,
|
|
26
|
-
field_validator,
|
|
27
23
|
)
|
|
28
24
|
|
|
29
25
|
from trilogy.constants import DEFAULT_NAMESPACE, MagicConstants
|
|
@@ -170,17 +166,14 @@ def concepts_to_build_grain_concepts(
|
|
|
170
166
|
return final
|
|
171
167
|
|
|
172
168
|
|
|
173
|
-
|
|
169
|
+
@dataclass
|
|
170
|
+
class LooseBuildConceptList:
|
|
174
171
|
concepts: Sequence[BuildConcept]
|
|
175
172
|
|
|
176
173
|
@cached_property
|
|
177
174
|
def addresses(self) -> set[str]:
|
|
178
175
|
return {s.address for s in self.concepts}
|
|
179
176
|
|
|
180
|
-
@classmethod
|
|
181
|
-
def validate(cls, v):
|
|
182
|
-
return cls(v)
|
|
183
|
-
|
|
184
177
|
@cached_property
|
|
185
178
|
def sorted_addresses(self) -> List[str]:
|
|
186
179
|
return sorted(list(self.addresses))
|
|
@@ -248,7 +241,8 @@ def get_concept_arguments(expr) -> List["BuildConcept"]:
|
|
|
248
241
|
return output
|
|
249
242
|
|
|
250
243
|
|
|
251
|
-
|
|
244
|
+
@dataclass
|
|
245
|
+
class BuildParamaterizedConceptReference(DataTyped):
|
|
252
246
|
concept: BuildConcept
|
|
253
247
|
|
|
254
248
|
def __str__(self):
|
|
@@ -263,8 +257,9 @@ class BuildParamaterizedConceptReference(DataTyped, BaseModel):
|
|
|
263
257
|
return self.concept.output_datatype
|
|
264
258
|
|
|
265
259
|
|
|
266
|
-
|
|
267
|
-
|
|
260
|
+
@dataclass
|
|
261
|
+
class BuildGrain:
|
|
262
|
+
components: set[str] = field(default_factory=set)
|
|
268
263
|
where_clause: Optional[BuildWhereClause] = None
|
|
269
264
|
_str: str | None = None
|
|
270
265
|
_str_no_condition: str | None = None
|
|
@@ -272,7 +267,7 @@ class BuildGrain(BaseModel):
|
|
|
272
267
|
def without_condition(self):
|
|
273
268
|
if not self.where_clause:
|
|
274
269
|
return self
|
|
275
|
-
return BuildGrain
|
|
270
|
+
return BuildGrain(components=self.components)
|
|
276
271
|
|
|
277
272
|
@classmethod
|
|
278
273
|
def from_concepts(
|
|
@@ -282,30 +277,13 @@ class BuildGrain(BaseModel):
|
|
|
282
277
|
where_clause: BuildWhereClause | None = None,
|
|
283
278
|
) -> "BuildGrain":
|
|
284
279
|
|
|
285
|
-
return BuildGrain
|
|
280
|
+
return BuildGrain(
|
|
286
281
|
components=concepts_to_build_grain_concepts(
|
|
287
282
|
concepts, environment=environment
|
|
288
283
|
),
|
|
289
284
|
where_clause=where_clause,
|
|
290
285
|
)
|
|
291
286
|
|
|
292
|
-
@field_validator("components", mode="before")
|
|
293
|
-
def component_validator(cls, v, info: ValidationInfo):
|
|
294
|
-
output = set()
|
|
295
|
-
if isinstance(v, list):
|
|
296
|
-
for vc in v:
|
|
297
|
-
if isinstance(vc, BuildConcept):
|
|
298
|
-
output.add(vc.address)
|
|
299
|
-
else:
|
|
300
|
-
output.add(vc)
|
|
301
|
-
else:
|
|
302
|
-
output = v
|
|
303
|
-
if not isinstance(output, set):
|
|
304
|
-
raise ValueError(f"Invalid grain component {output}, is not set")
|
|
305
|
-
if not all(isinstance(x, str) for x in output):
|
|
306
|
-
raise ValueError(f"Invalid component {output}")
|
|
307
|
-
return output
|
|
308
|
-
|
|
309
287
|
def __add__(self, other: "BuildGrain") -> "BuildGrain":
|
|
310
288
|
if not other:
|
|
311
289
|
return self
|
|
@@ -324,12 +302,12 @@ class BuildGrain(BaseModel):
|
|
|
324
302
|
# raise NotImplementedError(
|
|
325
303
|
# f"Cannot merge grains with where clauses, self {self.where_clause} other {other.where_clause}"
|
|
326
304
|
# )
|
|
327
|
-
return BuildGrain
|
|
305
|
+
return BuildGrain(
|
|
328
306
|
components=self.components.union(other.components), where_clause=where
|
|
329
307
|
)
|
|
330
308
|
|
|
331
309
|
def __sub__(self, other: "BuildGrain") -> "BuildGrain":
|
|
332
|
-
return BuildGrain
|
|
310
|
+
return BuildGrain(
|
|
333
311
|
components=self.components.difference(other.components),
|
|
334
312
|
where_clause=self.where_clause,
|
|
335
313
|
)
|
|
@@ -401,7 +379,8 @@ class BuildGrain(BaseModel):
|
|
|
401
379
|
return self.__add__(other)
|
|
402
380
|
|
|
403
381
|
|
|
404
|
-
|
|
382
|
+
@dataclass
|
|
383
|
+
class BuildParenthetical(DataTyped, ConstantInlineable, BuildConceptArgs):
|
|
405
384
|
content: "BuildExpr"
|
|
406
385
|
|
|
407
386
|
def __add__(self, other) -> Union["BuildParenthetical", "BuildConditional"]:
|
|
@@ -455,7 +434,8 @@ class BuildParenthetical(DataTyped, ConstantInlineable, BuildConceptArgs, BaseMo
|
|
|
455
434
|
return arg_to_datatype(self.content)
|
|
456
435
|
|
|
457
436
|
|
|
458
|
-
|
|
437
|
+
@dataclass
|
|
438
|
+
class BuildConditional(BuildConceptArgs, ConstantInlineable):
|
|
459
439
|
left: Union[
|
|
460
440
|
int,
|
|
461
441
|
str,
|
|
@@ -583,7 +563,8 @@ class BuildConditional(BuildConceptArgs, ConstantInlineable, BaseModel):
|
|
|
583
563
|
return chunks
|
|
584
564
|
|
|
585
565
|
|
|
586
|
-
|
|
566
|
+
@dataclass
|
|
567
|
+
class BuildWhereClause(BuildConceptArgs):
|
|
587
568
|
conditional: Union[
|
|
588
569
|
BuildSubselectComparison,
|
|
589
570
|
BuildComparison,
|
|
@@ -619,7 +600,8 @@ class BuildHavingClause(BuildWhereClause):
|
|
|
619
600
|
pass
|
|
620
601
|
|
|
621
602
|
|
|
622
|
-
|
|
603
|
+
@dataclass
|
|
604
|
+
class BuildComparison(BuildConceptArgs, ConstantInlineable):
|
|
623
605
|
|
|
624
606
|
left: Union[
|
|
625
607
|
int,
|
|
@@ -749,6 +731,7 @@ class BuildComparison(BuildConceptArgs, ConstantInlineable, BaseModel):
|
|
|
749
731
|
return output
|
|
750
732
|
|
|
751
733
|
|
|
734
|
+
@dataclass
|
|
752
735
|
class BuildSubselectComparison(BuildComparison):
|
|
753
736
|
left: Union[
|
|
754
737
|
int,
|
|
@@ -810,18 +793,18 @@ class BuildSubselectComparison(BuildComparison):
|
|
|
810
793
|
return [tuple(get_concept_arguments(self.right))]
|
|
811
794
|
|
|
812
795
|
|
|
813
|
-
|
|
796
|
+
@dataclass
|
|
797
|
+
class BuildConcept(Addressable, BuildConceptArgs, DataTyped):
|
|
814
798
|
model_config = ConfigDict(extra="forbid")
|
|
815
799
|
name: str
|
|
816
|
-
datatype: DataType | ArrayType | StructType | MapType | NumericType
|
|
800
|
+
datatype: DataType | ArrayType | StructType | MapType | NumericType | TraitDataType
|
|
817
801
|
purpose: Purpose
|
|
818
802
|
build_is_aggregate: bool
|
|
819
803
|
derivation: Derivation = Derivation.ROOT
|
|
820
804
|
granularity: Granularity = Granularity.MULTI_ROW
|
|
821
|
-
namespace: Optional[str] =
|
|
822
|
-
metadata: Metadata =
|
|
805
|
+
namespace: Optional[str] = field(default=DEFAULT_NAMESPACE)
|
|
806
|
+
metadata: Metadata = field(
|
|
823
807
|
default_factory=lambda: Metadata(description=None, line_number=None),
|
|
824
|
-
validate_default=True,
|
|
825
808
|
)
|
|
826
809
|
lineage: Optional[
|
|
827
810
|
Union[
|
|
@@ -835,22 +818,23 @@ class BuildConcept(Addressable, BuildConceptArgs, DataTyped, BaseModel):
|
|
|
835
818
|
] = None
|
|
836
819
|
|
|
837
820
|
keys: Optional[set[str]] = None
|
|
838
|
-
grain: BuildGrain =
|
|
839
|
-
modifiers: List[Modifier] =
|
|
840
|
-
pseudonyms: set[str] =
|
|
821
|
+
grain: BuildGrain = field(default=None) # type: ignore
|
|
822
|
+
modifiers: List[Modifier] = field(default_factory=list) # type: ignore
|
|
823
|
+
pseudonyms: set[str] = field(default_factory=set)
|
|
841
824
|
|
|
842
825
|
@property
|
|
843
826
|
def is_aggregate(self) -> bool:
|
|
844
827
|
return self.build_is_aggregate
|
|
845
828
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
def __hash__(self):
|
|
829
|
+
@cached_property
|
|
830
|
+
def hash(self) -> int:
|
|
850
831
|
return hash(
|
|
851
832
|
f"{self.name}+{self.datatype}+ {self.purpose} + {str(self.lineage)} + {self.namespace} + {str(self.grain)} + {str(self.keys)}"
|
|
852
833
|
)
|
|
853
834
|
|
|
835
|
+
def __hash__(self):
|
|
836
|
+
return self.hash
|
|
837
|
+
|
|
854
838
|
def __repr__(self):
|
|
855
839
|
base = f"{self.address}@{self.grain}"
|
|
856
840
|
return base
|
|
@@ -903,7 +887,7 @@ class BuildConcept(Addressable, BuildConceptArgs, DataTyped, BaseModel):
|
|
|
903
887
|
]
|
|
904
888
|
)
|
|
905
889
|
)
|
|
906
|
-
return self.__class__
|
|
890
|
+
return self.__class__(
|
|
907
891
|
name=self.name,
|
|
908
892
|
datatype=self.datatype,
|
|
909
893
|
purpose=self.purpose,
|
|
@@ -945,7 +929,7 @@ class BuildConcept(Addressable, BuildConceptArgs, DataTyped, BaseModel):
|
|
|
945
929
|
grain = self.grain
|
|
946
930
|
else:
|
|
947
931
|
grain = self.grain # type: ignore
|
|
948
|
-
return self.__class__
|
|
932
|
+
return self.__class__(
|
|
949
933
|
name=self.name,
|
|
950
934
|
datatype=self.datatype,
|
|
951
935
|
purpose=self.purpose,
|
|
@@ -1001,7 +985,8 @@ class BuildConcept(Addressable, BuildConceptArgs, DataTyped, BaseModel):
|
|
|
1001
985
|
return self.lineage.concept_arguments if self.lineage else []
|
|
1002
986
|
|
|
1003
987
|
|
|
1004
|
-
|
|
988
|
+
@dataclass
|
|
989
|
+
class BuildOrderItem(DataTyped, BuildConceptArgs):
|
|
1005
990
|
expr: BuildExpr
|
|
1006
991
|
order: Ordering
|
|
1007
992
|
|
|
@@ -1032,11 +1017,12 @@ class BuildOrderItem(DataTyped, BuildConceptArgs, BaseModel):
|
|
|
1032
1017
|
return arg_to_datatype(self.expr)
|
|
1033
1018
|
|
|
1034
1019
|
|
|
1035
|
-
|
|
1020
|
+
@dataclass
|
|
1021
|
+
class BuildWindowItem(DataTyped, BuildConceptArgs):
|
|
1036
1022
|
type: WindowType
|
|
1037
1023
|
content: BuildConcept
|
|
1038
1024
|
order_by: List[BuildOrderItem]
|
|
1039
|
-
over: List["BuildConcept"] =
|
|
1025
|
+
over: List["BuildConcept"] = field(default_factory=list)
|
|
1040
1026
|
index: Optional[int] = None
|
|
1041
1027
|
|
|
1042
1028
|
def __repr__(self) -> str:
|
|
@@ -1069,7 +1055,8 @@ class BuildWindowItem(DataTyped, BuildConceptArgs, BaseModel):
|
|
|
1069
1055
|
return Purpose.PROPERTY
|
|
1070
1056
|
|
|
1071
1057
|
|
|
1072
|
-
|
|
1058
|
+
@dataclass
|
|
1059
|
+
class BuildCaseWhen(BuildConceptArgs):
|
|
1073
1060
|
comparison: BuildConditional | BuildSubselectComparison | BuildComparison
|
|
1074
1061
|
expr: "BuildExpr"
|
|
1075
1062
|
|
|
@@ -1090,30 +1077,18 @@ class BuildCaseWhen(BuildConceptArgs, BaseModel):
|
|
|
1090
1077
|
)
|
|
1091
1078
|
|
|
1092
1079
|
|
|
1093
|
-
|
|
1080
|
+
@dataclass
|
|
1081
|
+
class BuildCaseElse(BuildConceptArgs):
|
|
1094
1082
|
expr: "BuildExpr"
|
|
1095
|
-
# this ensures that it's easily differentiable from CaseWhen
|
|
1096
|
-
discriminant: ComparisonOperator = ComparisonOperator.ELSE
|
|
1097
1083
|
|
|
1098
1084
|
@property
|
|
1099
1085
|
def concept_arguments(self):
|
|
1100
1086
|
return get_concept_arguments(self.expr)
|
|
1101
1087
|
|
|
1102
1088
|
|
|
1103
|
-
|
|
1104
|
-
|
|
1089
|
+
@dataclass
|
|
1090
|
+
class BuildFunction(DataTyped, BuildConceptArgs):
|
|
1105
1091
|
operator: FunctionType
|
|
1106
|
-
arg_count: int = Field(default=1)
|
|
1107
|
-
output_datatype: (
|
|
1108
|
-
DataType | ArrayType | StructType | MapType | NumericType | TraitDataType
|
|
1109
|
-
)
|
|
1110
|
-
output_purpose: Purpose
|
|
1111
|
-
valid_inputs: Optional[
|
|
1112
|
-
Union[
|
|
1113
|
-
Set[DataType],
|
|
1114
|
-
List[Set[DataType]],
|
|
1115
|
-
]
|
|
1116
|
-
] = None
|
|
1117
1092
|
arguments: Sequence[
|
|
1118
1093
|
Union[
|
|
1119
1094
|
int,
|
|
@@ -1139,6 +1114,17 @@ class BuildFunction(DataTyped, BuildConceptArgs, BaseModel):
|
|
|
1139
1114
|
ListWrapper[Any],
|
|
1140
1115
|
]
|
|
1141
1116
|
]
|
|
1117
|
+
output_data_type: (
|
|
1118
|
+
DataType | ArrayType | StructType | MapType | NumericType | TraitDataType
|
|
1119
|
+
)
|
|
1120
|
+
output_purpose: Purpose = field(default=Purpose.KEY)
|
|
1121
|
+
arg_count: int = field(default=1)
|
|
1122
|
+
valid_inputs: Optional[
|
|
1123
|
+
Union[
|
|
1124
|
+
Set[DataType],
|
|
1125
|
+
List[Set[DataType]],
|
|
1126
|
+
]
|
|
1127
|
+
] = None
|
|
1142
1128
|
|
|
1143
1129
|
def __repr__(self):
|
|
1144
1130
|
return f'{self.operator.value}({",".join([str(a) for a in self.arguments])})'
|
|
@@ -1148,7 +1134,11 @@ class BuildFunction(DataTyped, BuildConceptArgs, BaseModel):
|
|
|
1148
1134
|
|
|
1149
1135
|
@property
|
|
1150
1136
|
def datatype(self):
|
|
1151
|
-
return self.
|
|
1137
|
+
return self.output_data_type
|
|
1138
|
+
|
|
1139
|
+
@property
|
|
1140
|
+
def output_datatype(self):
|
|
1141
|
+
return self.output_data_type
|
|
1152
1142
|
|
|
1153
1143
|
@property
|
|
1154
1144
|
def concept_arguments(self) -> List[BuildConcept]:
|
|
@@ -1161,17 +1151,18 @@ class BuildFunction(DataTyped, BuildConceptArgs, BaseModel):
|
|
|
1161
1151
|
def output_grain(self):
|
|
1162
1152
|
# aggregates have an abstract grain
|
|
1163
1153
|
if self.operator in FunctionClass.AGGREGATE_FUNCTIONS.value:
|
|
1164
|
-
return BuildGrain
|
|
1154
|
+
return BuildGrain(components=[])
|
|
1165
1155
|
# scalars have implicit grain of all arguments
|
|
1166
1156
|
args = set()
|
|
1167
1157
|
for input in self.concept_arguments:
|
|
1168
1158
|
args += input.grain.components
|
|
1169
|
-
return BuildGrain
|
|
1159
|
+
return BuildGrain(components=args)
|
|
1170
1160
|
|
|
1171
1161
|
|
|
1172
|
-
|
|
1162
|
+
@dataclass
|
|
1163
|
+
class BuildAggregateWrapper(BuildConceptArgs, DataTyped):
|
|
1173
1164
|
function: BuildFunction
|
|
1174
|
-
by: List[BuildConcept] =
|
|
1165
|
+
by: List[BuildConcept] = field(default_factory=list)
|
|
1175
1166
|
|
|
1176
1167
|
def __str__(self):
|
|
1177
1168
|
grain_str = [str(c) for c in self.by] if self.by else "abstract"
|
|
@@ -1194,7 +1185,8 @@ class BuildAggregateWrapper(BuildConceptArgs, DataTyped, BaseModel):
|
|
|
1194
1185
|
return self.function.output_purpose
|
|
1195
1186
|
|
|
1196
1187
|
|
|
1197
|
-
|
|
1188
|
+
@dataclass
|
|
1189
|
+
class BuildFilterItem(BuildConceptArgs):
|
|
1198
1190
|
content: "BuildExpr"
|
|
1199
1191
|
where: BuildWhereClause
|
|
1200
1192
|
|
|
@@ -1226,13 +1218,15 @@ class BuildFilterItem(BuildConceptArgs, BaseModel):
|
|
|
1226
1218
|
return self.where.concept_arguments
|
|
1227
1219
|
|
|
1228
1220
|
|
|
1229
|
-
|
|
1221
|
+
@dataclass
|
|
1222
|
+
class BuildRowsetLineage(BuildConceptArgs):
|
|
1230
1223
|
name: str
|
|
1231
1224
|
derived_concepts: List[str]
|
|
1232
1225
|
select: SelectLineage | MultiSelectLineage
|
|
1233
1226
|
|
|
1234
1227
|
|
|
1235
|
-
|
|
1228
|
+
@dataclass
|
|
1229
|
+
class BuildRowsetItem(DataTyped, BuildConceptArgs):
|
|
1236
1230
|
content: BuildConcept
|
|
1237
1231
|
rowset: BuildRowsetLineage
|
|
1238
1232
|
|
|
@@ -1259,7 +1253,8 @@ class BuildRowsetItem(DataTyped, BuildConceptArgs, BaseModel):
|
|
|
1259
1253
|
return [self.content]
|
|
1260
1254
|
|
|
1261
1255
|
|
|
1262
|
-
|
|
1256
|
+
@dataclass
|
|
1257
|
+
class BuildOrderBy:
|
|
1263
1258
|
items: List[BuildOrderItem]
|
|
1264
1259
|
|
|
1265
1260
|
@property
|
|
@@ -1267,39 +1262,42 @@ class BuildOrderBy(BaseModel):
|
|
|
1267
1262
|
return [x.expr for x in self.items]
|
|
1268
1263
|
|
|
1269
1264
|
|
|
1270
|
-
|
|
1265
|
+
@dataclass
|
|
1266
|
+
class BuildAlignClause:
|
|
1271
1267
|
items: List[BuildAlignItem]
|
|
1272
1268
|
|
|
1273
1269
|
|
|
1274
|
-
|
|
1270
|
+
@dataclass
|
|
1271
|
+
class BuildSelectLineage:
|
|
1275
1272
|
selection: List[BuildConcept]
|
|
1276
1273
|
hidden_components: set[str]
|
|
1277
1274
|
local_concepts: dict[str, BuildConcept]
|
|
1278
1275
|
order_by: Optional[BuildOrderBy] = None
|
|
1279
1276
|
limit: Optional[int] = None
|
|
1280
|
-
meta: Metadata =
|
|
1281
|
-
grain: BuildGrain =
|
|
1282
|
-
where_clause: BuildWhereClause | None =
|
|
1283
|
-
having_clause: BuildHavingClause | None =
|
|
1277
|
+
meta: Metadata = field(default_factory=lambda: Metadata())
|
|
1278
|
+
grain: BuildGrain = field(default_factory=BuildGrain)
|
|
1279
|
+
where_clause: BuildWhereClause | None = field(default=None)
|
|
1280
|
+
having_clause: BuildHavingClause | None = field(default=None)
|
|
1284
1281
|
|
|
1285
1282
|
@property
|
|
1286
1283
|
def output_components(self) -> List[BuildConcept]:
|
|
1287
1284
|
return self.selection
|
|
1288
1285
|
|
|
1289
1286
|
|
|
1290
|
-
|
|
1287
|
+
@dataclass
|
|
1288
|
+
class BuildMultiSelectLineage(BuildConceptArgs):
|
|
1291
1289
|
selects: List[SelectLineage]
|
|
1292
1290
|
grain: BuildGrain
|
|
1293
1291
|
align: BuildAlignClause
|
|
1294
1292
|
namespace: str
|
|
1295
|
-
order_by: Optional[BuildOrderBy] = None
|
|
1296
|
-
limit: Optional[int] = None
|
|
1297
|
-
where_clause: Union["BuildWhereClause", None] = Field(default=None)
|
|
1298
|
-
having_clause: Union["BuildHavingClause", None] = Field(default=None)
|
|
1299
1293
|
local_concepts: dict[str, BuildConcept]
|
|
1300
1294
|
build_concept_arguments: list[BuildConcept]
|
|
1301
1295
|
build_output_components: list[BuildConcept]
|
|
1302
1296
|
hidden_components: set[str]
|
|
1297
|
+
order_by: Optional[BuildOrderBy] = None
|
|
1298
|
+
limit: Optional[int] = None
|
|
1299
|
+
where_clause: Union["BuildWhereClause", None] = field(default=None)
|
|
1300
|
+
having_clause: Union["BuildHavingClause", None] = field(default=None)
|
|
1303
1301
|
|
|
1304
1302
|
@property
|
|
1305
1303
|
def derived_concepts(self) -> set[str]:
|
|
@@ -1341,12 +1339,12 @@ class BuildMultiSelectLineage(BuildConceptArgs, BaseModel):
|
|
|
1341
1339
|
)
|
|
1342
1340
|
|
|
1343
1341
|
|
|
1344
|
-
|
|
1342
|
+
@dataclass
|
|
1343
|
+
class BuildAlignItem:
|
|
1345
1344
|
alias: str
|
|
1346
1345
|
concepts: List[BuildConcept]
|
|
1347
|
-
namespace: str =
|
|
1346
|
+
namespace: str = field(default=DEFAULT_NAMESPACE)
|
|
1348
1347
|
|
|
1349
|
-
@computed_field # type: ignore
|
|
1350
1348
|
@cached_property
|
|
1351
1349
|
def concepts_lcl(self) -> LooseBuildConceptList:
|
|
1352
1350
|
return LooseBuildConceptList(concepts=self.concepts)
|
|
@@ -1356,10 +1354,11 @@ class BuildAlignItem(BaseModel):
|
|
|
1356
1354
|
return f"{self.namespace}.{self.alias}"
|
|
1357
1355
|
|
|
1358
1356
|
|
|
1359
|
-
|
|
1360
|
-
|
|
1357
|
+
@dataclass
|
|
1358
|
+
class BuildColumnAssignment:
|
|
1359
|
+
alias: str | RawColumnExpr | BuildFunction | BuildAggregateWrapper
|
|
1361
1360
|
concept: BuildConcept
|
|
1362
|
-
modifiers: List[Modifier] =
|
|
1361
|
+
modifiers: List[Modifier] = field(default_factory=list)
|
|
1363
1362
|
|
|
1364
1363
|
@property
|
|
1365
1364
|
def is_complete(self) -> bool:
|
|
@@ -1370,15 +1369,16 @@ class BuildColumnAssignment(BaseModel):
|
|
|
1370
1369
|
return Modifier.NULLABLE in self.modifiers
|
|
1371
1370
|
|
|
1372
1371
|
|
|
1373
|
-
|
|
1372
|
+
@dataclass
|
|
1373
|
+
class BuildDatasource:
|
|
1374
1374
|
name: str
|
|
1375
1375
|
columns: List[BuildColumnAssignment]
|
|
1376
1376
|
address: Union[Address, str]
|
|
1377
|
-
grain: BuildGrain =
|
|
1378
|
-
default_factory=lambda: BuildGrain(components=set()),
|
|
1377
|
+
grain: BuildGrain = field(
|
|
1378
|
+
default_factory=lambda: BuildGrain(components=set()),
|
|
1379
1379
|
)
|
|
1380
|
-
namespace: Optional[str] =
|
|
1381
|
-
metadata: DatasourceMetadata =
|
|
1380
|
+
namespace: Optional[str] = field(default=DEFAULT_NAMESPACE)
|
|
1381
|
+
metadata: DatasourceMetadata = field(
|
|
1382
1382
|
default_factory=lambda: DatasourceMetadata(freshness_concept=None)
|
|
1383
1383
|
)
|
|
1384
1384
|
where: Optional[BuildWhereClause] = None
|
|
@@ -1447,7 +1447,7 @@ class BuildDatasource(BaseModel):
|
|
|
1447
1447
|
concept: BuildConcept,
|
|
1448
1448
|
use_raw_name: bool = True,
|
|
1449
1449
|
force_alias: bool = False,
|
|
1450
|
-
) -> Optional[str | RawColumnExpr] | BuildFunction:
|
|
1450
|
+
) -> Optional[str | RawColumnExpr] | BuildFunction | BuildAggregateWrapper:
|
|
1451
1451
|
# 2022-01-22
|
|
1452
1452
|
# this logic needs to be refined.
|
|
1453
1453
|
# if concept.lineage:
|
|
@@ -1491,8 +1491,6 @@ BuildExpr = (
|
|
|
1491
1491
|
| list
|
|
1492
1492
|
)
|
|
1493
1493
|
|
|
1494
|
-
BuildConcept.model_rebuild()
|
|
1495
|
-
|
|
1496
1494
|
|
|
1497
1495
|
def get_canonical_pseudonyms(environment: Environment) -> dict[str, set[str]]:
|
|
1498
1496
|
roots: dict[str, set[str]] = defaultdict(set)
|
|
@@ -1535,6 +1533,7 @@ class Factory:
|
|
|
1535
1533
|
)
|
|
1536
1534
|
self.local_non_build_concepts: dict[str, Concept] = {}
|
|
1537
1535
|
self.pseudonym_map = pseudonym_map or get_canonical_pseudonyms(environment)
|
|
1536
|
+
self.build_grain = self.build(self.grain) if self.grain else None
|
|
1538
1537
|
|
|
1539
1538
|
def instantiate_concept(
|
|
1540
1539
|
self,
|
|
@@ -1655,22 +1654,22 @@ class Factory:
|
|
|
1655
1654
|
)
|
|
1656
1655
|
)
|
|
1657
1656
|
|
|
1658
|
-
return BuildFunction
|
|
1657
|
+
return BuildFunction(
|
|
1659
1658
|
operator=base.operator,
|
|
1660
1659
|
arguments=[
|
|
1661
1660
|
rval,
|
|
1662
1661
|
*[self.handle_constant(self.build(c)) for c in raw_args[1:]],
|
|
1663
1662
|
],
|
|
1664
|
-
|
|
1663
|
+
output_data_type=base.output_datatype,
|
|
1665
1664
|
output_purpose=base.output_purpose,
|
|
1666
1665
|
valid_inputs=base.valid_inputs,
|
|
1667
1666
|
arg_count=base.arg_count,
|
|
1668
1667
|
)
|
|
1669
1668
|
|
|
1670
|
-
new = BuildFunction
|
|
1669
|
+
new = BuildFunction(
|
|
1671
1670
|
operator=base.operator,
|
|
1672
1671
|
arguments=[self.handle_constant(self.build(c)) for c in raw_args],
|
|
1673
|
-
|
|
1672
|
+
output_data_type=base.output_datatype,
|
|
1674
1673
|
output_purpose=base.output_purpose,
|
|
1675
1674
|
valid_inputs=base.valid_inputs,
|
|
1676
1675
|
arg_count=base.arg_count,
|
|
@@ -1702,7 +1701,7 @@ class Factory:
|
|
|
1702
1701
|
validation = requires_concept_nesting(expr)
|
|
1703
1702
|
if validation:
|
|
1704
1703
|
expr, _ = self.instantiate_concept(validation)
|
|
1705
|
-
return BuildCaseWhen
|
|
1704
|
+
return BuildCaseWhen(
|
|
1706
1705
|
comparison=self.build(comparison),
|
|
1707
1706
|
expr=self.build(expr),
|
|
1708
1707
|
)
|
|
@@ -1716,7 +1715,7 @@ class Factory:
|
|
|
1716
1715
|
validation = requires_concept_nesting(expr)
|
|
1717
1716
|
if validation:
|
|
1718
1717
|
expr, _ = self.instantiate_concept(validation)
|
|
1719
|
-
return BuildCaseElse
|
|
1718
|
+
return BuildCaseElse(expr=self.build(expr))
|
|
1720
1719
|
|
|
1721
1720
|
@build.register
|
|
1722
1721
|
def _(self, base: Concept) -> BuildConcept:
|
|
@@ -1751,7 +1750,7 @@ class Factory:
|
|
|
1751
1750
|
for x in self.pseudonym_map.get(base.address, set())
|
|
1752
1751
|
if x != base.address
|
|
1753
1752
|
}
|
|
1754
|
-
rval = BuildConcept
|
|
1753
|
+
rval = BuildConcept(
|
|
1755
1754
|
name=base.name,
|
|
1756
1755
|
datatype=base.datatype,
|
|
1757
1756
|
purpose=base.purpose,
|
|
@@ -1777,13 +1776,14 @@ class Factory:
|
|
|
1777
1776
|
def _build_aggregate_wrapper(self, base: AggregateWrapper) -> BuildAggregateWrapper:
|
|
1778
1777
|
if not base.by:
|
|
1779
1778
|
by = [
|
|
1780
|
-
self.
|
|
1779
|
+
self._build_concept(self.environment.concepts[c])
|
|
1780
|
+
for c in self.grain.components
|
|
1781
1781
|
]
|
|
1782
1782
|
else:
|
|
1783
1783
|
by = [self.build(x) for x in base.by]
|
|
1784
1784
|
|
|
1785
|
-
parent = self.
|
|
1786
|
-
return BuildAggregateWrapper
|
|
1785
|
+
parent: BuildFunction = self._build_function(base.function) # type: ignore
|
|
1786
|
+
return BuildAggregateWrapper(function=parent, by=by)
|
|
1787
1787
|
|
|
1788
1788
|
@build.register
|
|
1789
1789
|
def _(self, base: ColumnAssignment) -> BuildColumnAssignment:
|
|
@@ -1793,15 +1793,15 @@ class Factory:
|
|
|
1793
1793
|
address = base.concept.address
|
|
1794
1794
|
fetched = (
|
|
1795
1795
|
self._build_concept(
|
|
1796
|
-
self.environment.alias_origin_lookup[address]
|
|
1797
|
-
)
|
|
1796
|
+
self.environment.alias_origin_lookup[address]
|
|
1797
|
+
).with_grain(self.build_grain)
|
|
1798
1798
|
if address in self.environment.alias_origin_lookup
|
|
1799
|
-
else self._build_concept(
|
|
1800
|
-
self.
|
|
1799
|
+
else self._build_concept(self.environment.concepts[address]).with_grain(
|
|
1800
|
+
self.build_grain
|
|
1801
1801
|
)
|
|
1802
1802
|
)
|
|
1803
1803
|
|
|
1804
|
-
return BuildColumnAssignment
|
|
1804
|
+
return BuildColumnAssignment(
|
|
1805
1805
|
alias=(
|
|
1806
1806
|
self._build_function(base.alias)
|
|
1807
1807
|
if isinstance(base.alias, Function)
|
|
@@ -1816,7 +1816,7 @@ class Factory:
|
|
|
1816
1816
|
return self._build_order_by(base)
|
|
1817
1817
|
|
|
1818
1818
|
def _build_order_by(self, base: OrderBy) -> BuildOrderBy:
|
|
1819
|
-
return BuildOrderBy
|
|
1819
|
+
return BuildOrderBy(items=[self._build_order_item(x) for x in base.items])
|
|
1820
1820
|
|
|
1821
1821
|
@build.register
|
|
1822
1822
|
def _(self, base: FunctionCallWrapper) -> BuildExpr:
|
|
@@ -1838,7 +1838,7 @@ class Factory:
|
|
|
1838
1838
|
bexpr, _ = self.instantiate_concept(validation)
|
|
1839
1839
|
else:
|
|
1840
1840
|
bexpr = base.expr
|
|
1841
|
-
return BuildOrderItem
|
|
1841
|
+
return BuildOrderItem(
|
|
1842
1842
|
expr=(self.build(bexpr)),
|
|
1843
1843
|
order=base.order,
|
|
1844
1844
|
)
|
|
@@ -1848,18 +1848,14 @@ class Factory:
|
|
|
1848
1848
|
return self._build_where_clause(base)
|
|
1849
1849
|
|
|
1850
1850
|
def _build_where_clause(self, base: WhereClause) -> BuildWhereClause:
|
|
1851
|
-
return BuildWhereClause.
|
|
1852
|
-
conditional=self.build(base.conditional)
|
|
1853
|
-
)
|
|
1851
|
+
return BuildWhereClause(conditional=self.build(base.conditional))
|
|
1854
1852
|
|
|
1855
1853
|
@build.register
|
|
1856
1854
|
def _(self, base: HavingClause) -> BuildHavingClause:
|
|
1857
1855
|
return self._build_having_clause(base)
|
|
1858
1856
|
|
|
1859
1857
|
def _build_having_clause(self, base: HavingClause) -> BuildHavingClause:
|
|
1860
|
-
return BuildHavingClause.
|
|
1861
|
-
conditional=self.build(base.conditional)
|
|
1862
|
-
)
|
|
1858
|
+
return BuildHavingClause(conditional=self.build(base.conditional))
|
|
1863
1859
|
|
|
1864
1860
|
@build.register
|
|
1865
1861
|
def _(self, base: WindowItem) -> BuildWindowItem:
|
|
@@ -1879,11 +1875,11 @@ class Factory:
|
|
|
1879
1875
|
):
|
|
1880
1876
|
x.expr.by = [content]
|
|
1881
1877
|
final_by.append(x)
|
|
1882
|
-
return BuildWindowItem
|
|
1878
|
+
return BuildWindowItem(
|
|
1883
1879
|
type=base.type,
|
|
1884
1880
|
content=self.build(content),
|
|
1885
1881
|
order_by=[self.build(x) for x in final_by],
|
|
1886
|
-
over=[self.
|
|
1882
|
+
over=[self._build_concept_ref(x) for x in base.over],
|
|
1887
1883
|
index=base.index,
|
|
1888
1884
|
)
|
|
1889
1885
|
|
|
@@ -1892,7 +1888,7 @@ class Factory:
|
|
|
1892
1888
|
return self._build_conditional(base)
|
|
1893
1889
|
|
|
1894
1890
|
def _build_conditional(self, base: Conditional) -> BuildConditional:
|
|
1895
|
-
return BuildConditional
|
|
1891
|
+
return BuildConditional(
|
|
1896
1892
|
left=self.handle_constant(self.build(base.left)),
|
|
1897
1893
|
right=self.handle_constant(self.build(base.right)),
|
|
1898
1894
|
operator=base.operator,
|
|
@@ -1910,7 +1906,7 @@ class Factory:
|
|
|
1910
1906
|
if isinstance(base.right, (AggregateWrapper, WindowItem, FilterItem, Function)):
|
|
1911
1907
|
right_c, _ = self.instantiate_concept(base.right)
|
|
1912
1908
|
right = right_c
|
|
1913
|
-
return BuildSubselectComparison
|
|
1909
|
+
return BuildSubselectComparison(
|
|
1914
1910
|
left=self.handle_constant(self.build(base.left)),
|
|
1915
1911
|
right=self.handle_constant(self.build(right)),
|
|
1916
1912
|
operator=base.operator,
|
|
@@ -1931,7 +1927,7 @@ class Factory:
|
|
|
1931
1927
|
if validation:
|
|
1932
1928
|
right_c, _ = self.instantiate_concept(validation)
|
|
1933
1929
|
right = right_c # type: ignore
|
|
1934
|
-
return BuildComparison
|
|
1930
|
+
return BuildComparison(
|
|
1935
1931
|
left=self.handle_constant(self.build(left)),
|
|
1936
1932
|
right=self.handle_constant(self.build(right)),
|
|
1937
1933
|
operator=base.operator,
|
|
@@ -1942,9 +1938,9 @@ class Factory:
|
|
|
1942
1938
|
return self._build_align_item(base)
|
|
1943
1939
|
|
|
1944
1940
|
def _build_align_item(self, base: AlignItem) -> BuildAlignItem:
|
|
1945
|
-
return BuildAlignItem
|
|
1941
|
+
return BuildAlignItem(
|
|
1946
1942
|
alias=base.alias,
|
|
1947
|
-
concepts=[self.
|
|
1943
|
+
concepts=[self._build_concept_ref(x) for x in base.concepts],
|
|
1948
1944
|
namespace=base.namespace,
|
|
1949
1945
|
)
|
|
1950
1946
|
|
|
@@ -1953,9 +1949,7 @@ class Factory:
|
|
|
1953
1949
|
return self._build_align_clause(base)
|
|
1954
1950
|
|
|
1955
1951
|
def _build_align_clause(self, base: AlignClause) -> BuildAlignClause:
|
|
1956
|
-
return BuildAlignClause.
|
|
1957
|
-
items=[self.build(x) for x in base.items]
|
|
1958
|
-
)
|
|
1952
|
+
return BuildAlignClause(items=[self._build_align_item(x) for x in base.items])
|
|
1959
1953
|
|
|
1960
1954
|
@build.register
|
|
1961
1955
|
def _(self, base: RowsetItem) -> BuildRowsetItem:
|
|
@@ -1994,12 +1988,10 @@ class Factory:
|
|
|
1994
1988
|
factory = Factory(
|
|
1995
1989
|
environment=self.environment, pseudonym_map=self.pseudonym_map
|
|
1996
1990
|
)
|
|
1997
|
-
where = factory.
|
|
1991
|
+
where = factory._build_where_clause(base.where_clause)
|
|
1998
1992
|
else:
|
|
1999
1993
|
where = None
|
|
2000
|
-
return BuildGrain.
|
|
2001
|
-
components=base.components, where_clause=where
|
|
2002
|
-
)
|
|
1994
|
+
return BuildGrain(components=base.components, where_clause=where)
|
|
2003
1995
|
|
|
2004
1996
|
@build.register
|
|
2005
1997
|
def _(self, base: TupleWrapper) -> TupleWrapper:
|
|
@@ -2017,10 +2009,8 @@ class Factory:
|
|
|
2017
2009
|
base.content, (Function, AggregateWrapper, WindowItem, FilterItem)
|
|
2018
2010
|
):
|
|
2019
2011
|
_, built = self.instantiate_concept(base.content)
|
|
2020
|
-
return BuildFilterItem.
|
|
2021
|
-
|
|
2022
|
-
)
|
|
2023
|
-
return BuildFilterItem.model_construct(
|
|
2012
|
+
return BuildFilterItem(content=built, where=self.build(base.where))
|
|
2013
|
+
return BuildFilterItem(
|
|
2024
2014
|
content=self.build(base.content), where=self.build(base.where)
|
|
2025
2015
|
)
|
|
2026
2016
|
|
|
@@ -2029,7 +2019,7 @@ class Factory:
|
|
|
2029
2019
|
return self._build_parenthetical(base)
|
|
2030
2020
|
|
|
2031
2021
|
def _build_parenthetical(self, base: Parenthetical) -> BuildParenthetical:
|
|
2032
|
-
return BuildParenthetical
|
|
2022
|
+
return BuildParenthetical(content=(self.build(base.content)))
|
|
2033
2023
|
|
|
2034
2024
|
@build.register
|
|
2035
2025
|
def _(self, base: SelectLineage) -> BuildSelectLineage:
|
|
@@ -2117,7 +2107,7 @@ class Factory:
|
|
|
2117
2107
|
derived_base = []
|
|
2118
2108
|
for k in base.derived_concepts:
|
|
2119
2109
|
base_concept = self.environment.concepts[k]
|
|
2120
|
-
x = BuildConcept
|
|
2110
|
+
x = BuildConcept(
|
|
2121
2111
|
name=base_concept.name,
|
|
2122
2112
|
datatype=base_concept.datatype,
|
|
2123
2113
|
purpose=base_concept.purpose,
|
|
@@ -2145,7 +2135,7 @@ class Factory:
|
|
|
2145
2135
|
where_factory = Factory(
|
|
2146
2136
|
environment=self.environment, pseudonym_map=self.pseudonym_map
|
|
2147
2137
|
)
|
|
2148
|
-
lineage = BuildMultiSelectLineage
|
|
2138
|
+
lineage = BuildMultiSelectLineage(
|
|
2149
2139
|
# we don't build selects here; they'll be built automatically in query discovery
|
|
2150
2140
|
selects=base.selects,
|
|
2151
2141
|
grain=final_grain,
|
|
@@ -2253,7 +2243,7 @@ class Factory:
|
|
|
2253
2243
|
local_concepts=local_cache,
|
|
2254
2244
|
pseudonym_map=self.pseudonym_map,
|
|
2255
2245
|
)
|
|
2256
|
-
return BuildDatasource
|
|
2246
|
+
return BuildDatasource(
|
|
2257
2247
|
name=base.name,
|
|
2258
2248
|
columns=[factory._build_column_assignment(c) for c in base.columns],
|
|
2259
2249
|
address=base.address,
|