nsj-rest-lib2 0.0.35__py3-none-any.whl → 0.0.37__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 +111 -3
- nsj_rest_lib2/compiler/dto_compiler.py +5 -1
- nsj_rest_lib2/compiler/edl_model/api_model.py +18 -6
- nsj_rest_lib2/compiler/model.py +12 -0
- nsj_rest_lib2/compiler/response_dto_compiler.py +104 -0
- nsj_rest_lib2/compiler/util/type_naming_util.py +83 -1
- nsj_rest_lib2/controller/dynamic_controller.py +87 -5
- nsj_rest_lib2/service/entity_config_writer.py +19 -44
- nsj_rest_lib2/service/entity_loader.py +421 -70
- nsj_rest_lib2/settings.py +10 -0
- nsj_rest_lib2-0.0.37.dist-info/METADATA +203 -0
- {nsj_rest_lib2-0.0.35.dist-info → nsj_rest_lib2-0.0.37.dist-info}/RECORD +14 -13
- nsj_rest_lib2-0.0.35.dist-info/METADATA +0 -27
- {nsj_rest_lib2-0.0.35.dist-info → nsj_rest_lib2-0.0.37.dist-info}/WHEEL +0 -0
- {nsj_rest_lib2-0.0.35.dist-info → nsj_rest_lib2-0.0.37.dist-info}/top_level.txt +0 -0
|
@@ -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.response_dto_compiler import ResponseDTOCompiler
|
|
31
32
|
from nsj_rest_lib2.compiler.util.relation_ref import RelationRefParser
|
|
32
33
|
|
|
33
34
|
from nsj_rest_lib2.compiler.edl_model.entity_model import EntityModel
|
|
@@ -169,9 +170,12 @@ class EDLCompiler:
|
|
|
169
170
|
get_function_name = None
|
|
170
171
|
list_function_name = None
|
|
171
172
|
delete_function_name = None
|
|
173
|
+
handlers: dict[str, Any] = {}
|
|
174
|
+
post_handler = None
|
|
175
|
+
put_handler = None
|
|
176
|
+
patch_handler = None
|
|
172
177
|
|
|
173
178
|
if isinstance(entity_model, EntityModel) and entity_model.api:
|
|
174
|
-
handlers = {}
|
|
175
179
|
if entity_model.api.handlers:
|
|
176
180
|
handlers = {
|
|
177
181
|
(verb or "").lower(): handler
|
|
@@ -179,16 +183,20 @@ class EDLCompiler:
|
|
|
179
183
|
if handler
|
|
180
184
|
}
|
|
181
185
|
|
|
186
|
+
post_handler = handlers.get("post")
|
|
187
|
+
put_handler = handlers.get("put")
|
|
188
|
+
patch_handler = handlers.get("patch")
|
|
189
|
+
|
|
182
190
|
insert_output = self._function_compiler.compile_insert(
|
|
183
191
|
entity_model,
|
|
184
192
|
properties_structure,
|
|
185
|
-
|
|
193
|
+
post_handler,
|
|
186
194
|
prefx_class_name,
|
|
187
195
|
)
|
|
188
196
|
update_output = self._function_compiler.compile_update(
|
|
189
197
|
entity_model,
|
|
190
198
|
properties_structure,
|
|
191
|
-
|
|
199
|
+
put_handler,
|
|
192
200
|
prefx_class_name,
|
|
193
201
|
)
|
|
194
202
|
get_handler = handlers.get("get")
|
|
@@ -354,6 +362,16 @@ class EDLCompiler:
|
|
|
354
362
|
# Adicionando as dependências das relações
|
|
355
363
|
relations_dependencies_complete.extend(relations_dependencies)
|
|
356
364
|
|
|
365
|
+
response_dto_compiler = ResponseDTOCompiler(
|
|
366
|
+
dto_compiler=self._dto_compiler,
|
|
367
|
+
entity_model=entity_model,
|
|
368
|
+
prefx_class_name=prefx_class_name,
|
|
369
|
+
ast_dto_attributes=ast_dto_attributes,
|
|
370
|
+
aux_classes=aux_classes,
|
|
371
|
+
related_imports=related_imports,
|
|
372
|
+
fixed_filters=fixed_filters,
|
|
373
|
+
)
|
|
374
|
+
|
|
357
375
|
# Adicionando as dependências da extensão parcial
|
|
358
376
|
if partial_metadata and partial_base_model:
|
|
359
377
|
relation_dependency = RelationDependency()
|
|
@@ -367,6 +385,68 @@ class EDLCompiler:
|
|
|
367
385
|
relation_dependency.grupo_empresarial = partial_base_model.grupo_empresarial
|
|
368
386
|
relations_dependencies_complete.append(relation_dependency)
|
|
369
387
|
|
|
388
|
+
post_expected = "empty"
|
|
389
|
+
put_expected = "empty"
|
|
390
|
+
patch_expected = "empty"
|
|
391
|
+
get_expected = "empty"
|
|
392
|
+
list_expected = "empty"
|
|
393
|
+
delete_expected = "empty"
|
|
394
|
+
post_properties = None
|
|
395
|
+
put_properties = None
|
|
396
|
+
patch_properties = None
|
|
397
|
+
if isinstance(entity_model, EntityModel) and entity_model.api:
|
|
398
|
+
post_expected, post_properties = (
|
|
399
|
+
response_dto_compiler.handler_result_details(post_handler)
|
|
400
|
+
)
|
|
401
|
+
put_expected, put_properties = (
|
|
402
|
+
response_dto_compiler.handler_result_details(put_handler)
|
|
403
|
+
)
|
|
404
|
+
patch_expected, patch_properties = (
|
|
405
|
+
response_dto_compiler.handler_result_details(patch_handler)
|
|
406
|
+
)
|
|
407
|
+
get_expected, _ = response_dto_compiler.handler_result_details(
|
|
408
|
+
get_handler
|
|
409
|
+
)
|
|
410
|
+
list_expected, _ = response_dto_compiler.handler_result_details(
|
|
411
|
+
list_handler
|
|
412
|
+
)
|
|
413
|
+
delete_expected, _ = response_dto_compiler.handler_result_details(
|
|
414
|
+
delete_handler
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
if post_expected == "partial_row":
|
|
418
|
+
post_class_name, post_code = (
|
|
419
|
+
response_dto_compiler.compile_partial_response_dto(
|
|
420
|
+
"post", post_properties or []
|
|
421
|
+
)
|
|
422
|
+
)
|
|
423
|
+
compiler_result_post_class = post_class_name
|
|
424
|
+
dto_code += "\n\n" + post_code
|
|
425
|
+
else:
|
|
426
|
+
compiler_result_post_class = None
|
|
427
|
+
|
|
428
|
+
if put_expected == "partial_row":
|
|
429
|
+
put_class_name, put_code = (
|
|
430
|
+
response_dto_compiler.compile_partial_response_dto(
|
|
431
|
+
"put", put_properties or []
|
|
432
|
+
)
|
|
433
|
+
)
|
|
434
|
+
compiler_result_put_class = put_class_name
|
|
435
|
+
dto_code += "\n\n" + put_code
|
|
436
|
+
else:
|
|
437
|
+
compiler_result_put_class = None
|
|
438
|
+
|
|
439
|
+
if patch_expected == "partial_row":
|
|
440
|
+
patch_class_name, patch_code = (
|
|
441
|
+
response_dto_compiler.compile_partial_response_dto(
|
|
442
|
+
"patch", patch_properties or []
|
|
443
|
+
)
|
|
444
|
+
)
|
|
445
|
+
compiler_result_patch_class = patch_class_name
|
|
446
|
+
dto_code += "\n\n" + patch_code
|
|
447
|
+
else:
|
|
448
|
+
compiler_result_patch_class = None
|
|
449
|
+
|
|
370
450
|
# Construindo o resultado
|
|
371
451
|
compiler_result = CompilerResult()
|
|
372
452
|
compiler_result.entity_class_name = entity_class_name
|
|
@@ -389,6 +469,34 @@ class EDLCompiler:
|
|
|
389
469
|
compiler_result.source_delete_function_type = (
|
|
390
470
|
delete_function_code.strip() or None
|
|
391
471
|
)
|
|
472
|
+
compiler_result.retrieve_after_insert = post_expected == "entity_row"
|
|
473
|
+
compiler_result.retrieve_after_update = put_expected == "entity_row"
|
|
474
|
+
compiler_result.retrieve_after_partial_update = (
|
|
475
|
+
patch_expected == "entity_row"
|
|
476
|
+
)
|
|
477
|
+
compiler_result.post_response_dto_class_name = compiler_result_post_class
|
|
478
|
+
compiler_result.put_response_dto_class_name = compiler_result_put_class
|
|
479
|
+
compiler_result.patch_response_dto_class_name = (
|
|
480
|
+
compiler_result_patch_class
|
|
481
|
+
)
|
|
482
|
+
compiler_result.custom_json_post_response = (
|
|
483
|
+
post_expected == "custom_json"
|
|
484
|
+
)
|
|
485
|
+
compiler_result.custom_json_put_response = (
|
|
486
|
+
put_expected == "custom_json"
|
|
487
|
+
)
|
|
488
|
+
compiler_result.custom_json_patch_response = (
|
|
489
|
+
patch_expected == "custom_json"
|
|
490
|
+
)
|
|
491
|
+
compiler_result.custom_json_get_response = (
|
|
492
|
+
get_expected == "custom_json"
|
|
493
|
+
)
|
|
494
|
+
compiler_result.custom_json_list_response = (
|
|
495
|
+
list_expected == "custom_json"
|
|
496
|
+
)
|
|
497
|
+
compiler_result.custom_json_delete_response = (
|
|
498
|
+
delete_expected == "custom_json"
|
|
499
|
+
)
|
|
392
500
|
|
|
393
501
|
insert_code_compiled = insert_function_code.strip()
|
|
394
502
|
update_code_compiled = update_function_code.strip()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import ast
|
|
2
|
+
from typing import Optional
|
|
2
3
|
|
|
3
4
|
import black
|
|
4
5
|
|
|
@@ -21,6 +22,7 @@ class DTOCompiler:
|
|
|
21
22
|
fixed_filters: list[tuple[str, BasicTypes]],
|
|
22
23
|
prefx_class_name: str,
|
|
23
24
|
partial_metadata: dict[str, str] | None,
|
|
25
|
+
class_name_override: Optional[str] = None,
|
|
24
26
|
) -> tuple[str, str]:
|
|
25
27
|
"""
|
|
26
28
|
Compila o código do DTO a partir do AST e retorna o código compilado.
|
|
@@ -158,7 +160,9 @@ class DTOCompiler:
|
|
|
158
160
|
)
|
|
159
161
|
|
|
160
162
|
# Criando o ast da classe
|
|
161
|
-
class_name = compile_dto_class_name(
|
|
163
|
+
class_name = class_name_override or compile_dto_class_name(
|
|
164
|
+
entity_model.id, prefx_class_name
|
|
165
|
+
)
|
|
162
166
|
ast_class = ast.ClassDef(
|
|
163
167
|
name=class_name,
|
|
164
168
|
bases=[ast.Name(id="DTOBase", ctx=ast.Load())],
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import Dict, List, Literal, Optional
|
|
4
4
|
|
|
5
|
-
from pydantic import AliasChoices, BaseModel, Field
|
|
5
|
+
from pydantic import AliasChoices, BaseModel, Field, model_validator
|
|
6
6
|
|
|
7
7
|
APIVerbs = Literal["GET", "POST", "PUT", "DELETE", "PATCH"]
|
|
8
8
|
|
|
@@ -46,10 +46,22 @@ class HandlerCall(BaseModel):
|
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
class HandlerResult(BaseModel):
|
|
49
|
-
expected: Literal["empty", "entity_row"] = Field(
|
|
49
|
+
expected: Literal["empty", "entity_row", "custom_json", "partial_row"] = Field(
|
|
50
50
|
default="empty",
|
|
51
51
|
description="Define o formato esperado do retorno da função.",
|
|
52
52
|
)
|
|
53
|
+
properties: Optional[List[str]] = Field(
|
|
54
|
+
default=None,
|
|
55
|
+
description="Lista de propriedades a serem retornadas quando o resultado esperado for 'partial_row'.",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
@model_validator(mode="after")
|
|
59
|
+
def validate_partial_row(self):
|
|
60
|
+
if self.expected == "partial_row" and not self.properties:
|
|
61
|
+
raise ValueError(
|
|
62
|
+
"result.properties é obrigatório quando result.expected for 'partial_row'."
|
|
63
|
+
)
|
|
64
|
+
return self
|
|
53
65
|
|
|
54
66
|
|
|
55
67
|
class HandlerError(BaseModel):
|
|
@@ -68,12 +80,12 @@ class HandlerError(BaseModel):
|
|
|
68
80
|
|
|
69
81
|
|
|
70
82
|
class HandlerConfig(BaseModel):
|
|
71
|
-
impl: Literal["pg_function"] = Field(
|
|
72
|
-
|
|
83
|
+
impl: Optional[Literal["pg_function"]] = Field(
|
|
84
|
+
default=None,
|
|
73
85
|
description="Somente funções PostgreSQL (pg_function) são suportadas neste estágio.",
|
|
74
86
|
)
|
|
75
|
-
function_ref: str = Field(
|
|
76
|
-
|
|
87
|
+
function_ref: Optional[str] = Field(
|
|
88
|
+
default=None,
|
|
77
89
|
description="Referência qualificada para a função no banco (ex.: schema.fn_nome).",
|
|
78
90
|
)
|
|
79
91
|
call: Optional[HandlerCall] = Field(
|
nsj_rest_lib2/compiler/model.py
CHANGED
|
@@ -59,3 +59,15 @@ class CompilerResult:
|
|
|
59
59
|
self.source_get_function_type: str | None = None
|
|
60
60
|
self.source_list_function_type: str | None = None
|
|
61
61
|
self.source_delete_function_type: str | None = None
|
|
62
|
+
self.retrieve_after_insert: bool | None = None
|
|
63
|
+
self.retrieve_after_update: bool | None = None
|
|
64
|
+
self.retrieve_after_partial_update: bool | None = None
|
|
65
|
+
self.post_response_dto_class_name: str | None = None
|
|
66
|
+
self.put_response_dto_class_name: str | None = None
|
|
67
|
+
self.patch_response_dto_class_name: str | None = None
|
|
68
|
+
self.custom_json_post_response: bool | None = None
|
|
69
|
+
self.custom_json_put_response: bool | None = None
|
|
70
|
+
self.custom_json_patch_response: bool | None = None
|
|
71
|
+
self.custom_json_get_response: bool | None = None
|
|
72
|
+
self.custom_json_list_response: bool | None = None
|
|
73
|
+
self.custom_json_delete_response: bool | None = None
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
from typing import Any, Optional
|
|
5
|
+
|
|
6
|
+
from nsj_rest_lib2.compiler.dto_compiler import DTOCompiler
|
|
7
|
+
from nsj_rest_lib2.compiler.edl_model.entity_model_base import EntityModelBase
|
|
8
|
+
from nsj_rest_lib2.compiler.edl_model.primitives import BasicTypes
|
|
9
|
+
from nsj_rest_lib2.compiler.util.str_util import CompilerStrUtil
|
|
10
|
+
from nsj_rest_lib2.compiler.util.type_naming_util import (
|
|
11
|
+
compile_response_dto_class_name,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ResponseDTOCompiler:
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
dto_compiler: DTOCompiler,
|
|
19
|
+
entity_model: EntityModelBase,
|
|
20
|
+
prefx_class_name: str,
|
|
21
|
+
ast_dto_attributes: list[ast.stmt],
|
|
22
|
+
aux_classes: list[ast.stmt],
|
|
23
|
+
related_imports: list[tuple[str, str, str]],
|
|
24
|
+
fixed_filters: list[tuple[str, BasicTypes]],
|
|
25
|
+
) -> None:
|
|
26
|
+
self._dto_compiler = dto_compiler
|
|
27
|
+
self._entity_model = entity_model
|
|
28
|
+
self._prefx_class_name = prefx_class_name
|
|
29
|
+
self._aux_classes = aux_classes
|
|
30
|
+
self._related_imports = related_imports
|
|
31
|
+
self._fixed_filters = fixed_filters
|
|
32
|
+
self._dto_attr_map = self._build_attr_map(ast_dto_attributes)
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def handler_result_details(handler: Any) -> tuple[str, list[str] | None]:
|
|
36
|
+
expected = "empty"
|
|
37
|
+
properties = None
|
|
38
|
+
if handler and getattr(handler, "result", None):
|
|
39
|
+
expected = handler.result.expected or "empty"
|
|
40
|
+
properties = handler.result.properties
|
|
41
|
+
return (expected, properties)
|
|
42
|
+
|
|
43
|
+
def compile_partial_response_dto(
|
|
44
|
+
self, verb: str, properties: list[str]
|
|
45
|
+
) -> tuple[str, str]:
|
|
46
|
+
if not properties:
|
|
47
|
+
raise Exception(
|
|
48
|
+
f"result.properties não pode ser vazio para '{verb}' na entidade '{self._entity_model.id}'."
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
normalized = [
|
|
52
|
+
CompilerStrUtil.to_snake_case(prop) for prop in properties
|
|
53
|
+
]
|
|
54
|
+
missing = [
|
|
55
|
+
properties[idx]
|
|
56
|
+
for idx, norm in enumerate(normalized)
|
|
57
|
+
if norm not in self._dto_attr_map
|
|
58
|
+
]
|
|
59
|
+
if missing:
|
|
60
|
+
raise Exception(
|
|
61
|
+
f"As propriedades {missing} não foram encontradas na entidade '{self._entity_model.id}'."
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
filtered_attrs = [self._dto_attr_map[name] for name in normalized]
|
|
65
|
+
filtered_fixed_filters = [
|
|
66
|
+
item for item in self._fixed_filters if item[0] in normalized
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
class_name = compile_response_dto_class_name(
|
|
70
|
+
self._entity_model.id,
|
|
71
|
+
self._prefx_class_name,
|
|
72
|
+
verb,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
return self._dto_compiler.compile(
|
|
76
|
+
self._entity_model,
|
|
77
|
+
filtered_attrs,
|
|
78
|
+
self._aux_classes,
|
|
79
|
+
self._related_imports,
|
|
80
|
+
filtered_fixed_filters,
|
|
81
|
+
self._prefx_class_name,
|
|
82
|
+
None,
|
|
83
|
+
class_name_override=class_name,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
@staticmethod
|
|
87
|
+
def _extract_attr_name(stmt: ast.stmt) -> Optional[str]:
|
|
88
|
+
if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Name):
|
|
89
|
+
return stmt.target.id
|
|
90
|
+
if isinstance(stmt, ast.Assign) and stmt.targets:
|
|
91
|
+
target = stmt.targets[0]
|
|
92
|
+
if isinstance(target, ast.Name):
|
|
93
|
+
return target.id
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
def _build_attr_map(
|
|
97
|
+
self, ast_dto_attributes: list[ast.stmt]
|
|
98
|
+
) -> dict[str, ast.stmt]:
|
|
99
|
+
dto_attr_map: dict[str, ast.stmt] = {}
|
|
100
|
+
for stmt in ast_dto_attributes:
|
|
101
|
+
name = self._extract_attr_name(stmt)
|
|
102
|
+
if name:
|
|
103
|
+
dto_attr_map[name] = stmt
|
|
104
|
+
return dto_attr_map
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import hashlib
|
|
1
2
|
import uuid
|
|
2
|
-
from typing import Iterable
|
|
3
|
+
from typing import Iterable, Iterator, Optional
|
|
3
4
|
|
|
5
|
+
from nsj_rest_lib2.compiler.model import CompilerResult
|
|
4
6
|
from nsj_rest_lib2.compiler.util.str_util import CompilerStrUtil
|
|
5
7
|
|
|
6
8
|
|
|
@@ -14,10 +16,90 @@ def compile_namespace_keys(
|
|
|
14
16
|
return (grupo_key, tenant_key, default_key)
|
|
15
17
|
|
|
16
18
|
|
|
19
|
+
def resolve_namespace_key(
|
|
20
|
+
tenant: str | int | None, grupo_empresarial: str | uuid.UUID | None
|
|
21
|
+
) -> str:
|
|
22
|
+
grupo_key, tenant_key, default_key = compile_namespace_keys(
|
|
23
|
+
tenant,
|
|
24
|
+
grupo_empresarial,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
if (
|
|
28
|
+
tenant
|
|
29
|
+
and tenant != 0
|
|
30
|
+
and grupo_empresarial
|
|
31
|
+
and str(grupo_empresarial) != "00000000-0000-0000-0000-000000000000"
|
|
32
|
+
):
|
|
33
|
+
return grupo_key
|
|
34
|
+
if tenant and tenant != 0:
|
|
35
|
+
return tenant_key
|
|
36
|
+
return default_key
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def build_entity_hash(compiler_result: CompilerResult) -> str:
|
|
40
|
+
hasher = hashlib.sha256()
|
|
41
|
+
|
|
42
|
+
for content in _iter_hash_chunks(
|
|
43
|
+
compiler_result.dto_code,
|
|
44
|
+
compiler_result.entity_code,
|
|
45
|
+
compiler_result.insert_function_name,
|
|
46
|
+
compiler_result.update_function_name,
|
|
47
|
+
compiler_result.get_function_name,
|
|
48
|
+
compiler_result.list_function_name,
|
|
49
|
+
compiler_result.delete_function_name,
|
|
50
|
+
compiler_result.source_insert_function,
|
|
51
|
+
compiler_result.source_update_function,
|
|
52
|
+
compiler_result.source_get_function_type,
|
|
53
|
+
compiler_result.source_list_function_type,
|
|
54
|
+
compiler_result.source_delete_function_type,
|
|
55
|
+
compiler_result.post_response_dto_class_name,
|
|
56
|
+
compiler_result.put_response_dto_class_name,
|
|
57
|
+
compiler_result.patch_response_dto_class_name,
|
|
58
|
+
str(compiler_result.retrieve_after_insert),
|
|
59
|
+
str(compiler_result.retrieve_after_update),
|
|
60
|
+
str(compiler_result.retrieve_after_partial_update),
|
|
61
|
+
str(compiler_result.custom_json_post_response),
|
|
62
|
+
str(compiler_result.custom_json_put_response),
|
|
63
|
+
str(compiler_result.custom_json_patch_response),
|
|
64
|
+
str(compiler_result.custom_json_get_response),
|
|
65
|
+
str(compiler_result.custom_json_list_response),
|
|
66
|
+
str(compiler_result.custom_json_delete_response),
|
|
67
|
+
compiler_result.service_account,
|
|
68
|
+
):
|
|
69
|
+
hasher.update(content)
|
|
70
|
+
|
|
71
|
+
return hasher.hexdigest()
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _iter_hash_chunks(*chunks: Optional[str]) -> Iterator[bytes]:
|
|
75
|
+
for chunk in chunks:
|
|
76
|
+
if chunk:
|
|
77
|
+
yield chunk.encode("utf-8")
|
|
78
|
+
|
|
79
|
+
|
|
17
80
|
def compile_dto_class_name(entity_id: str, prefx_class_name: str = "") -> str:
|
|
18
81
|
return f"{CompilerStrUtil.to_pascal_case(prefx_class_name)}{CompilerStrUtil.to_pascal_case(entity_id)}DTO"
|
|
19
82
|
|
|
20
83
|
|
|
84
|
+
def compile_response_dto_class_name(
|
|
85
|
+
entity_id: str, prefx_class_name: str, verb: str
|
|
86
|
+
) -> str:
|
|
87
|
+
verb = (verb or "").lower()
|
|
88
|
+
suffix_map = {
|
|
89
|
+
"post": "PostResponseDTO",
|
|
90
|
+
"put": "PutResponseDTO",
|
|
91
|
+
"patch": "PatchResponseDTO",
|
|
92
|
+
}
|
|
93
|
+
suffix = suffix_map.get(
|
|
94
|
+
verb, f"{CompilerStrUtil.to_pascal_case(verb)}ResponseDTO"
|
|
95
|
+
)
|
|
96
|
+
return (
|
|
97
|
+
f"{CompilerStrUtil.to_pascal_case(prefx_class_name)}"
|
|
98
|
+
f"{CompilerStrUtil.to_pascal_case(entity_id)}"
|
|
99
|
+
f"{suffix}"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
21
103
|
def compile_entity_class_name(entity_id: str, prefx_class_name: str = "") -> str:
|
|
22
104
|
return f"{CompilerStrUtil.to_pascal_case(prefx_class_name)}{CompilerStrUtil.to_pascal_case(entity_id)}Entity"
|
|
23
105
|
|
|
@@ -11,12 +11,12 @@ from nsj_gcf_utils.rest_error_util import format_json_error
|
|
|
11
11
|
from nsj_multi_database_lib.decorator.multi_database import multi_database
|
|
12
12
|
|
|
13
13
|
from nsj_rest_lib.controller.controller_util import DEFAULT_RESP_HEADERS
|
|
14
|
-
from nsj_rest_lib.controller.
|
|
14
|
+
from nsj_rest_lib.controller.delete_route import DeleteRoute
|
|
15
15
|
from nsj_rest_lib.controller.get_route import GetRoute
|
|
16
|
+
from nsj_rest_lib.controller.list_route import ListRoute
|
|
17
|
+
from nsj_rest_lib.controller.patch_route import PatchRoute
|
|
16
18
|
from nsj_rest_lib.controller.post_route import PostRoute
|
|
17
19
|
from nsj_rest_lib.controller.put_route import PutRoute
|
|
18
|
-
from nsj_rest_lib.controller.patch_route import PatchRoute
|
|
19
|
-
from nsj_rest_lib.controller.delete_route import DeleteRoute
|
|
20
20
|
|
|
21
21
|
from nsj_rest_lib2.exception import MissingEntityConfigException
|
|
22
22
|
from nsj_rest_lib2.service.entity_loader import EntityLoader
|
|
@@ -55,6 +55,7 @@ def setup_dynamic_routes(
|
|
|
55
55
|
dynamic_root_path: str = "edl1",
|
|
56
56
|
injector_factory: Any = None,
|
|
57
57
|
escopo_in_url: bool = False,
|
|
58
|
+
edls_path: str | None = None,
|
|
58
59
|
) -> None:
|
|
59
60
|
|
|
60
61
|
if not escopo_in_url:
|
|
@@ -68,6 +69,8 @@ def setup_dynamic_routes(
|
|
|
68
69
|
f"/{APP_NAME}/{dynamic_root_path}/<entity_escopo>/<entity_resource>/<id>"
|
|
69
70
|
)
|
|
70
71
|
|
|
72
|
+
entity_loader = EntityLoader(edls_path=edls_path)
|
|
73
|
+
|
|
71
74
|
def _dynamic_route_wrapper(
|
|
72
75
|
route_builder: Callable[[tuple[Any, ...]], Callable[..., Any]],
|
|
73
76
|
endpoint_suffix: str | None = None,
|
|
@@ -83,7 +86,6 @@ def setup_dynamic_routes(
|
|
|
83
86
|
tenant, grupo_empresarial, force_reload = _get_query_args()
|
|
84
87
|
|
|
85
88
|
try:
|
|
86
|
-
entity_loader = EntityLoader()
|
|
87
89
|
entity_config = entity_loader.load_entity_source(
|
|
88
90
|
entity_resource,
|
|
89
91
|
tenant,
|
|
@@ -133,6 +135,10 @@ def setup_dynamic_routes(
|
|
|
133
135
|
_get_function_type_class_name,
|
|
134
136
|
list_function_type_class_name,
|
|
135
137
|
_delete_function_type_class_name,
|
|
138
|
+
*_,
|
|
139
|
+
_custom_json_get_response,
|
|
140
|
+
custom_json_list_response,
|
|
141
|
+
_custom_json_delete_response,
|
|
136
142
|
) = entity_config
|
|
137
143
|
|
|
138
144
|
def list_dynamic(*args: Any, **kwargs: Any) -> Any:
|
|
@@ -149,6 +155,7 @@ def setup_dynamic_routes(
|
|
|
149
155
|
list_function_type_class=etities_dict.get(
|
|
150
156
|
list_function_type_class_name
|
|
151
157
|
),
|
|
158
|
+
custom_json_response=bool(custom_json_list_response),
|
|
152
159
|
)
|
|
153
160
|
|
|
154
161
|
return route.handle_request(*args, **kwargs)
|
|
@@ -173,6 +180,10 @@ def setup_dynamic_routes(
|
|
|
173
180
|
get_function_type_class_name,
|
|
174
181
|
_list_function_type_class_name,
|
|
175
182
|
_delete_function_type_class_name,
|
|
183
|
+
*_,
|
|
184
|
+
custom_json_get_response,
|
|
185
|
+
_custom_json_list_response,
|
|
186
|
+
_custom_json_delete_response,
|
|
176
187
|
) = entity_config
|
|
177
188
|
|
|
178
189
|
def get_dynamic(*args: Any, **kwargs: Any) -> Any:
|
|
@@ -187,6 +198,7 @@ def setup_dynamic_routes(
|
|
|
187
198
|
injector_factory=injector_factory,
|
|
188
199
|
get_function_name=get_function_name,
|
|
189
200
|
get_function_type_class=etities_dict.get(get_function_type_class_name),
|
|
201
|
+
custom_json_response=bool(custom_json_get_response),
|
|
190
202
|
)
|
|
191
203
|
|
|
192
204
|
return route.handle_request(*args, **kwargs)
|
|
@@ -211,6 +223,18 @@ def setup_dynamic_routes(
|
|
|
211
223
|
_get_function_type_class_name,
|
|
212
224
|
_list_function_type_class_name,
|
|
213
225
|
_delete_function_type_class_name,
|
|
226
|
+
retrieve_after_insert,
|
|
227
|
+
_retrieve_after_update,
|
|
228
|
+
_retrieve_after_partial_update,
|
|
229
|
+
post_response_dto_class_name,
|
|
230
|
+
_put_response_dto_class_name,
|
|
231
|
+
_patch_response_dto_class_name,
|
|
232
|
+
custom_json_post_response,
|
|
233
|
+
_custom_json_put_response,
|
|
234
|
+
_custom_json_patch_response,
|
|
235
|
+
_custom_json_get_response,
|
|
236
|
+
_custom_json_list_response,
|
|
237
|
+
_custom_json_delete_response,
|
|
214
238
|
) = entity_config
|
|
215
239
|
|
|
216
240
|
def post_dynamic(*args: Any, **kwargs: Any) -> Any:
|
|
@@ -223,6 +247,12 @@ def setup_dynamic_routes(
|
|
|
223
247
|
else None
|
|
224
248
|
)
|
|
225
249
|
|
|
250
|
+
dto_response_class = (
|
|
251
|
+
etities_dict.get(post_response_dto_class_name)
|
|
252
|
+
if post_response_dto_class_name
|
|
253
|
+
else None
|
|
254
|
+
)
|
|
255
|
+
|
|
226
256
|
route = PostRoute(
|
|
227
257
|
url=COLLECTION_DYNAMIC_ROUTE,
|
|
228
258
|
http_method="POST",
|
|
@@ -231,6 +261,9 @@ def setup_dynamic_routes(
|
|
|
231
261
|
injector_factory=injector_factory,
|
|
232
262
|
insert_function_type_class=insert_function_type_class,
|
|
233
263
|
insert_function_name=insert_function_name,
|
|
264
|
+
dto_response_class=dto_response_class,
|
|
265
|
+
retrieve_after_insert=retrieve_after_insert,
|
|
266
|
+
custom_json_response=bool(custom_json_post_response),
|
|
234
267
|
)
|
|
235
268
|
|
|
236
269
|
return route.handle_request(*args, **kwargs)
|
|
@@ -255,8 +288,26 @@ def setup_dynamic_routes(
|
|
|
255
288
|
_get_function_type_class_name,
|
|
256
289
|
_list_function_type_class_name,
|
|
257
290
|
_delete_function_type_class_name,
|
|
291
|
+
_retrieve_after_insert,
|
|
292
|
+
retrieve_after_update,
|
|
293
|
+
_retrieve_after_partial_update,
|
|
294
|
+
_post_response_dto_class_name,
|
|
295
|
+
put_response_dto_class_name,
|
|
296
|
+
_patch_response_dto_class_name,
|
|
297
|
+
_custom_json_post_response,
|
|
298
|
+
custom_json_put_response,
|
|
299
|
+
_custom_json_patch_response,
|
|
300
|
+
_custom_json_get_response,
|
|
301
|
+
_custom_json_list_response,
|
|
302
|
+
_custom_json_delete_response,
|
|
258
303
|
) = entity_config
|
|
259
304
|
|
|
305
|
+
dto_response_class = (
|
|
306
|
+
etities_dict.get(put_response_dto_class_name)
|
|
307
|
+
if put_response_dto_class_name
|
|
308
|
+
else None
|
|
309
|
+
)
|
|
310
|
+
|
|
260
311
|
def put_dynamic(*args: Any, **kwargs: Any) -> Any:
|
|
261
312
|
if not api_expose or "PUT" not in api_verbs:
|
|
262
313
|
return ("", 405, {})
|
|
@@ -275,6 +326,9 @@ def setup_dynamic_routes(
|
|
|
275
326
|
injector_factory=injector_factory,
|
|
276
327
|
update_function_type_class=update_function_type_class,
|
|
277
328
|
update_function_name=update_function_name,
|
|
329
|
+
dto_response_class=dto_response_class,
|
|
330
|
+
retrieve_after_update=retrieve_after_update,
|
|
331
|
+
custom_json_response=bool(custom_json_put_response),
|
|
278
332
|
)
|
|
279
333
|
|
|
280
334
|
return route.handle_request(*args, **kwargs)
|
|
@@ -296,19 +350,42 @@ def setup_dynamic_routes(
|
|
|
296
350
|
_get_function_name,
|
|
297
351
|
_list_function_name,
|
|
298
352
|
_delete_function_name,
|
|
299
|
-
|
|
353
|
+
_get_function_type_class_name,
|
|
354
|
+
_list_function_type_class_name,
|
|
355
|
+
_delete_function_type_class_name,
|
|
356
|
+
_retrieve_after_insert,
|
|
357
|
+
_retrieve_after_update,
|
|
358
|
+
retrieve_after_partial_update,
|
|
359
|
+
_post_response_dto_class_name,
|
|
360
|
+
_put_response_dto_class_name,
|
|
361
|
+
patch_response_dto_class_name,
|
|
362
|
+
_custom_json_post_response,
|
|
363
|
+
_custom_json_put_response,
|
|
364
|
+
custom_json_patch_response,
|
|
365
|
+
_custom_json_get_response,
|
|
366
|
+
_custom_json_list_response,
|
|
367
|
+
_custom_json_delete_response,
|
|
300
368
|
) = entity_config
|
|
301
369
|
|
|
302
370
|
def patch_dynamic(*args: Any, **kwargs: Any) -> Any:
|
|
303
371
|
if not api_expose or "PATCH" not in api_verbs:
|
|
304
372
|
return ("", 405, {})
|
|
305
373
|
|
|
374
|
+
dto_response_class = (
|
|
375
|
+
etities_dict.get(patch_response_dto_class_name)
|
|
376
|
+
if patch_response_dto_class_name
|
|
377
|
+
else None
|
|
378
|
+
)
|
|
379
|
+
|
|
306
380
|
route = PatchRoute(
|
|
307
381
|
url=ONE_DYNAMIC_ROUTE,
|
|
308
382
|
http_method="PATCH",
|
|
309
383
|
dto_class=etities_dict[dto_class_name],
|
|
310
384
|
entity_class=etities_dict[entity_class_name],
|
|
311
385
|
injector_factory=injector_factory,
|
|
386
|
+
dto_response_class=dto_response_class,
|
|
387
|
+
retrieve_after_partial_update=retrieve_after_partial_update,
|
|
388
|
+
custom_json_response=bool(custom_json_patch_response),
|
|
312
389
|
)
|
|
313
390
|
|
|
314
391
|
return route.handle_request(*args, **kwargs)
|
|
@@ -333,6 +410,10 @@ def setup_dynamic_routes(
|
|
|
333
410
|
_get_function_type_class_name,
|
|
334
411
|
_list_function_type_class_name,
|
|
335
412
|
delete_function_type_class_name,
|
|
413
|
+
*_,
|
|
414
|
+
_custom_json_get_response,
|
|
415
|
+
_custom_json_list_response,
|
|
416
|
+
custom_json_delete_response,
|
|
336
417
|
) = entity_config
|
|
337
418
|
|
|
338
419
|
def delete_dynamic(*args: Any, **kwargs: Any) -> Any:
|
|
@@ -349,6 +430,7 @@ def setup_dynamic_routes(
|
|
|
349
430
|
delete_function_type_class=etities_dict.get(
|
|
350
431
|
delete_function_type_class_name
|
|
351
432
|
),
|
|
433
|
+
custom_json_response=bool(custom_json_delete_response),
|
|
352
434
|
)
|
|
353
435
|
|
|
354
436
|
return route.handle_request(*args, **kwargs)
|