sera-2 1.16.0__py3-none-any.whl → 1.17.0__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.
- sera/exports/schema.py +14 -0
- sera/make/make_python_model.py +38 -4
- sera/models/_parse.py +1 -0
- sera/models/_property.py +6 -0
- sera/typing.py +1 -0
- {sera_2-1.16.0.dist-info → sera_2-1.17.0.dist-info}/METADATA +1 -1
- {sera_2-1.16.0.dist-info → sera_2-1.17.0.dist-info}/RECORD +8 -8
- {sera_2-1.16.0.dist-info → sera_2-1.17.0.dist-info}/WHEEL +0 -0
sera/exports/schema.py
CHANGED
@@ -54,6 +54,20 @@ def export_tbls(schema: Schema, outfile: Path):
|
|
54
54
|
"columns": [prop.name],
|
55
55
|
}
|
56
56
|
)
|
57
|
+
|
58
|
+
if prop.db.foreign_key is not None:
|
59
|
+
idprop = assert_not_null(prop.db.foreign_key.get_id_property())
|
60
|
+
out["relations"].append(
|
61
|
+
{
|
62
|
+
"table": cls.name,
|
63
|
+
"columns": [prop.name],
|
64
|
+
"cardinality": "zero_or_one",
|
65
|
+
"parent_table": prop.db.foreign_key.name,
|
66
|
+
"parent_columns": [idprop_name],
|
67
|
+
"parent_cardinality": "zero_or_one",
|
68
|
+
"def": f"FOREIGN KEY ({prop.name}) REFERENCES {prop.db.foreign_key.name}({idprop_name})",
|
69
|
+
}
|
70
|
+
)
|
57
71
|
else:
|
58
72
|
if prop.cardinality == Cardinality.MANY_TO_MANY:
|
59
73
|
# For many-to-many relationships, we need to create a join table
|
sera/make/make_python_model.py
CHANGED
@@ -1079,12 +1079,10 @@ def make_python_relational_model(
|
|
1079
1079
|
|
1080
1080
|
target_pkg.module("base").write(program)
|
1081
1081
|
|
1082
|
-
|
1083
|
-
|
1084
|
-
for cls in schema.topological_sort():
|
1082
|
+
def make_orm(cls: Class):
|
1085
1083
|
if cls.db is None or cls.name in reference_classes:
|
1086
1084
|
# skip classes that are not stored in the database
|
1087
|
-
|
1085
|
+
return
|
1088
1086
|
|
1089
1087
|
program = Program()
|
1090
1088
|
program.import_("__future__.annotations", True)
|
@@ -1093,6 +1091,11 @@ def make_python_relational_model(
|
|
1093
1091
|
program.import_("sqlalchemy.orm.Mapped", True)
|
1094
1092
|
program.import_(f"{target_pkg.path}.base.Base", True)
|
1095
1093
|
|
1094
|
+
ident_manager = ImportHelper(
|
1095
|
+
program,
|
1096
|
+
GLOBAL_IDENTS,
|
1097
|
+
)
|
1098
|
+
|
1096
1099
|
index_stmts = []
|
1097
1100
|
if len(cls.db.indices) > 0:
|
1098
1101
|
program.import_("sqlalchemy.Index", True)
|
@@ -1159,6 +1162,32 @@ def make_python_relational_model(
|
|
1159
1162
|
proptype = f"Mapped[{sqltype.mapped_pytype}]"
|
1160
1163
|
|
1161
1164
|
propvalargs: list[expr.Expr] = [expr.ExprIdent(sqltype.type)]
|
1165
|
+
if prop.db.foreign_key is not None:
|
1166
|
+
assert (
|
1167
|
+
prop.db.foreign_key.db is not None
|
1168
|
+
), f"Foreign key {prop.db.foreign_key.name} must have a database mapping"
|
1169
|
+
foreign_key_idprop = prop.db.foreign_key.get_id_property()
|
1170
|
+
assert (
|
1171
|
+
foreign_key_idprop is not None
|
1172
|
+
), f"Foreign key {prop.db.foreign_key.name} must have an id property"
|
1173
|
+
propvalargs.append(
|
1174
|
+
expr.ExprFuncCall(
|
1175
|
+
ident_manager.use("ForeignKey"),
|
1176
|
+
[
|
1177
|
+
expr.ExprConstant(
|
1178
|
+
f"{prop.db.foreign_key.db.table_name}.{foreign_key_idprop.name}"
|
1179
|
+
),
|
1180
|
+
PredefinedFn.keyword_assignment(
|
1181
|
+
"ondelete",
|
1182
|
+
expr.ExprConstant("CASCADE"),
|
1183
|
+
),
|
1184
|
+
PredefinedFn.keyword_assignment(
|
1185
|
+
"onupdate",
|
1186
|
+
expr.ExprConstant("CASCADE"),
|
1187
|
+
),
|
1188
|
+
],
|
1189
|
+
)
|
1190
|
+
)
|
1162
1191
|
if prop.db.is_primary_key:
|
1163
1192
|
propvalargs.append(
|
1164
1193
|
PredefinedFn.keyword_assignment(
|
@@ -1208,6 +1237,11 @@ def make_python_relational_model(
|
|
1208
1237
|
|
1209
1238
|
target_pkg.module(cls.get_pymodule_name()).write(program)
|
1210
1239
|
|
1240
|
+
custom_types: list[ObjectProperty] = []
|
1241
|
+
|
1242
|
+
for cls in schema.topological_sort():
|
1243
|
+
make_orm(cls)
|
1244
|
+
|
1211
1245
|
# make a base class that implements the mapping for custom types
|
1212
1246
|
custom_types = filter_duplication(
|
1213
1247
|
custom_types, lambda p: (p.target.name, p.cardinality, p.is_optional, p.is_map)
|
sera/models/_parse.py
CHANGED
sera/models/_property.py
CHANGED
@@ -150,6 +150,12 @@ class DataPropDBInfo:
|
|
150
150
|
is_unique: bool = False
|
151
151
|
# whether this property is indexed or not
|
152
152
|
is_indexed: bool = False
|
153
|
+
# this is used in conjunction with is_primary_key = True for the case of
|
154
|
+
# extending a table with frequently updated properties. The value for the `foreign_key`
|
155
|
+
# will be a target class. The cardinality is one-to-one, on target class deletion,
|
156
|
+
# this class will be deleted as well (because it's an extended table of the target class).
|
157
|
+
# on source (this class) deletion, the target class will not be deleted.
|
158
|
+
foreign_key: Optional[Class] = None
|
153
159
|
|
154
160
|
|
155
161
|
@dataclass(kw_only=True)
|
sera/typing.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
sera/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
2
|
sera/constants.py,sha256=mzAaMyIx8TJK0-RYYJ5I24C4s0Uvj26OLMJmBo0pxHI,123
|
3
3
|
sera/exports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
-
sera/exports/schema.py,sha256=
|
4
|
+
sera/exports/schema.py,sha256=wEBUrDOyuCoCJC8X4RlmoWpeqSugaboG-9Q1UQ8HEzk,7824
|
5
5
|
sera/exports/test.py,sha256=jK1EJmLGiy7eREpnY_68IIVRH43uH8S_u5Z7STPbXOM,2002
|
6
6
|
sera/libs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
7
|
sera/libs/api_helper.py,sha256=47y1kcwk3Xd2ZEMnUj_0OwCuUmgwOs5kYrE95BDVUn4,5411
|
@@ -17,7 +17,7 @@ sera/make/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
sera/make/__main__.py,sha256=HRfOR53p351h6KblVvYm3DLhDIfEtk6R0kjl78_S_S8,1453
|
18
18
|
sera/make/make_app.py,sha256=n9NtW73O3s_5Q31VHIRmnd-jEIcpDO7ksAsOdovde2s,5999
|
19
19
|
sera/make/make_python_api.py,sha256=iXGbKQ3IJvsY1ur_fhurr_THFNnH66E3Wl85o0emUbw,26853
|
20
|
-
sera/make/make_python_model.py,sha256=
|
20
|
+
sera/make/make_python_model.py,sha256=Nc4vDGgM8icgWBqzNnMgEkLadf5EsZwbbHs3WLW9_co,62778
|
21
21
|
sera/make/make_python_services.py,sha256=0ZpWLwQ7Nwfn8BXAikAB4JRpNknpSJyJgY5b1cjtxV4,2073
|
22
22
|
sera/make/make_typescript_model.py,sha256=1ouYFCeqOlwEzsGBiXUn4VZtLJjJW7GSacdOSlQzhjI,67012
|
23
23
|
sera/misc/__init__.py,sha256=mPKkik00j3tO_m45VPDJBjm8K85NpymRPl36Kh4hBn8,473
|
@@ -32,10 +32,10 @@ sera/models/_default.py,sha256=ABggW6qdPR4ZDqIPJdJ0GCGQ-7kfsfZmQ_DchgZEa-I,137
|
|
32
32
|
sera/models/_enum.py,sha256=sy0q7E646F-APsqrVQ52r1fAQ_DCAeaNq5YM5QN3zIk,2070
|
33
33
|
sera/models/_module.py,sha256=I-GfnTgAa-5R87qTAvEzOt-VVEGeFBBwubGCgUkXVSw,5159
|
34
34
|
sera/models/_multi_lingual_string.py,sha256=JETN6k00VH4wrA4w5vAHMEJV8fp3SY9bJebskFTjQLA,1186
|
35
|
-
sera/models/_parse.py,sha256=
|
36
|
-
sera/models/_property.py,sha256=
|
35
|
+
sera/models/_parse.py,sha256=ciTLzCkO0q6xA1R_rHbnYJYK3Duo2oh56WeuwxXwJaI,12392
|
36
|
+
sera/models/_property.py,sha256=9yMDxrmbyuF6-29lQjiq163Xzwbk75TlmGBpu0NLpkI,7485
|
37
37
|
sera/models/_schema.py,sha256=VxJEiqgVvbXgcSUK4UW6JnRcggk4nsooVSE6MyXmfNY,1636
|
38
|
-
sera/typing.py,sha256=
|
39
|
-
sera_2-1.
|
40
|
-
sera_2-1.
|
41
|
-
sera_2-1.
|
38
|
+
sera/typing.py,sha256=o_DKfSvs8JpNRQ0kdaTc3BbfdkvibY3uY4tJRt-n2fQ,1023
|
39
|
+
sera_2-1.17.0.dist-info/METADATA,sha256=aIaXid2dkyX8P9nty-1eFHFBuH0Cpy34vOGDi1wTFkI,852
|
40
|
+
sera_2-1.17.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
41
|
+
sera_2-1.17.0.dist-info/RECORD,,
|
File without changes
|