sera-2 1.12.0__py3-none-any.whl → 1.12.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.
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from operator import is_
4
- from typing import Callable, Sequence
4
+ from typing import Callable, Optional, Sequence
5
5
 
6
6
  from codegen.models import AST, DeferredVar, PredefinedFn, Program, expr, stmt
7
7
 
@@ -83,9 +83,25 @@ def make_python_data_model(
83
83
  app = target_pkg.app
84
84
 
85
85
  def from_db_type_conversion(
86
- record: expr.ExprIdent, prop: DataProperty | ObjectProperty
86
+ record: expr.ExprIdent,
87
+ prop: DataProperty | ObjectProperty,
88
+ value_pass_as_args: Optional[expr.Expr] = None,
87
89
  ):
88
- value = PredefinedFn.attr_getter(record, expr.ExprIdent(prop.name))
90
+ """Convert the value from the database to the data model type.
91
+
92
+ Args:
93
+ record: The record to convert from.
94
+ prop: The property to convert.
95
+ value_pass_as_args: If provided, this value will be used instead of getting the value from the record. This is useful for functions that
96
+ receive the column value as an argument, such as the `as_composite` function.
97
+ """
98
+ if value_pass_as_args is not None:
99
+ value = value_pass_as_args
100
+ assert record == expr.ExprIdent(
101
+ ""
102
+ ), "If value_pass_as_args is provided, record should not be used as a dummy value should be passed instead."
103
+ else:
104
+ value = PredefinedFn.attr_getter(record, expr.ExprIdent(prop.name))
89
105
  if isinstance(prop, ObjectProperty) and prop.target.db is not None:
90
106
  if prop.cardinality.is_star_to_many():
91
107
  value = PredefinedFn.map_list(
@@ -95,6 +111,9 @@ def make_python_data_model(
95
111
  ),
96
112
  )
97
113
  else:
114
+ assert (
115
+ value_pass_as_args is None
116
+ ), "Cannot use value_pass_as_args for a single object property."
98
117
  value = PredefinedFn.attr_getter(
99
118
  record, expr.ExprIdent(prop.name + "_id")
100
119
  )
@@ -500,6 +519,69 @@ def make_python_data_model(
500
519
  ),
501
520
  )
502
521
 
522
+ if cls.db is None:
523
+ as_composite_args = [DeferredVar.simple("cls")]
524
+ as_composite_null_condition = []
525
+ for prop in cls.properties.values():
526
+ assert (
527
+ not prop.data.is_private
528
+ ), f"Embedded classes should not have private properties: {cls.name}.{prop.name}"
529
+ as_composite_args.append(DeferredVar.simple(prop.name))
530
+ as_composite_null_condition.append(
531
+ expr.ExprIs(expr.ExprIdent(prop.name), expr.ExprConstant(None))
532
+ )
533
+
534
+ # For simplicity, we assume that this embedded class can be used in a nullable field (check if all properties are None and return None).
535
+ # However, we could be more efficient by checking if there are any other classes that use this class as a composite and are non-optional,
536
+ # and eliminate the None check because we know that the class will always be re-created.
537
+ cls_ast(
538
+ stmt.LineBreak(),
539
+ stmt.PythonDecoratorStatement(
540
+ expr.ExprFuncCall(expr.ExprIdent("classmethod"), [])
541
+ ),
542
+ lambda ast: ast.func(
543
+ "as_composite",
544
+ vars=as_composite_args,
545
+ return_type=expr.ExprIdent(f"Optional[{cls.name}]"),
546
+ comment="Create an embedded instance from the embedded columns in the database table. If all properties of this embedded class are None (indicating that the parent field is None), then this function will return None.",
547
+ )(
548
+ lambda ast_l1: ast_l1.if_(
549
+ expr.ExprLogicalAnd(as_composite_null_condition)
550
+ )(lambda ast_l2: ast_l2.return_(expr.ExprConstant(None))),
551
+ lambda ast_l1: ast_l1.return_(
552
+ expr.ExprFuncCall(
553
+ expr.ExprIdent("cls"),
554
+ [
555
+ from_db_type_conversion(
556
+ expr.ExprIdent(""), prop, expr.ExprIdent(prop.name)
557
+ )
558
+ for prop in cls.properties.values()
559
+ ],
560
+ )
561
+ ),
562
+ ),
563
+ stmt.LineBreak(),
564
+ lambda ast: ast.func(
565
+ "__composite_values__",
566
+ [
567
+ DeferredVar.simple("self"),
568
+ ],
569
+ return_type=expr.ExprIdent("tuple"),
570
+ comment="Return the values of the properties of this embedded class as a tuple. This is used to create a composite object in SQLAlchemy.",
571
+ )(
572
+ lambda ast_l1: ast_l1.return_(
573
+ PredefinedFn.tuple(
574
+ [
575
+ to_db_type_conversion(
576
+ program, expr.ExprIdent("self"), cls, prop
577
+ )
578
+ for prop in cls.properties.values()
579
+ ]
580
+ )
581
+ )
582
+ ),
583
+ )
584
+
503
585
  for cls in schema.topological_sort():
504
586
  if cls.name in reference_classes:
505
587
  continue
@@ -1138,7 +1138,7 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
1138
1138
  (
1139
1139
  expr.ExprIdent("datatype"),
1140
1140
  expr.ExprConstant(
1141
- tstype.type if prop.target.db is not None else "embedded"
1141
+ tstype.type if prop.target.db is not None else "undefined"
1142
1142
  ),
1143
1143
  ),
1144
1144
  (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sera-2
3
- Version: 1.12.0
3
+ Version: 1.12.2
4
4
  Summary:
5
5
  Author: Binh Vu
6
6
  Author-email: bvu687@gmail.com
@@ -9,7 +9,7 @@ Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Programming Language :: Python :: 3.12
10
10
  Classifier: Programming Language :: Python :: 3.13
11
11
  Requires-Dist: black (>=25.1.0,<26.0.0)
12
- Requires-Dist: codegen-2 (>=2.6.0,<3.0.0)
12
+ Requires-Dist: codegen-2 (>=2.10.0,<3.0.0)
13
13
  Requires-Dist: isort (>=6.0.1,<7.0.0)
14
14
  Requires-Dist: litestar (>=2.15.1,<3.0.0)
15
15
  Requires-Dist: loguru (>=0.7.0,<0.8.0)
@@ -13,9 +13,9 @@ sera/make/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  sera/make/__main__.py,sha256=G5O7s6135-708honwqMFn2yPTs06WbGQTHpupID0eZ4,1417
14
14
  sera/make/make_app.py,sha256=n9NtW73O3s_5Q31VHIRmnd-jEIcpDO7ksAsOdovde2s,5999
15
15
  sera/make/make_python_api.py,sha256=kq5DClmEeeNgg-a3Bb_8GN9jxvjnhjmW3RfBHNzynO8,25407
16
- sera/make/make_python_model.py,sha256=AlNJyyovb99TWocS2jtfTxy0C5YaFizx-Bhwdw1mUNw,41923
16
+ sera/make/make_python_model.py,sha256=ldaDnuwudkq81w2hwKZIuRqFnqhxOAaIT_VhYandXG4,46128
17
17
  sera/make/make_python_services.py,sha256=RsinYZdfkrTlTn9CT50VgqGs9w6IZawsJx-KEmqfnEY,2062
18
- sera/make/make_typescript_model.py,sha256=-Z3vHblUcEpWvMMdzQGZ9XWhUjLv99PBJGqZHsF0m1o,63686
18
+ sera/make/make_typescript_model.py,sha256=ugDdSTw_1ayHLuL--92RQ8hf_D-dpJtnvmUZNxcwcDs,63687
19
19
  sera/misc/__init__.py,sha256=Dh4uDq0D4N53h3zhvmwfa5a0TPVRSUvLzb0hkFuPirk,411
20
20
  sera/misc/_formatter.py,sha256=aCGYL08l8f3aLODHxSocxBBwkRYEo3K1QzCDEn3suj0,1685
21
21
  sera/misc/_utils.py,sha256=V5g4oLGHOhUCR75Kkcn1w01pAvGvaepK-T8Z3pIgHjI,1450
@@ -32,6 +32,6 @@ sera/models/_parse.py,sha256=uw6fvvh1ucGqE2jFTCCr-e6_qMfZfSVpaPolNxmrHww,9897
32
32
  sera/models/_property.py,sha256=SJSm5fZJimd2rQuL4UH_aZuNyp9v7x64xMbEVbtYx8Q,5633
33
33
  sera/models/_schema.py,sha256=r-Gqg9Lb_wR3UrbNvfXXgt_qs5bts0t2Ve7aquuF_OI,1155
34
34
  sera/typing.py,sha256=Q4QMfbtfrCjC9tFfsZPhsAnbNX4lm4NHQ9lmjNXYdV0,772
35
- sera_2-1.12.0.dist-info/METADATA,sha256=9OsTsh39Me41u3v-tRUiddDVkLKE-Qra7eMQLa8Kt2k,857
36
- sera_2-1.12.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
37
- sera_2-1.12.0.dist-info/RECORD,,
35
+ sera_2-1.12.2.dist-info/METADATA,sha256=724nMBYqD82HxkFzUWLora6vu5V-BA7wjfou6AEHM30,858
36
+ sera_2-1.12.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
37
+ sera_2-1.12.2.dist-info/RECORD,,