nsj-rest-lib2 0.0.30__py3-none-any.whl → 0.0.32__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.
- nsj_rest_lib2/compiler/compiler.py +96 -10
- nsj_rest_lib2/compiler/compiler_structures.py +1 -0
- nsj_rest_lib2/compiler/edl_model/primitives.py +12 -3
- nsj_rest_lib2/compiler/function_get_delete_compiler.py +238 -0
- nsj_rest_lib2/compiler/{function_compiler.py → function_insert_update_compiler.py} +2 -4
- nsj_rest_lib2/compiler/function_model.py +1 -0
- nsj_rest_lib2/compiler/migration_compiler.py +674 -0
- nsj_rest_lib2/compiler/migration_compiler_alter_table.py +201 -0
- nsj_rest_lib2/compiler/migration_compiler_create_table.py +75 -0
- nsj_rest_lib2/compiler/migration_compiler_util.py +144 -0
- nsj_rest_lib2/compiler/model.py +11 -0
- nsj_rest_lib2/compiler/property_compiler.py +38 -32
- nsj_rest_lib2/compiler/util/relation_ref.py +118 -0
- nsj_rest_lib2/compiler/util/type_naming_util.py +38 -1
- nsj_rest_lib2/controller/dynamic_controller.py +59 -0
- nsj_rest_lib2/service/entity_config_writer.py +19 -0
- nsj_rest_lib2/service/entity_loader.py +176 -2
- {nsj_rest_lib2-0.0.30.dist-info → nsj_rest_lib2-0.0.32.dist-info}/METADATA +1 -1
- {nsj_rest_lib2-0.0.30.dist-info → nsj_rest_lib2-0.0.32.dist-info}/RECORD +21 -16
- nsj_rest_lib2/compiler/ai_compiler.py +0 -285
- {nsj_rest_lib2-0.0.30.dist-info → nsj_rest_lib2-0.0.32.dist-info}/WHEEL +0 -0
- {nsj_rest_lib2-0.0.30.dist-info → nsj_rest_lib2-0.0.32.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import re
|
|
2
|
-
|
|
3
1
|
from typing import Any
|
|
4
2
|
|
|
5
3
|
from nsj_rest_lib2.compiler.compiler_structures import (
|
|
@@ -8,17 +6,19 @@ from nsj_rest_lib2.compiler.compiler_structures import (
|
|
|
8
6
|
PropertiesCompilerStructure,
|
|
9
7
|
)
|
|
10
8
|
from nsj_rest_lib2.compiler.dto_compiler import DTOCompiler
|
|
11
|
-
from nsj_rest_lib2.compiler.
|
|
12
|
-
|
|
9
|
+
from nsj_rest_lib2.compiler.function_insert_update_compiler import (
|
|
10
|
+
FunctionInsertUpdateCompiler,
|
|
13
11
|
inject_function_bindings,
|
|
14
12
|
)
|
|
13
|
+
from nsj_rest_lib2.compiler.function_get_delete_compiler import (
|
|
14
|
+
FunctionGetDeleteCompiler,
|
|
15
|
+
)
|
|
15
16
|
from nsj_rest_lib2.compiler.function_model import (
|
|
16
17
|
FunctionBindingConfig,
|
|
17
18
|
FunctionCompilationOutput,
|
|
18
19
|
)
|
|
19
20
|
from nsj_rest_lib2.compiler.edl_model.entity_model_base import EntityModelBase
|
|
20
21
|
from nsj_rest_lib2.compiler.edl_model.entity_model_root import EntityModelRoot
|
|
21
|
-
from nsj_rest_lib2.compiler.edl_model.primitives import REGEX_EXTERNAL_REF
|
|
22
22
|
from nsj_rest_lib2.compiler.entity_compiler import EntityCompiler
|
|
23
23
|
from nsj_rest_lib2.compiler.model import CompilerResult, RelationDependency
|
|
24
24
|
from nsj_rest_lib2.compiler.property_compiler import EDLPropertyCompiler
|
|
@@ -28,6 +28,7 @@ from nsj_rest_lib2.compiler.util.type_naming_util import (
|
|
|
28
28
|
compile_entity_class_name,
|
|
29
29
|
compile_namespace_keys,
|
|
30
30
|
)
|
|
31
|
+
from nsj_rest_lib2.compiler.util.relation_ref import RelationRefParser
|
|
31
32
|
|
|
32
33
|
from nsj_rest_lib2.compiler.edl_model.entity_model import EntityModel
|
|
33
34
|
|
|
@@ -39,7 +40,8 @@ class EDLCompiler:
|
|
|
39
40
|
self._properties_compiler = EDLPropertyCompiler()
|
|
40
41
|
self._dto_compiler = DTOCompiler()
|
|
41
42
|
self._entity_compiler = EntityCompiler()
|
|
42
|
-
self._function_compiler =
|
|
43
|
+
self._function_compiler = FunctionInsertUpdateCompiler()
|
|
44
|
+
self._function_get_delete_compiler = FunctionGetDeleteCompiler()
|
|
43
45
|
|
|
44
46
|
def compile_models(
|
|
45
47
|
self, entity_models: dict[str, EntityModel]
|
|
@@ -144,6 +146,15 @@ class EDLCompiler:
|
|
|
144
146
|
update_output = FunctionCompilationOutput()
|
|
145
147
|
insert_function_code = ""
|
|
146
148
|
update_function_code = ""
|
|
149
|
+
get_function_code = ""
|
|
150
|
+
list_function_code = ""
|
|
151
|
+
delete_function_code = ""
|
|
152
|
+
get_function_type_class = None
|
|
153
|
+
list_function_type_class = None
|
|
154
|
+
delete_function_type_class = None
|
|
155
|
+
get_function_name = None
|
|
156
|
+
list_function_name = None
|
|
157
|
+
delete_function_name = None
|
|
147
158
|
|
|
148
159
|
if isinstance(entity_model, EntityModel) and entity_model.api:
|
|
149
160
|
handlers = {}
|
|
@@ -166,6 +177,15 @@ class EDLCompiler:
|
|
|
166
177
|
handlers.get("put"),
|
|
167
178
|
prefx_class_name,
|
|
168
179
|
)
|
|
180
|
+
get_handler = handlers.get("get")
|
|
181
|
+
list_handler = handlers.get("list")
|
|
182
|
+
delete_handler = handlers.get("delete")
|
|
183
|
+
|
|
184
|
+
get_function_name = get_handler.function_ref if get_handler else None
|
|
185
|
+
list_function_name = list_handler.function_ref if list_handler else None
|
|
186
|
+
delete_function_name = (
|
|
187
|
+
delete_handler.function_ref if delete_handler else None
|
|
188
|
+
)
|
|
169
189
|
|
|
170
190
|
inject_function_bindings(
|
|
171
191
|
function_bindings,
|
|
@@ -178,6 +198,46 @@ class EDLCompiler:
|
|
|
178
198
|
if update_output.code:
|
|
179
199
|
update_function_code += update_output.code + "\n\n"
|
|
180
200
|
|
|
201
|
+
# Gerando FunctionTypes para GET/LIST/DELETE (quando configuradas)
|
|
202
|
+
get_output = self._function_get_delete_compiler.compile(
|
|
203
|
+
entity_model,
|
|
204
|
+
properties_structure,
|
|
205
|
+
get_handler,
|
|
206
|
+
prefx_class_name,
|
|
207
|
+
verb="get",
|
|
208
|
+
)
|
|
209
|
+
if get_output.class_name and get_output.code:
|
|
210
|
+
get_function_type_class = get_output.class_name
|
|
211
|
+
get_function_code = get_output.code
|
|
212
|
+
if get_output.function_name:
|
|
213
|
+
get_function_name = get_output.function_name
|
|
214
|
+
|
|
215
|
+
list_output = self._function_get_delete_compiler.compile(
|
|
216
|
+
entity_model,
|
|
217
|
+
properties_structure,
|
|
218
|
+
list_handler,
|
|
219
|
+
prefx_class_name,
|
|
220
|
+
verb="list",
|
|
221
|
+
)
|
|
222
|
+
if list_output.class_name and list_output.code:
|
|
223
|
+
list_function_type_class = list_output.class_name
|
|
224
|
+
list_function_code = list_output.code
|
|
225
|
+
if list_output.function_name:
|
|
226
|
+
list_function_name = list_output.function_name
|
|
227
|
+
|
|
228
|
+
delete_output = self._function_get_delete_compiler.compile(
|
|
229
|
+
entity_model,
|
|
230
|
+
properties_structure,
|
|
231
|
+
delete_handler,
|
|
232
|
+
prefx_class_name,
|
|
233
|
+
verb="delete",
|
|
234
|
+
)
|
|
235
|
+
if delete_output.class_name and delete_output.code:
|
|
236
|
+
delete_function_type_class = delete_output.class_name
|
|
237
|
+
delete_function_code = delete_output.code
|
|
238
|
+
if delete_output.function_name:
|
|
239
|
+
delete_function_name = delete_output.function_name
|
|
240
|
+
|
|
181
241
|
# Criando a lista de atributos do DTO e da Entity; e recuperando as chaves primarias
|
|
182
242
|
(
|
|
183
243
|
ast_dto_attributes,
|
|
@@ -301,7 +361,22 @@ class EDLCompiler:
|
|
|
301
361
|
compiler_result.dto_code = dto_code
|
|
302
362
|
compiler_result.relations_dependencies = relations_dependencies_complete
|
|
303
363
|
compiler_result.insert_function_class_name = insert_output.class_name
|
|
364
|
+
compiler_result.insert_function_name = insert_output.function_name
|
|
304
365
|
compiler_result.update_function_class_name = update_output.class_name
|
|
366
|
+
compiler_result.update_function_name = update_output.function_name
|
|
367
|
+
compiler_result.get_function_name = get_function_name
|
|
368
|
+
compiler_result.list_function_name = list_function_name
|
|
369
|
+
compiler_result.delete_function_name = delete_function_name
|
|
370
|
+
compiler_result.get_function_type_class_name = get_function_type_class
|
|
371
|
+
compiler_result.list_function_type_class_name = list_function_type_class
|
|
372
|
+
compiler_result.delete_function_type_class_name = delete_function_type_class
|
|
373
|
+
compiler_result.source_get_function_type = get_function_code.strip() or None
|
|
374
|
+
compiler_result.source_list_function_type = (
|
|
375
|
+
list_function_code.strip() or None
|
|
376
|
+
)
|
|
377
|
+
compiler_result.source_delete_function_type = (
|
|
378
|
+
delete_function_code.strip() or None
|
|
379
|
+
)
|
|
305
380
|
|
|
306
381
|
insert_code_compiled = insert_function_code.strip()
|
|
307
382
|
update_code_compiled = update_function_code.strip()
|
|
@@ -496,6 +571,7 @@ class EDLCompiler:
|
|
|
496
571
|
properties_structure: PropertiesCompilerStructure,
|
|
497
572
|
entity_model: EntityModelBase,
|
|
498
573
|
entity_models: dict[str, EntityModel],
|
|
574
|
+
relation_type: str = "self",
|
|
499
575
|
):
|
|
500
576
|
if not entity_model:
|
|
501
577
|
return
|
|
@@ -511,6 +587,7 @@ class EDLCompiler:
|
|
|
511
587
|
properties_structure,
|
|
512
588
|
mixin_model,
|
|
513
589
|
entity_models,
|
|
590
|
+
relation_type="mixin",
|
|
514
591
|
)
|
|
515
592
|
|
|
516
593
|
# Populando com as propriedades da superclasse (extends)
|
|
@@ -521,6 +598,7 @@ class EDLCompiler:
|
|
|
521
598
|
properties_structure,
|
|
522
599
|
super_model,
|
|
523
600
|
entity_models,
|
|
601
|
+
relation_type="extends",
|
|
524
602
|
)
|
|
525
603
|
|
|
526
604
|
# Populando com as propriedades do trait
|
|
@@ -531,10 +609,18 @@ class EDLCompiler:
|
|
|
531
609
|
properties_structure,
|
|
532
610
|
trait_model,
|
|
533
611
|
entity_models,
|
|
612
|
+
relation_type="trait",
|
|
534
613
|
)
|
|
535
614
|
|
|
536
615
|
# Populando com as propriedades da entidade atual
|
|
537
616
|
properties_structure.properties.update(entity_model.properties)
|
|
617
|
+
for prop_name in entity_model.properties or {}:
|
|
618
|
+
# Preferimos não sobrescrever quando já marcado como 'self'
|
|
619
|
+
if (
|
|
620
|
+
prop_name not in properties_structure.property_origins
|
|
621
|
+
or relation_type == "self"
|
|
622
|
+
):
|
|
623
|
+
properties_structure.property_origins[prop_name] = relation_type
|
|
538
624
|
if entity_model.main_properties:
|
|
539
625
|
for main_property in entity_model.main_properties:
|
|
540
626
|
if not isinstance(main_property, str):
|
|
@@ -706,10 +792,10 @@ class EDLCompiler:
|
|
|
706
792
|
prop = entity_model.properties[pkey]
|
|
707
793
|
|
|
708
794
|
if isinstance(prop.type, str):
|
|
709
|
-
|
|
710
|
-
if
|
|
711
|
-
|
|
712
|
-
|
|
795
|
+
relation_ref = RelationRefParser.parse(prop.type)
|
|
796
|
+
if relation_ref and relation_ref.is_external:
|
|
797
|
+
if relation_ref.entity_key:
|
|
798
|
+
entities.append(relation_ref.entity_key)
|
|
713
799
|
|
|
714
800
|
return entities
|
|
715
801
|
|
|
@@ -27,6 +27,7 @@ class PropertiesCompilerStructure:
|
|
|
27
27
|
self.trait_properties: dict[str, TraitPropertyMetaModel] = {}
|
|
28
28
|
self.extends_properties: dict[str, ExtendsPropertyMetaModel] = {}
|
|
29
29
|
self.composed_properties: dict[str, list[str]] = {}
|
|
30
|
+
self.property_origins: dict[str, str] = {}
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
class ComponentsCompilerStructure:
|
|
@@ -4,15 +4,20 @@ from typing import Annotated, List, Union
|
|
|
4
4
|
from pydantic import StringConstraints
|
|
5
5
|
|
|
6
6
|
REGEX_EXTERNAL_REF = r"^(\w+)\/(\w+)$"
|
|
7
|
-
|
|
7
|
+
REGEX_EXTERNAL_COMPONENT_REF = r"^(\w+)\/(\w+)\/([\w\/#]+)$"
|
|
8
|
+
REGEX_INTERNAL_REF = r"^#\/components\/([\w\/#]+)$"
|
|
8
9
|
|
|
9
10
|
ExternalRefType = Annotated[str, StringConstraints(pattern=REGEX_EXTERNAL_REF)]
|
|
11
|
+
ExternalComponentRefType = Annotated[
|
|
12
|
+
str, StringConstraints(pattern=REGEX_EXTERNAL_COMPONENT_REF)
|
|
13
|
+
]
|
|
10
14
|
InternalRefType = Annotated[str, StringConstraints(pattern=REGEX_INTERNAL_REF)]
|
|
11
15
|
|
|
12
16
|
|
|
13
17
|
class PrimitiveTypes(enum.Enum):
|
|
14
18
|
# TODO Validar esses tipos
|
|
15
19
|
STRING = "string"
|
|
20
|
+
TEXT = "text"
|
|
16
21
|
NUMBER = "number"
|
|
17
22
|
INTEGER = "integer"
|
|
18
23
|
BOOLEAN = "boolean"
|
|
@@ -28,10 +33,13 @@ class PrimitiveTypes(enum.Enum):
|
|
|
28
33
|
DURATION = "duration"
|
|
29
34
|
|
|
30
35
|
|
|
31
|
-
PropertyType = Union[
|
|
36
|
+
PropertyType = Union[
|
|
37
|
+
PrimitiveTypes, ExternalRefType, ExternalComponentRefType, InternalRefType
|
|
38
|
+
]
|
|
32
39
|
|
|
33
40
|
MAPPING_PRIMITIVE_TYPES_TO_PYTHON = {
|
|
34
41
|
PrimitiveTypes.STRING: "str",
|
|
42
|
+
PrimitiveTypes.TEXT: "str",
|
|
35
43
|
PrimitiveTypes.NUMBER: "float",
|
|
36
44
|
PrimitiveTypes.INTEGER: "int",
|
|
37
45
|
PrimitiveTypes.BOOLEAN: "bool",
|
|
@@ -44,7 +52,7 @@ MAPPING_PRIMITIVE_TYPES_TO_PYTHON = {
|
|
|
44
52
|
PrimitiveTypes.EMAIL: "str",
|
|
45
53
|
PrimitiveTypes.DATE: "datetime.date",
|
|
46
54
|
PrimitiveTypes.DATETIME: "datetime.datetime",
|
|
47
|
-
PrimitiveTypes.DURATION: "relativedelta"
|
|
55
|
+
PrimitiveTypes.DURATION: "relativedelta",
|
|
48
56
|
}
|
|
49
57
|
|
|
50
58
|
BasicTypes = int | bool | float | str
|
|
@@ -52,6 +60,7 @@ DefaultTypes = BasicTypes | List[BasicTypes]
|
|
|
52
60
|
|
|
53
61
|
STR_BASED_TYPES = {
|
|
54
62
|
PrimitiveTypes.STRING,
|
|
63
|
+
PrimitiveTypes.TEXT,
|
|
55
64
|
PrimitiveTypes.EMAIL,
|
|
56
65
|
PrimitiveTypes.CPF,
|
|
57
66
|
PrimitiveTypes.CNPJ,
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from nsj_rest_lib2.compiler.compiler_structures import PropertiesCompilerStructure
|
|
6
|
+
from nsj_rest_lib2.compiler.edl_model.api_model import HandlerConfig, HandlerMapping
|
|
7
|
+
from nsj_rest_lib2.compiler.edl_model.entity_model_base import EntityModelBase
|
|
8
|
+
from nsj_rest_lib2.compiler.edl_model.primitives import PrimitiveTypes
|
|
9
|
+
from nsj_rest_lib2.compiler.function_model import FunctionCompilationOutput
|
|
10
|
+
from nsj_rest_lib2.compiler.util.str_util import CompilerStrUtil
|
|
11
|
+
from nsj_rest_lib2.compiler.util.type_naming_util import compile_function_class_name
|
|
12
|
+
from nsj_rest_lib2.compiler.util.type_util import TypeUtil
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class FunctionGetDeleteCompiler:
|
|
16
|
+
"""
|
|
17
|
+
Responsável por gerar FunctionTypes (Get/List/Delete) baseados no
|
|
18
|
+
binding de pg_function declarado no EDL.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def compile(
|
|
22
|
+
self,
|
|
23
|
+
entity_model: EntityModelBase,
|
|
24
|
+
properties_structure: PropertiesCompilerStructure,
|
|
25
|
+
handler_config: Optional[HandlerConfig],
|
|
26
|
+
prefx_class_name: str,
|
|
27
|
+
verb: str,
|
|
28
|
+
) -> FunctionCompilationOutput:
|
|
29
|
+
if not isinstance(handler_config, HandlerConfig):
|
|
30
|
+
return FunctionCompilationOutput()
|
|
31
|
+
if handler_config.impl != "pg_function":
|
|
32
|
+
return FunctionCompilationOutput()
|
|
33
|
+
if not handler_config.call or not handler_config.call.arg_binding:
|
|
34
|
+
return FunctionCompilationOutput()
|
|
35
|
+
|
|
36
|
+
arg_binding = handler_config.call.arg_binding
|
|
37
|
+
if not arg_binding.mapping or not arg_binding.type_name:
|
|
38
|
+
return FunctionCompilationOutput()
|
|
39
|
+
|
|
40
|
+
function_name = handler_config.function_ref
|
|
41
|
+
if not function_name:
|
|
42
|
+
return FunctionCompilationOutput()
|
|
43
|
+
|
|
44
|
+
class_name = compile_function_class_name(
|
|
45
|
+
entity_model.id,
|
|
46
|
+
prefx_class_name,
|
|
47
|
+
[],
|
|
48
|
+
verb,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
fields = self._build_fields(arg_binding.mapping, properties_structure)
|
|
52
|
+
if not fields:
|
|
53
|
+
return FunctionCompilationOutput()
|
|
54
|
+
|
|
55
|
+
code = self._build_code(class_name, arg_binding.type_name, fields, verb)
|
|
56
|
+
|
|
57
|
+
return FunctionCompilationOutput(
|
|
58
|
+
class_name=class_name,
|
|
59
|
+
code=code,
|
|
60
|
+
function_name=function_name,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# ------------------------------------------------------------------ #
|
|
64
|
+
# Helpers
|
|
65
|
+
# ------------------------------------------------------------------ #
|
|
66
|
+
|
|
67
|
+
def _build_fields(
|
|
68
|
+
self,
|
|
69
|
+
mappings: list[HandlerMapping],
|
|
70
|
+
properties_structure: PropertiesCompilerStructure,
|
|
71
|
+
) -> list[tuple[str, str, Optional[str], bool]]:
|
|
72
|
+
"""
|
|
73
|
+
Retorna lista de tuplas:
|
|
74
|
+
(python_name, annotation, type_field_name, is_pk)
|
|
75
|
+
"""
|
|
76
|
+
fields: list[tuple[str, str, Optional[str], bool]] = []
|
|
77
|
+
used: set[str] = set()
|
|
78
|
+
|
|
79
|
+
for entry in mappings or []:
|
|
80
|
+
attr = (entry.attr or "").strip()
|
|
81
|
+
if not attr:
|
|
82
|
+
continue
|
|
83
|
+
|
|
84
|
+
python_name = self._sanitize_identifier(attr)
|
|
85
|
+
if python_name in used:
|
|
86
|
+
continue
|
|
87
|
+
used.add(python_name)
|
|
88
|
+
|
|
89
|
+
type_field_name = attr if python_name != attr else None
|
|
90
|
+
source = (entry.from_ or "").strip()
|
|
91
|
+
is_pk = source.startswith("path.")
|
|
92
|
+
|
|
93
|
+
annotation = self._resolve_annotation(entry, properties_structure)
|
|
94
|
+
|
|
95
|
+
fields.append(
|
|
96
|
+
(
|
|
97
|
+
python_name,
|
|
98
|
+
annotation,
|
|
99
|
+
type_field_name,
|
|
100
|
+
is_pk,
|
|
101
|
+
)
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
return fields
|
|
105
|
+
|
|
106
|
+
def _resolve_annotation(
|
|
107
|
+
self,
|
|
108
|
+
entry: HandlerMapping,
|
|
109
|
+
properties_structure: PropertiesCompilerStructure,
|
|
110
|
+
) -> str:
|
|
111
|
+
"""
|
|
112
|
+
Tenta inferir o tipo a partir das propriedades da entidade.
|
|
113
|
+
Prioriza:
|
|
114
|
+
- campos referenciados como body.<campo>;
|
|
115
|
+
- ou, se o último segmento de 'from' (após o '.') existir como
|
|
116
|
+
property do EDL, usa esse nome para lookup.
|
|
117
|
+
"""
|
|
118
|
+
dto_field = self._extract_dto_field(entry.from_)
|
|
119
|
+
|
|
120
|
+
# Se não veio de body.*, tenta casar o último segmento de 'from'
|
|
121
|
+
# com o nome de alguma propriedade do EDL.
|
|
122
|
+
if not dto_field:
|
|
123
|
+
candidate = CompilerStrUtil.to_snake_case(
|
|
124
|
+
(entry.from_ or "").split(".")[-1]
|
|
125
|
+
)
|
|
126
|
+
if candidate and properties_structure and candidate in properties_structure.properties:
|
|
127
|
+
dto_field = candidate
|
|
128
|
+
|
|
129
|
+
if not dto_field:
|
|
130
|
+
return "Any"
|
|
131
|
+
|
|
132
|
+
prop = (
|
|
133
|
+
properties_structure.properties.get(dto_field)
|
|
134
|
+
if properties_structure
|
|
135
|
+
else None
|
|
136
|
+
)
|
|
137
|
+
if not prop or not isinstance(prop.type, PrimitiveTypes):
|
|
138
|
+
return "Any"
|
|
139
|
+
|
|
140
|
+
return TypeUtil.property_type_to_python_type(prop.type)
|
|
141
|
+
|
|
142
|
+
def _build_code(
|
|
143
|
+
self,
|
|
144
|
+
class_name: str,
|
|
145
|
+
type_name: str,
|
|
146
|
+
fields: list[tuple[str, str, Optional[str], bool]],
|
|
147
|
+
verb: str,
|
|
148
|
+
) -> str:
|
|
149
|
+
needs_any = any(annotation == "Any" for _, annotation, _, _ in fields)
|
|
150
|
+
needs_uuid = any(annotation == "uuid.UUID" for _, annotation, _, _ in fields)
|
|
151
|
+
needs_datetime = any(
|
|
152
|
+
annotation == "datetime.datetime" for _, annotation, _, _ in fields
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
lines: list[str] = []
|
|
156
|
+
if needs_uuid:
|
|
157
|
+
lines.append("import uuid")
|
|
158
|
+
if needs_datetime:
|
|
159
|
+
lines.append("import datetime")
|
|
160
|
+
if needs_any:
|
|
161
|
+
lines.append("from typing import Any")
|
|
162
|
+
|
|
163
|
+
decorator_module, decorator_name, base_class = self._resolve_decorator(verb)
|
|
164
|
+
lines.extend(
|
|
165
|
+
[
|
|
166
|
+
f"from {decorator_module} import {decorator_name}",
|
|
167
|
+
f"from nsj_rest_lib.entity.function_type_base import {base_class}",
|
|
168
|
+
"from nsj_rest_lib.descriptor.function_field import FunctionField",
|
|
169
|
+
"",
|
|
170
|
+
f"@{decorator_name}(type_name=\"{type_name}\")",
|
|
171
|
+
f"class {class_name}({base_class}):",
|
|
172
|
+
]
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
for name, annotation, type_field_name, is_pk in fields:
|
|
176
|
+
kwargs: list[str] = []
|
|
177
|
+
if type_field_name:
|
|
178
|
+
kwargs.append(f'type_field_name="{type_field_name}"')
|
|
179
|
+
if is_pk:
|
|
180
|
+
kwargs.append("pk=True")
|
|
181
|
+
kwargs_str = ", ".join(kwargs)
|
|
182
|
+
if kwargs_str:
|
|
183
|
+
kwargs_str = ", " + kwargs_str
|
|
184
|
+
lines.append(
|
|
185
|
+
f" {name}: {annotation} = FunctionField({kwargs_str.lstrip(', ')})"
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
if not fields:
|
|
189
|
+
lines.append(" pass")
|
|
190
|
+
|
|
191
|
+
lines.append("") # newline final
|
|
192
|
+
return "\n".join(lines)
|
|
193
|
+
|
|
194
|
+
def _resolve_decorator(self, verb: str) -> tuple[str, str, str]:
|
|
195
|
+
verb = (verb or "").lower()
|
|
196
|
+
if verb == "get":
|
|
197
|
+
return (
|
|
198
|
+
"nsj_rest_lib.decorator.get_function_type",
|
|
199
|
+
"GetFunctionType",
|
|
200
|
+
"GetFunctionTypeBase",
|
|
201
|
+
)
|
|
202
|
+
if verb == "list":
|
|
203
|
+
return (
|
|
204
|
+
"nsj_rest_lib.decorator.list_function_type",
|
|
205
|
+
"ListFunctionType",
|
|
206
|
+
"ListFunctionTypeBase",
|
|
207
|
+
)
|
|
208
|
+
if verb == "delete":
|
|
209
|
+
return (
|
|
210
|
+
"nsj_rest_lib.decorator.delete_function_type",
|
|
211
|
+
"DeleteFunctionType",
|
|
212
|
+
"DeleteFunctionTypeBase",
|
|
213
|
+
)
|
|
214
|
+
# fallback genérico
|
|
215
|
+
return (
|
|
216
|
+
"nsj_rest_lib.decorator.function_type",
|
|
217
|
+
"FunctionType",
|
|
218
|
+
"FunctionTypeBase",
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
def _sanitize_identifier(self, name: str) -> str:
|
|
222
|
+
candidate = CompilerStrUtil.to_snake_case(name)
|
|
223
|
+
candidate = "".join(ch if ch.isalnum() or ch == "_" else "_" for ch in candidate)
|
|
224
|
+
if not candidate:
|
|
225
|
+
candidate = "field"
|
|
226
|
+
if candidate[0].isdigit():
|
|
227
|
+
candidate = f"_{candidate}"
|
|
228
|
+
return candidate
|
|
229
|
+
|
|
230
|
+
def _extract_dto_field(self, source: Optional[str]) -> Optional[str]:
|
|
231
|
+
if not source:
|
|
232
|
+
return None
|
|
233
|
+
|
|
234
|
+
if source.startswith("body."):
|
|
235
|
+
segment = source[5:].split(".", 1)[0]
|
|
236
|
+
return CompilerStrUtil.to_snake_case(segment)
|
|
237
|
+
|
|
238
|
+
return None
|
|
@@ -50,7 +50,7 @@ class _ClassSpec:
|
|
|
50
50
|
children: list["_ClassSpec"] = field(default_factory=list)
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
class
|
|
53
|
+
class FunctionInsertUpdateCompiler:
|
|
54
54
|
"""
|
|
55
55
|
Responsável por compilar tipos usados por funções de banco (Insert/Update)
|
|
56
56
|
com base na configuração declarada no EDL.
|
|
@@ -156,6 +156,7 @@ class FunctionCompiler:
|
|
|
156
156
|
return FunctionCompilationOutput(
|
|
157
157
|
class_name=class_name,
|
|
158
158
|
code=code,
|
|
159
|
+
function_name=function_name,
|
|
159
160
|
field_bindings=field_bindings,
|
|
160
161
|
relation_bindings=relation_bindings,
|
|
161
162
|
)
|
|
@@ -333,9 +334,6 @@ class FunctionCompiler:
|
|
|
333
334
|
args=[],
|
|
334
335
|
keywords=[
|
|
335
336
|
ast.keyword(arg="type_name", value=ast.Constant(value=spec.type_name)),
|
|
336
|
-
ast.keyword(
|
|
337
|
-
arg="function_name", value=ast.Constant(value=spec.function_name)
|
|
338
|
-
),
|
|
339
337
|
],
|
|
340
338
|
)
|
|
341
339
|
|
|
@@ -64,6 +64,7 @@ class FunctionCompilationOutput:
|
|
|
64
64
|
|
|
65
65
|
class_name: Optional[str] = None
|
|
66
66
|
code: Optional[str] = None
|
|
67
|
+
function_name: Optional[str] = None
|
|
67
68
|
field_bindings: Dict[str, str] = field(default_factory=dict)
|
|
68
69
|
relation_bindings: Dict[str, FunctionRelationBinding] = field(
|
|
69
70
|
default_factory=dict
|