pytrilogy 0.0.3.92__py3-none-any.whl → 0.0.3.93__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.

@@ -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
- class LooseBuildConceptList(BaseModel):
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
- class BuildParamaterizedConceptReference(DataTyped, BaseModel):
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
- class BuildGrain(BaseModel):
267
- components: set[str] = Field(default_factory=set)
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.model_construct(components=self.components)
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.model_construct(
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.model_construct(
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.model_construct(
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
- class BuildParenthetical(DataTyped, ConstantInlineable, BuildConceptArgs, BaseModel):
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
- class BuildConditional(BuildConceptArgs, ConstantInlineable, BaseModel):
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
- class BuildWhereClause(BuildConceptArgs, BaseModel):
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
- class BuildComparison(BuildConceptArgs, ConstantInlineable, BaseModel):
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
- class BuildConcept(Addressable, BuildConceptArgs, DataTyped, BaseModel):
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] = Field(default=DEFAULT_NAMESPACE, validate_default=True)
822
- metadata: Metadata = Field(
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 = Field(default=None, validate_default=True) # type: ignore
839
- modifiers: List[Modifier] = Field(default_factory=list) # type: ignore
840
- pseudonyms: set[str] = Field(default_factory=set)
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
- def duplicate(self) -> BuildConcept:
847
- return self.model_copy(deep=True)
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__.model_construct(
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__.model_construct(
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
- class BuildOrderItem(DataTyped, BuildConceptArgs, BaseModel):
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
- class BuildWindowItem(DataTyped, BuildConceptArgs, BaseModel):
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"] = Field(default_factory=list)
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
- class BuildCaseWhen(BuildConceptArgs, BaseModel):
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
- class BuildCaseElse(BuildConceptArgs, BaseModel):
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
- class BuildFunction(DataTyped, BuildConceptArgs, BaseModel):
1104
- # class BuildFunction(Function):
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.output_datatype
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.model_construct(components=[])
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.model_construct(components=args)
1159
+ return BuildGrain(components=args)
1170
1160
 
1171
1161
 
1172
- class BuildAggregateWrapper(BuildConceptArgs, DataTyped, BaseModel):
1162
+ @dataclass
1163
+ class BuildAggregateWrapper(BuildConceptArgs, DataTyped):
1173
1164
  function: BuildFunction
1174
- by: List[BuildConcept] = Field(default_factory=list)
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
- class BuildFilterItem(BuildConceptArgs, BaseModel):
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
- class BuildRowsetLineage(BuildConceptArgs, BaseModel):
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
- class BuildRowsetItem(DataTyped, BuildConceptArgs, BaseModel):
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
- class BuildOrderBy(BaseModel):
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
- class BuildAlignClause(BaseModel):
1265
+ @dataclass
1266
+ class BuildAlignClause:
1271
1267
  items: List[BuildAlignItem]
1272
1268
 
1273
1269
 
1274
- class BuildSelectLineage(BaseModel):
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 = Field(default_factory=lambda: Metadata())
1281
- grain: BuildGrain = Field(default_factory=BuildGrain)
1282
- where_clause: BuildWhereClause | None = Field(default=None)
1283
- having_clause: BuildHavingClause | None = Field(default=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
- class BuildMultiSelectLineage(BuildConceptArgs, BaseModel):
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
- class BuildAlignItem(BaseModel):
1342
+ @dataclass
1343
+ class BuildAlignItem:
1345
1344
  alias: str
1346
1345
  concepts: List[BuildConcept]
1347
- namespace: str = Field(default=DEFAULT_NAMESPACE, validate_default=True)
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
- class BuildColumnAssignment(BaseModel):
1360
- alias: str | RawColumnExpr | BuildFunction
1357
+ @dataclass
1358
+ class BuildColumnAssignment:
1359
+ alias: str | RawColumnExpr | BuildFunction | BuildAggregateWrapper
1361
1360
  concept: BuildConcept
1362
- modifiers: List[Modifier] = Field(default_factory=list)
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
- class BuildDatasource(BaseModel):
1372
+ @dataclass
1373
+ class BuildDatasource:
1374
1374
  name: str
1375
1375
  columns: List[BuildColumnAssignment]
1376
1376
  address: Union[Address, str]
1377
- grain: BuildGrain = Field(
1378
- default_factory=lambda: BuildGrain(components=set()), validate_default=True
1377
+ grain: BuildGrain = field(
1378
+ default_factory=lambda: BuildGrain(components=set()),
1379
1379
  )
1380
- namespace: Optional[str] = Field(default=DEFAULT_NAMESPACE, validate_default=True)
1381
- metadata: DatasourceMetadata = Field(
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)
@@ -1655,22 +1653,22 @@ class Factory:
1655
1653
  )
1656
1654
  )
1657
1655
 
1658
- return BuildFunction.model_construct(
1656
+ return BuildFunction(
1659
1657
  operator=base.operator,
1660
1658
  arguments=[
1661
1659
  rval,
1662
1660
  *[self.handle_constant(self.build(c)) for c in raw_args[1:]],
1663
1661
  ],
1664
- output_datatype=base.output_datatype,
1662
+ output_data_type=base.output_datatype,
1665
1663
  output_purpose=base.output_purpose,
1666
1664
  valid_inputs=base.valid_inputs,
1667
1665
  arg_count=base.arg_count,
1668
1666
  )
1669
1667
 
1670
- new = BuildFunction.model_construct(
1668
+ new = BuildFunction(
1671
1669
  operator=base.operator,
1672
1670
  arguments=[self.handle_constant(self.build(c)) for c in raw_args],
1673
- output_datatype=base.output_datatype,
1671
+ output_data_type=base.output_datatype,
1674
1672
  output_purpose=base.output_purpose,
1675
1673
  valid_inputs=base.valid_inputs,
1676
1674
  arg_count=base.arg_count,
@@ -1702,7 +1700,7 @@ class Factory:
1702
1700
  validation = requires_concept_nesting(expr)
1703
1701
  if validation:
1704
1702
  expr, _ = self.instantiate_concept(validation)
1705
- return BuildCaseWhen.model_construct(
1703
+ return BuildCaseWhen(
1706
1704
  comparison=self.build(comparison),
1707
1705
  expr=self.build(expr),
1708
1706
  )
@@ -1716,7 +1714,7 @@ class Factory:
1716
1714
  validation = requires_concept_nesting(expr)
1717
1715
  if validation:
1718
1716
  expr, _ = self.instantiate_concept(validation)
1719
- return BuildCaseElse.model_construct(expr=self.build(expr))
1717
+ return BuildCaseElse(expr=self.build(expr))
1720
1718
 
1721
1719
  @build.register
1722
1720
  def _(self, base: Concept) -> BuildConcept:
@@ -1751,7 +1749,7 @@ class Factory:
1751
1749
  for x in self.pseudonym_map.get(base.address, set())
1752
1750
  if x != base.address
1753
1751
  }
1754
- rval = BuildConcept.model_construct(
1752
+ rval = BuildConcept(
1755
1753
  name=base.name,
1756
1754
  datatype=base.datatype,
1757
1755
  purpose=base.purpose,
@@ -1777,13 +1775,14 @@ class Factory:
1777
1775
  def _build_aggregate_wrapper(self, base: AggregateWrapper) -> BuildAggregateWrapper:
1778
1776
  if not base.by:
1779
1777
  by = [
1780
- self.build(self.environment.concepts[c]) for c in self.grain.components
1778
+ self._build_concept(self.environment.concepts[c])
1779
+ for c in self.grain.components
1781
1780
  ]
1782
1781
  else:
1783
1782
  by = [self.build(x) for x in base.by]
1784
1783
 
1785
- parent = self.build(base.function)
1786
- return BuildAggregateWrapper.model_construct(function=parent, by=by)
1784
+ parent: BuildFunction = self._build_function(base.function) # type: ignore
1785
+ return BuildAggregateWrapper(function=parent, by=by)
1787
1786
 
1788
1787
  @build.register
1789
1788
  def _(self, base: ColumnAssignment) -> BuildColumnAssignment:
@@ -1801,7 +1800,7 @@ class Factory:
1801
1800
  )
1802
1801
  )
1803
1802
 
1804
- return BuildColumnAssignment.model_construct(
1803
+ return BuildColumnAssignment(
1805
1804
  alias=(
1806
1805
  self._build_function(base.alias)
1807
1806
  if isinstance(base.alias, Function)
@@ -1816,7 +1815,7 @@ class Factory:
1816
1815
  return self._build_order_by(base)
1817
1816
 
1818
1817
  def _build_order_by(self, base: OrderBy) -> BuildOrderBy:
1819
- return BuildOrderBy.model_construct(items=[self.build(x) for x in base.items])
1818
+ return BuildOrderBy(items=[self._build_order_item(x) for x in base.items])
1820
1819
 
1821
1820
  @build.register
1822
1821
  def _(self, base: FunctionCallWrapper) -> BuildExpr:
@@ -1838,7 +1837,7 @@ class Factory:
1838
1837
  bexpr, _ = self.instantiate_concept(validation)
1839
1838
  else:
1840
1839
  bexpr = base.expr
1841
- return BuildOrderItem.model_construct(
1840
+ return BuildOrderItem(
1842
1841
  expr=(self.build(bexpr)),
1843
1842
  order=base.order,
1844
1843
  )
@@ -1848,18 +1847,14 @@ class Factory:
1848
1847
  return self._build_where_clause(base)
1849
1848
 
1850
1849
  def _build_where_clause(self, base: WhereClause) -> BuildWhereClause:
1851
- return BuildWhereClause.model_construct(
1852
- conditional=self.build(base.conditional)
1853
- )
1850
+ return BuildWhereClause(conditional=self.build(base.conditional))
1854
1851
 
1855
1852
  @build.register
1856
1853
  def _(self, base: HavingClause) -> BuildHavingClause:
1857
1854
  return self._build_having_clause(base)
1858
1855
 
1859
1856
  def _build_having_clause(self, base: HavingClause) -> BuildHavingClause:
1860
- return BuildHavingClause.model_construct(
1861
- conditional=self.build(base.conditional)
1862
- )
1857
+ return BuildHavingClause(conditional=self.build(base.conditional))
1863
1858
 
1864
1859
  @build.register
1865
1860
  def _(self, base: WindowItem) -> BuildWindowItem:
@@ -1879,11 +1874,11 @@ class Factory:
1879
1874
  ):
1880
1875
  x.expr.by = [content]
1881
1876
  final_by.append(x)
1882
- return BuildWindowItem.model_construct(
1877
+ return BuildWindowItem(
1883
1878
  type=base.type,
1884
1879
  content=self.build(content),
1885
1880
  order_by=[self.build(x) for x in final_by],
1886
- over=[self.build(x) for x in base.over],
1881
+ over=[self._build_concept_ref(x) for x in base.over],
1887
1882
  index=base.index,
1888
1883
  )
1889
1884
 
@@ -1892,7 +1887,7 @@ class Factory:
1892
1887
  return self._build_conditional(base)
1893
1888
 
1894
1889
  def _build_conditional(self, base: Conditional) -> BuildConditional:
1895
- return BuildConditional.model_construct(
1890
+ return BuildConditional(
1896
1891
  left=self.handle_constant(self.build(base.left)),
1897
1892
  right=self.handle_constant(self.build(base.right)),
1898
1893
  operator=base.operator,
@@ -1910,7 +1905,7 @@ class Factory:
1910
1905
  if isinstance(base.right, (AggregateWrapper, WindowItem, FilterItem, Function)):
1911
1906
  right_c, _ = self.instantiate_concept(base.right)
1912
1907
  right = right_c
1913
- return BuildSubselectComparison.model_construct(
1908
+ return BuildSubselectComparison(
1914
1909
  left=self.handle_constant(self.build(base.left)),
1915
1910
  right=self.handle_constant(self.build(right)),
1916
1911
  operator=base.operator,
@@ -1931,7 +1926,7 @@ class Factory:
1931
1926
  if validation:
1932
1927
  right_c, _ = self.instantiate_concept(validation)
1933
1928
  right = right_c # type: ignore
1934
- return BuildComparison.model_construct(
1929
+ return BuildComparison(
1935
1930
  left=self.handle_constant(self.build(left)),
1936
1931
  right=self.handle_constant(self.build(right)),
1937
1932
  operator=base.operator,
@@ -1942,9 +1937,9 @@ class Factory:
1942
1937
  return self._build_align_item(base)
1943
1938
 
1944
1939
  def _build_align_item(self, base: AlignItem) -> BuildAlignItem:
1945
- return BuildAlignItem.model_construct(
1940
+ return BuildAlignItem(
1946
1941
  alias=base.alias,
1947
- concepts=[self.build(x) for x in base.concepts],
1942
+ concepts=[self._build_concept_ref(x) for x in base.concepts],
1948
1943
  namespace=base.namespace,
1949
1944
  )
1950
1945
 
@@ -1953,9 +1948,7 @@ class Factory:
1953
1948
  return self._build_align_clause(base)
1954
1949
 
1955
1950
  def _build_align_clause(self, base: AlignClause) -> BuildAlignClause:
1956
- return BuildAlignClause.model_construct(
1957
- items=[self.build(x) for x in base.items]
1958
- )
1951
+ return BuildAlignClause(items=[self._build_align_item(x) for x in base.items])
1959
1952
 
1960
1953
  @build.register
1961
1954
  def _(self, base: RowsetItem) -> BuildRowsetItem:
@@ -1994,12 +1987,10 @@ class Factory:
1994
1987
  factory = Factory(
1995
1988
  environment=self.environment, pseudonym_map=self.pseudonym_map
1996
1989
  )
1997
- where = factory.build(base.where_clause)
1990
+ where = factory._build_where_clause(base.where_clause)
1998
1991
  else:
1999
1992
  where = None
2000
- return BuildGrain.model_construct(
2001
- components=base.components, where_clause=where
2002
- )
1993
+ return BuildGrain(components=base.components, where_clause=where)
2003
1994
 
2004
1995
  @build.register
2005
1996
  def _(self, base: TupleWrapper) -> TupleWrapper:
@@ -2017,10 +2008,8 @@ class Factory:
2017
2008
  base.content, (Function, AggregateWrapper, WindowItem, FilterItem)
2018
2009
  ):
2019
2010
  _, built = self.instantiate_concept(base.content)
2020
- return BuildFilterItem.model_construct(
2021
- content=built, where=self.build(base.where)
2022
- )
2023
- return BuildFilterItem.model_construct(
2011
+ return BuildFilterItem(content=built, where=self.build(base.where))
2012
+ return BuildFilterItem(
2024
2013
  content=self.build(base.content), where=self.build(base.where)
2025
2014
  )
2026
2015
 
@@ -2029,7 +2018,7 @@ class Factory:
2029
2018
  return self._build_parenthetical(base)
2030
2019
 
2031
2020
  def _build_parenthetical(self, base: Parenthetical) -> BuildParenthetical:
2032
- return BuildParenthetical.model_construct(content=(self.build(base.content)))
2021
+ return BuildParenthetical(content=(self.build(base.content)))
2033
2022
 
2034
2023
  @build.register
2035
2024
  def _(self, base: SelectLineage) -> BuildSelectLineage:
@@ -2117,7 +2106,7 @@ class Factory:
2117
2106
  derived_base = []
2118
2107
  for k in base.derived_concepts:
2119
2108
  base_concept = self.environment.concepts[k]
2120
- x = BuildConcept.model_construct(
2109
+ x = BuildConcept(
2121
2110
  name=base_concept.name,
2122
2111
  datatype=base_concept.datatype,
2123
2112
  purpose=base_concept.purpose,
@@ -2145,7 +2134,7 @@ class Factory:
2145
2134
  where_factory = Factory(
2146
2135
  environment=self.environment, pseudonym_map=self.pseudonym_map
2147
2136
  )
2148
- lineage = BuildMultiSelectLineage.model_construct(
2137
+ lineage = BuildMultiSelectLineage(
2149
2138
  # we don't build selects here; they'll be built automatically in query discovery
2150
2139
  selects=base.selects,
2151
2140
  grain=final_grain,
@@ -2253,7 +2242,7 @@ class Factory:
2253
2242
  local_concepts=local_cache,
2254
2243
  pseudonym_map=self.pseudonym_map,
2255
2244
  )
2256
- return BuildDatasource.model_construct(
2245
+ return BuildDatasource(
2257
2246
  name=base.name,
2258
2247
  columns=[factory._build_column_assignment(c) for c in base.columns],
2259
2248
  address=base.address,