sera-2 1.7.0__py3-none-any.whl → 1.7.2__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/libs/dag/__init__.py +0 -0
- sera/libs/dag/_dag.py +0 -0
- sera/make/make_typescript_model.py +91 -2
- sera/models/_datatype.py +12 -1
- {sera_2-1.7.0.dist-info → sera_2-1.7.2.dist-info}/METADATA +1 -1
- {sera_2-1.7.0.dist-info → sera_2-1.7.2.dist-info}/RECORD +7 -5
- {sera_2-1.7.0.dist-info → sera_2-1.7.2.dist-info}/WHEEL +0 -0
File without changes
|
sera/libs/dag/_dag.py
ADDED
File without changes
|
@@ -1,10 +1,12 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
import re
|
3
4
|
from typing import Any, Callable
|
4
5
|
|
5
6
|
from codegen.models import AST, PredefinedFn, Program, expr, stmt
|
6
7
|
from codegen.models.var import DeferredVar
|
7
8
|
from loguru import logger
|
9
|
+
|
8
10
|
from sera.misc import (
|
9
11
|
assert_isinstance,
|
10
12
|
assert_not_null,
|
@@ -239,8 +241,15 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
|
|
239
241
|
program.import_("mobx.makeObservable", True)
|
240
242
|
program.import_("mobx.observable", True)
|
241
243
|
program.import_("mobx.action", True)
|
244
|
+
program.import_("sera-db.validators", True)
|
242
245
|
|
243
|
-
program.root
|
246
|
+
program.root(
|
247
|
+
stmt.LineBreak(),
|
248
|
+
stmt.TypescriptStatement(
|
249
|
+
"const {getValidator, memoizeOneValidators} = validators;"
|
250
|
+
),
|
251
|
+
stmt.LineBreak(),
|
252
|
+
)
|
244
253
|
|
245
254
|
# make sure that the property stale is not in existing properties
|
246
255
|
if "stale" in cls.properties:
|
@@ -250,6 +259,7 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
|
|
250
259
|
cls_pk = None
|
251
260
|
observable_args: list[tuple[expr.Expr, expr.ExprIdent]] = []
|
252
261
|
prop_defs = []
|
262
|
+
prop_validators = []
|
253
263
|
prop_constructor_assigns = []
|
254
264
|
# attrs needed for the cls.create function
|
255
265
|
create_args = []
|
@@ -307,6 +317,10 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
|
|
307
317
|
f"{cls.name}Id",
|
308
318
|
dep=f"@.models.{pkg.dir.name}.{cls.name}.{cls.name}Id",
|
309
319
|
)
|
320
|
+
else:
|
321
|
+
# for none id properties, we need to include a type for "invalid" value
|
322
|
+
tstype = _inject_type_for_invalid_value(tstype)
|
323
|
+
|
310
324
|
if tstype.dep is not None:
|
311
325
|
program.import_(tstype.dep, True)
|
312
326
|
|
@@ -324,6 +338,25 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
|
|
324
338
|
else:
|
325
339
|
create_propvalue = tstype.get_default()
|
326
340
|
|
341
|
+
prop_validators.append(
|
342
|
+
(
|
343
|
+
expr.ExprIdent(propname),
|
344
|
+
expr.ExprFuncCall(
|
345
|
+
expr.ExprIdent("getValidator"),
|
346
|
+
[
|
347
|
+
PredefinedFn.list(
|
348
|
+
[
|
349
|
+
expr.ExprConstant(
|
350
|
+
constraint.get_typescript_constraint()
|
351
|
+
)
|
352
|
+
for constraint in prop.data.constraints
|
353
|
+
]
|
354
|
+
),
|
355
|
+
],
|
356
|
+
),
|
357
|
+
)
|
358
|
+
)
|
359
|
+
|
327
360
|
if prop.db is not None and prop.db.is_primary_key:
|
328
361
|
# for checking if the primary key is from the database or default (create_propvalue)
|
329
362
|
cls_pk = (expr.ExprIdent(propname), create_propvalue)
|
@@ -524,6 +557,10 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
|
|
524
557
|
)
|
525
558
|
observable_args.sort(key=lambda x: {"observable": 0, "action": 1}[x[1].ident])
|
526
559
|
|
560
|
+
validators = expr.ExprFuncCall(
|
561
|
+
expr.ExprIdent("memoizeOneValidators"), [PredefinedFn.dict(prop_validators)]
|
562
|
+
)
|
563
|
+
|
527
564
|
program.root(
|
528
565
|
lambda ast00: ast00.class_like(
|
529
566
|
"interface",
|
@@ -533,6 +570,10 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
|
|
533
570
|
lambda ast10: ast10.class_(draft_clsname)(
|
534
571
|
*prop_defs,
|
535
572
|
stmt.LineBreak(),
|
573
|
+
stmt.DefClassVarStatement(
|
574
|
+
"validators", type=None, value=validators, is_static=True
|
575
|
+
),
|
576
|
+
stmt.LineBreak(),
|
536
577
|
lambda ast10: ast10.func(
|
537
578
|
"constructor",
|
538
579
|
[
|
@@ -822,7 +863,10 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
|
|
822
863
|
[
|
823
864
|
(expr.ExprIdent("name"), expr.ExprConstant(prop.name)),
|
824
865
|
(expr.ExprIdent("tsName"), expr.ExprConstant(propname)),
|
825
|
-
(
|
866
|
+
(
|
867
|
+
expr.ExprIdent("updateFuncName"),
|
868
|
+
expr.ExprConstant(f"update{to_pascal_case(prop.name)}"),
|
869
|
+
),
|
826
870
|
(
|
827
871
|
expr.ExprIdent("label"),
|
828
872
|
expr.ExprConstant(prop.label.to_dict()),
|
@@ -1069,3 +1113,48 @@ def make_typescript_enum(schema: Schema, target_pkg: Package):
|
|
1069
1113
|
),
|
1070
1114
|
)
|
1071
1115
|
enum_pkg.module("index").write(program)
|
1116
|
+
|
1117
|
+
|
1118
|
+
def _inject_type_for_invalid_value(tstype: TsTypeWithDep) -> TsTypeWithDep:
|
1119
|
+
"""
|
1120
|
+
Inject a type for "invalid" values into the given TypeScript type. For context, see the discussion in Data Modeling Problems:
|
1121
|
+
What would be an appropriate type for an invalid value? Since it's user input, it will be a string type.
|
1122
|
+
|
1123
|
+
However, there are some exceptions such as boolean type, which will always be valid and do not need injection.
|
1124
|
+
|
1125
|
+
If the type already includes `string` type, no changes are needed. Otherwise, we add `string` to the type. For example:
|
1126
|
+
- (number | undefined) -> (number | undefined | string)
|
1127
|
+
- number | undefined -> number | undefined | string
|
1128
|
+
- number[] -> (number | string)[]
|
1129
|
+
- (number | undefined)[] -> (number | undefined | string)[]
|
1130
|
+
"""
|
1131
|
+
if tstype.type == "boolean":
|
1132
|
+
return tstype
|
1133
|
+
|
1134
|
+
# TODO: fix me and make it more robust!
|
1135
|
+
m = re.match(r"(\(?[a-zA-Z \|]+\)?)(\[\])", tstype.type)
|
1136
|
+
if m is not None:
|
1137
|
+
# This is an array type, add string to the inner type
|
1138
|
+
inner_type = m.group(1)
|
1139
|
+
if "string" not in inner_type:
|
1140
|
+
if inner_type.startswith("(") and inner_type.endswith(")"):
|
1141
|
+
# Already has parentheses
|
1142
|
+
inner_type = f"{inner_type[:-1]} | string)"
|
1143
|
+
else:
|
1144
|
+
# Need to add parentheses
|
1145
|
+
inner_type = f"({inner_type} | string)"
|
1146
|
+
return TsTypeWithDep(inner_type + "[]", tstype.dep)
|
1147
|
+
|
1148
|
+
m = re.match(r"^\(?[a-zA-Z \|]+\)?$", tstype.type)
|
1149
|
+
if m is not None:
|
1150
|
+
if "string" not in tstype.type:
|
1151
|
+
if tstype.type.startswith("(") and tstype.type.endswith(")"):
|
1152
|
+
# Already has parentheses
|
1153
|
+
new_type = f"{tstype.type[:-1]} | string)"
|
1154
|
+
else:
|
1155
|
+
# Needs parentheses for clarity
|
1156
|
+
new_type = f"({tstype.type} | string)"
|
1157
|
+
return TsTypeWithDep(new_type, tstype.dep)
|
1158
|
+
return tstype
|
1159
|
+
|
1160
|
+
raise NotImplementedError(tstype.type)
|
sera/models/_datatype.py
CHANGED
@@ -69,10 +69,21 @@ class TsTypeWithDep:
|
|
69
69
|
return expr.ExprConstant(False)
|
70
70
|
if self.type == "string | undefined":
|
71
71
|
return expr.ExprConstant("undefined")
|
72
|
+
if self.type.endswith("| string)") or self.type.endswith("| string"):
|
73
|
+
return expr.ExprConstant("")
|
72
74
|
raise ValueError(f"Unknown type: {self.type}")
|
73
75
|
|
74
76
|
def as_list_type(self) -> TsTypeWithDep:
|
75
|
-
|
77
|
+
"""Convert the type to a list type.
|
78
|
+
If the type is not a simple identifier, wrap it in parentheses.
|
79
|
+
"""
|
80
|
+
# Check if type is a simple identifier or needs parentheses
|
81
|
+
if not all(c.isalnum() or c == "_" for c in self.type.strip()):
|
82
|
+
# Type contains special chars like | or spaces, wrap in parentheses
|
83
|
+
list_type = f"({self.type})[]"
|
84
|
+
else:
|
85
|
+
list_type = f"{self.type}[]"
|
86
|
+
return TsTypeWithDep(type=list_type, dep=self.dep)
|
76
87
|
|
77
88
|
|
78
89
|
@dataclass
|
@@ -4,13 +4,15 @@ sera/libs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
sera/libs/api_helper.py,sha256=hUEy0INHM18lxTQ348tgbXNceOHcjiAnqmuL_8CRpLQ,2509
|
5
5
|
sera/libs/base_orm.py,sha256=dyh0OT2sbHku5qPJXvRzYAHRTSXvvbQaS-Qwg65Bw04,2918
|
6
6
|
sera/libs/base_service.py,sha256=l5D4IjxIiz8LBRranUYddb8J0Y6SwSyetKYTLrCUdQA,4098
|
7
|
+
sera/libs/dag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
+
sera/libs/dag/_dag.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
9
|
sera/make/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
10
|
sera/make/__main__.py,sha256=G5O7s6135-708honwqMFn2yPTs06WbGQTHpupID0eZ4,1417
|
9
11
|
sera/make/make_app.py,sha256=n9NtW73O3s_5Q31VHIRmnd-jEIcpDO7ksAsOdovde2s,5999
|
10
12
|
sera/make/make_python_api.py,sha256=RuJUm9z-4plBEtjobeOPr12o27OT-0tSeXI4ZlM3IY0,29433
|
11
13
|
sera/make/make_python_model.py,sha256=xf4revAwVWEnF6QhxbbqPyUGgXOOB--Gu3jPxsESg0Y,36593
|
12
14
|
sera/make/make_python_services.py,sha256=RsinYZdfkrTlTn9CT50VgqGs9w6IZawsJx-KEmqfnEY,2062
|
13
|
-
sera/make/make_typescript_model.py,sha256=
|
15
|
+
sera/make/make_typescript_model.py,sha256=27lk4YgfJ6_7xxBirxJKgK0-wBNowMWZkvcMUFdmStE,46865
|
14
16
|
sera/misc/__init__.py,sha256=Dh4uDq0D4N53h3zhvmwfa5a0TPVRSUvLzb0hkFuPirk,411
|
15
17
|
sera/misc/_formatter.py,sha256=aCGYL08l8f3aLODHxSocxBBwkRYEo3K1QzCDEn3suj0,1685
|
16
18
|
sera/misc/_utils.py,sha256=V5g4oLGHOhUCR75Kkcn1w01pAvGvaepK-T8Z3pIgHjI,1450
|
@@ -18,7 +20,7 @@ sera/models/__init__.py,sha256=vJC5Kzo_N7wd16ocNPy1VvAZDGNiWeiAhWJ4ihATKvA,780
|
|
18
20
|
sera/models/_class.py,sha256=Wf0e8x6-szG9TzoFkAlqj7_dG0SCICMBw_333n3paxk,2514
|
19
21
|
sera/models/_collection.py,sha256=ZnQEriKC4X88Zz48Kn1AVZKH-1_l8OgWa-zf2kcQOOE,1414
|
20
22
|
sera/models/_constraints.py,sha256=L6QwKL3hRJ5DvvIB4JNgLoyvTKbE9FrpYRzezM4CweE,1484
|
21
|
-
sera/models/_datatype.py,sha256=
|
23
|
+
sera/models/_datatype.py,sha256=eF71q-X7LA91sNYG29aXQiDVMjjr8-e6ez7P9NRwq_E,6376
|
22
24
|
sera/models/_default.py,sha256=ABggW6qdPR4ZDqIPJdJ0GCGQ-7kfsfZmQ_DchgZEa-I,137
|
23
25
|
sera/models/_enum.py,sha256=sy0q7E646F-APsqrVQ52r1fAQ_DCAeaNq5YM5QN3zIk,2070
|
24
26
|
sera/models/_module.py,sha256=8QRSCubZmdDP9rL58rGAS6X5VCrkc1ZHvuMu1I1KrWk,5043
|
@@ -27,6 +29,6 @@ sera/models/_parse.py,sha256=sJYfQtwek96ltpgxExG4xUbiLnU3qvNYhTP1CeyXGjs,9746
|
|
27
29
|
sera/models/_property.py,sha256=CmEmgOShtSyNFq05YW3tGupwCIVRzPMKudXWld8utPk,5530
|
28
30
|
sera/models/_schema.py,sha256=r-Gqg9Lb_wR3UrbNvfXXgt_qs5bts0t2Ve7aquuF_OI,1155
|
29
31
|
sera/typing.py,sha256=Q4QMfbtfrCjC9tFfsZPhsAnbNX4lm4NHQ9lmjNXYdV0,772
|
30
|
-
sera_2-1.7.
|
31
|
-
sera_2-1.7.
|
32
|
-
sera_2-1.7.
|
32
|
+
sera_2-1.7.2.dist-info/METADATA,sha256=xzCJfINCVbrv5Xd3oAKXJnhF_tYm7A51PpdTpdVqUW8,856
|
33
|
+
sera_2-1.7.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
34
|
+
sera_2-1.7.2.dist-info/RECORD,,
|
File without changes
|