sera-2 1.23.0__py3-none-any.whl → 1.25.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.
@@ -1,12 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import re
4
- from typing import Any, Callable, Optional
4
+ from typing import Any, Callable
5
5
 
6
6
  from codegen.models import AST, ImportHelper, PredefinedFn, Program, expr, stmt
7
7
  from codegen.models.var import DeferredVar
8
8
  from loguru import logger
9
9
 
10
+ from sera.make.ts_frontend.make_class_schema import make_class_schema
11
+ from sera.make.ts_frontend.misc import TS_GLOBAL_IDENTS, get_normalizer
10
12
  from sera.misc import (
11
13
  assert_isinstance,
12
14
  assert_not_null,
@@ -26,13 +28,6 @@ from sera.models import (
26
28
  )
27
29
  from sera.typing import is_set
28
30
 
29
- TS_GLOBAL_IDENTS = {
30
- "normalizers.normalizeNumber": "sera-db.normalizers",
31
- "normalizers.normalizeOptionalNumber": "sera-db.normalizers",
32
- "normalizers.normalizeDate": "sera-db.normalizers",
33
- "normalizers.normalizeOptionalDate": "sera-db.normalizers",
34
- }
35
-
36
31
 
37
32
  def make_typescript_data_model(schema: Schema, target_pkg: Package):
38
33
  """Generate TypeScript data model from the schema. The data model aligns with the public data model in Python, not the database model."""
@@ -440,13 +435,12 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
440
435
  if tstype.type in idprop_aliases:
441
436
  create_propvalue = idprop_aliases[tstype.type].get_default()
442
437
  elif tstype.type in schema.enums:
443
- enum_value = next(
438
+ enum_value_name = next(
444
439
  iter(schema.enums[tstype.type].values.values())
445
- ).value
446
- # TODO: handle enum value integer
447
- assert isinstance(enum_value, str)
440
+ ).name
441
+ assert isinstance(enum_value_name, str), enum_value_name
448
442
  create_propvalue = expr.ExprIdent(
449
- tstype.type + "." + enum_value
443
+ tstype.type + "." + enum_value_name
450
444
  )
451
445
  else:
452
446
  create_propvalue = tstype.get_default()
@@ -1194,323 +1188,6 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
1194
1188
 
1195
1189
  outmod.write(program)
1196
1190
 
1197
- def make_definition(cls: Class, pkg: Package):
1198
- """Make schema definition for the class in frontend so that we can generate components"""
1199
- if not cls.is_public:
1200
- # skip classes that are not public
1201
- return
1202
-
1203
- program = Program()
1204
- prop_defs: list[tuple[DataProperty | ObjectProperty, expr.Expr, expr.Expr]] = []
1205
- prop_normalizers: list[tuple[expr.Expr, expr.Expr]] = []
1206
-
1207
- import_helper = ImportHelper(program, TS_GLOBAL_IDENTS)
1208
-
1209
- for prop in cls.properties.values():
1210
- # we must include private properties that are needed during upsert for our forms.
1211
- # if prop.data.is_private:
1212
- # # skip private fields as this is for APIs exchange
1213
- # continue
1214
- tspropname = to_camel_case(prop.name)
1215
- pypropname = prop.name
1216
- if isinstance(prop, ObjectProperty) and prop.target.db is not None:
1217
- # this is a database object, we append id to the property name
1218
- tspropname = tspropname + "Id"
1219
- pypropname = prop.name + "_id"
1220
-
1221
- tsprop = {}
1222
-
1223
- if isinstance(prop, DataProperty):
1224
- tstype = prop.get_data_model_datatype().get_typescript_type()
1225
- # for schema definition, we need to use the original type, not the type alias
1226
- # if prop.name == idprop.name:
1227
- # # use id type alias
1228
- # tstype = TsTypeWithDep(f"{cls.name}Id")
1229
- for dep in tstype.deps:
1230
- program.import_(dep, True)
1231
- tsprop = [
1232
- (
1233
- expr.ExprIdent("datatype"),
1234
- (
1235
- expr.ExprConstant(tstype.spectype)
1236
- if tstype.type not in schema.enums
1237
- else expr.ExprConstant("enum")
1238
- ),
1239
- ),
1240
- *(
1241
- [(expr.ExprIdent("enumType"), expr.ExprIdent(tstype.type))]
1242
- if tstype.type in schema.enums
1243
- else []
1244
- ),
1245
- *(
1246
- [
1247
- (
1248
- expr.ExprIdent("foreignKeyTarget"),
1249
- expr.ExprConstant(prop.db.foreign_key.name),
1250
- )
1251
- ]
1252
- if prop.db is not None
1253
- and prop.db.is_primary_key
1254
- and prop.db.foreign_key is not None
1255
- else []
1256
- ),
1257
- (
1258
- expr.ExprIdent("isRequired"),
1259
- expr.ExprConstant(
1260
- not prop.is_optional
1261
- and prop.default_value is None
1262
- and prop.default_factory is None
1263
- ),
1264
- ),
1265
- ]
1266
-
1267
- norm_func = get_normalizer(tstype, import_helper)
1268
- if norm_func is not None:
1269
- # we have a normalizer for this type
1270
- prop_normalizers.append((expr.ExprIdent(tspropname), norm_func))
1271
- else:
1272
- assert isinstance(prop, ObjectProperty)
1273
- if prop.target.db is not None:
1274
- # this class is stored in the database, we store the id instead
1275
- tstype = (
1276
- assert_not_null(prop.target.get_id_property())
1277
- .get_data_model_datatype()
1278
- .get_typescript_type()
1279
- )
1280
- else:
1281
- # we are going to store the whole object
1282
- tstype = TsTypeWithDep(
1283
- type=prop.target.name,
1284
- spectype=prop.target.name,
1285
- deps=[
1286
- f"@.models.{prop.target.get_tsmodule_name()}.{prop.target.name}.{prop.target.name}"
1287
- ],
1288
- )
1289
-
1290
- # we don't store the type itself, but just the name of the type
1291
- # so not need to import the dependency
1292
- # if tstype.dep is not None:
1293
- # program.import_(
1294
- # tstype.dep,
1295
- # True,
1296
- # )
1297
-
1298
- tsprop = [
1299
- (
1300
- expr.ExprIdent("targetClass"),
1301
- expr.ExprConstant(prop.target.name),
1302
- ),
1303
- (
1304
- expr.ExprIdent("datatype"),
1305
- expr.ExprConstant(
1306
- tstype.spectype
1307
- if prop.target.db is not None
1308
- else "undefined"
1309
- ),
1310
- ),
1311
- (
1312
- expr.ExprIdent("cardinality"),
1313
- expr.ExprConstant(prop.cardinality.value),
1314
- ),
1315
- (
1316
- expr.ExprIdent("isEmbedded"),
1317
- expr.ExprConstant(prop.target.db is None),
1318
- ),
1319
- (
1320
- expr.ExprIdent("isRequired"),
1321
- expr.ExprConstant(not prop.is_optional),
1322
- ),
1323
- ]
1324
-
1325
- prop_defs.append(
1326
- (
1327
- prop,
1328
- expr.ExprIdent(tspropname),
1329
- PredefinedFn.dict(
1330
- [
1331
- (expr.ExprIdent("name"), expr.ExprConstant(pypropname)),
1332
- (expr.ExprIdent("tsName"), expr.ExprConstant(tspropname)),
1333
- (
1334
- expr.ExprIdent("updateFuncName"),
1335
- expr.ExprConstant(f"update{to_pascal_case(prop.name)}"),
1336
- ),
1337
- (
1338
- expr.ExprIdent("label"),
1339
- expr.ExprConstant(prop.label.to_dict()),
1340
- ),
1341
- (
1342
- expr.ExprIdent("description"),
1343
- (
1344
- expr.ExprConstant(prop.description.to_dict())
1345
- if not prop.description.is_empty()
1346
- else expr.ExprConstant("undefined")
1347
- ),
1348
- ),
1349
- (
1350
- expr.ExprIdent("constraints"),
1351
- PredefinedFn.list(
1352
- [
1353
- expr.ExprConstant(
1354
- constraint.get_typescript_constraint()
1355
- )
1356
- for constraint in prop.data.constraints
1357
- ]
1358
- ),
1359
- ),
1360
- ]
1361
- + tsprop
1362
- ),
1363
- )
1364
- )
1365
-
1366
- for type in ["ObjectProperty", "DataProperty"]:
1367
- program.import_(f"sera-db.{type}", True)
1368
- if cls.db is not None:
1369
- program.import_(f"sera-db.Schema", True)
1370
- else:
1371
- program.import_(f"sera-db.EmbeddedSchema", True)
1372
-
1373
- program.import_(f"@.models.{pkg.dir.name}.{cls.name}.{cls.name}", True)
1374
- program.import_(
1375
- f"@.models.{pkg.dir.name}.Draft{cls.name}.Draft{cls.name}", True
1376
- )
1377
- program.import_(
1378
- f"@.models.{pkg.dir.name}.Draft{cls.name}.draft{cls.name}Validators", True
1379
- )
1380
- if cls.db is not None:
1381
- program.import_(f"@.models.{pkg.dir.name}.{cls.name}.{cls.name}Id", True)
1382
-
1383
- program.root(
1384
- stmt.LineBreak(),
1385
- stmt.TypescriptStatement(
1386
- f"export type {cls.name}SchemaType = "
1387
- + PredefinedFn.dict(
1388
- (
1389
- [
1390
- (expr.ExprIdent("id"), expr.ExprIdent(f"{cls.name}Id")),
1391
- ]
1392
- if cls.db is not None
1393
- else []
1394
- )
1395
- + [
1396
- (
1397
- expr.ExprIdent("publicProperties"),
1398
- expr.ExprIdent(
1399
- " | ".join(
1400
- [
1401
- expr.ExprConstant(
1402
- to_camel_case(prop.name) + "Id"
1403
- if isinstance(prop, ObjectProperty)
1404
- and prop.target.db is not None
1405
- else to_camel_case(prop.name)
1406
- ).to_typescript()
1407
- for prop in cls.properties.values()
1408
- if not prop.data.is_private
1409
- ]
1410
- )
1411
- ),
1412
- ),
1413
- (
1414
- expr.ExprIdent("allProperties"),
1415
- expr.ExprIdent(
1416
- f"{cls.name}SchemaType['publicProperties']"
1417
- + (
1418
- " | "
1419
- + " | ".join(
1420
- [
1421
- expr.ExprConstant(
1422
- to_camel_case(prop.name)
1423
- ).to_typescript()
1424
- for prop in cls.properties.values()
1425
- if prop.data.is_private
1426
- ]
1427
- )
1428
- if any(
1429
- prop.data.is_private
1430
- for prop in cls.properties.values()
1431
- )
1432
- else ""
1433
- )
1434
- ),
1435
- ),
1436
- (
1437
- expr.ExprIdent("cls"),
1438
- expr.ExprIdent(cls.name),
1439
- ),
1440
- (
1441
- expr.ExprIdent("draftCls"),
1442
- expr.ExprIdent(f"Draft{cls.name}"),
1443
- ),
1444
- ]
1445
- ).to_typescript()
1446
- + ";",
1447
- ),
1448
- stmt.LineBreak(),
1449
- stmt.TypescriptStatement(
1450
- f"const publicProperties: Record<{cls.name}SchemaType['publicProperties'], DataProperty | ObjectProperty> = "
1451
- + PredefinedFn.dict(
1452
- [
1453
- (prop_name, prop_def)
1454
- for prop, prop_name, prop_def in prop_defs
1455
- if not prop.data.is_private
1456
- ]
1457
- ).to_typescript()
1458
- + ";"
1459
- ),
1460
- stmt.LineBreak(),
1461
- stmt.TypescriptStatement(
1462
- (
1463
- f"export const {cls.name}Schema: Schema<{cls.name}SchemaType['id'], {cls.name}SchemaType['cls'], {cls.name}SchemaType['draftCls'], {cls.name}SchemaType['publicProperties'], {cls.name}SchemaType['allProperties'], {cls.name}SchemaType> = "
1464
- if cls.db is not None
1465
- else f"export const {cls.name}Schema: EmbeddedSchema<{cls.name}SchemaType['cls'], {cls.name}SchemaType['draftCls'], {cls.name}SchemaType['publicProperties'], {cls.name}SchemaType['allProperties']> = "
1466
- )
1467
- + PredefinedFn.dict(
1468
- [
1469
- (
1470
- expr.ExprIdent("publicProperties"),
1471
- expr.ExprIdent("publicProperties"),
1472
- ),
1473
- (
1474
- expr.ExprIdent("allProperties"),
1475
- expr.ExprIdent(
1476
- "{ ...publicProperties, "
1477
- + ", ".join(
1478
- [
1479
- f"{prop_name.to_typescript()}: {prop_def.to_typescript()}"
1480
- for prop, prop_name, prop_def in prop_defs
1481
- if prop.data.is_private
1482
- ]
1483
- )
1484
- + "}"
1485
- ),
1486
- ),
1487
- (
1488
- expr.ExprIdent("validators"),
1489
- expr.ExprIdent(f"draft{cls.name}Validators"),
1490
- ),
1491
- (
1492
- expr.ExprIdent("normalizers"),
1493
- PredefinedFn.dict(prop_normalizers),
1494
- ),
1495
- ]
1496
- + (
1497
- [
1498
- (
1499
- expr.ExprIdent("primaryKey"),
1500
- expr.ExprConstant(
1501
- assert_not_null(cls.get_id_property()).name
1502
- ),
1503
- )
1504
- ]
1505
- if cls.db is not None
1506
- else []
1507
- )
1508
- ).to_typescript()
1509
- + ";"
1510
- ),
1511
- )
1512
- pkg.module(cls.name + "Schema").write(program)
1513
-
1514
1191
  def make_index(pkg: Package):
1515
1192
  outmod = pkg.module("index")
1516
1193
  if outmod.exists():
@@ -1566,7 +1243,7 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
1566
1243
  make_draft(cls, pkg)
1567
1244
  make_query_processor(cls, pkg)
1568
1245
  make_table(cls, pkg)
1569
- make_definition(cls, pkg)
1246
+ make_class_schema(schema, cls, pkg)
1570
1247
 
1571
1248
  make_index(pkg)
1572
1249
 
@@ -1661,22 +1338,6 @@ def _inject_type_for_invalid_value(tstype: TsTypeWithDep) -> TsTypeWithDep:
1661
1338
  raise NotImplementedError(tstype.type)
1662
1339
 
1663
1340
 
1664
- def get_normalizer(
1665
- tstype: TsTypeWithDep, import_helper: ImportHelper
1666
- ) -> Optional[expr.ExprIdent]:
1667
- if tstype.type == "number":
1668
- return import_helper.use("normalizers.normalizeNumber")
1669
- if tstype.type == "number | undefined":
1670
- return import_helper.use("normalizers.normalizeOptionalNumber")
1671
- if tstype.type == "Date":
1672
- return import_helper.use("normalizers.normalizeDate")
1673
- if tstype.type == "Date | undefined":
1674
- return import_helper.use("normalizers.normalizeOptionalDate")
1675
-
1676
- assert "number" not in tstype.type, tstype.type
1677
- return None
1678
-
1679
-
1680
1341
  def get_norm_func(
1681
1342
  tstype: TsTypeWithDep, import_helper: ImportHelper
1682
1343
  ) -> Callable[[expr.Expr], expr.Expr]:
File without changes