nsj-rest-lib2 0.0.25__py3-none-any.whl → 0.0.27__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 +81 -0
- nsj_rest_lib2/compiler/dto_compiler.py +1 -1
- nsj_rest_lib2/compiler/edl_model/api_model.py +95 -2
- nsj_rest_lib2/compiler/function_compiler.py +550 -0
- nsj_rest_lib2/compiler/function_model.py +70 -0
- nsj_rest_lib2/compiler/model.py +4 -0
- nsj_rest_lib2/compiler/property_compiler.py +111 -0
- nsj_rest_lib2/compiler/util/type_naming_util.py +22 -0
- nsj_rest_lib2/controller/dynamic_controller.py +35 -38
- nsj_rest_lib2/service/entity_config_writer.py +134 -0
- nsj_rest_lib2/service/entity_loader.py +56 -6
- {nsj_rest_lib2-0.0.25.dist-info → nsj_rest_lib2-0.0.27.dist-info}/METADATA +1 -1
- {nsj_rest_lib2-0.0.25.dist-info → nsj_rest_lib2-0.0.27.dist-info}/RECORD +15 -12
- {nsj_rest_lib2-0.0.25.dist-info → nsj_rest_lib2-0.0.27.dist-info}/WHEEL +0 -0
- {nsj_rest_lib2-0.0.25.dist-info → nsj_rest_lib2-0.0.27.dist-info}/top_level.txt +0 -0
|
@@ -18,6 +18,7 @@ from nsj_rest_lib2.compiler.edl_model.primitives import (
|
|
|
18
18
|
STR_BASED_TYPES,
|
|
19
19
|
)
|
|
20
20
|
from nsj_rest_lib2.compiler.edl_model.property_meta_model import PropertyMetaModel
|
|
21
|
+
from nsj_rest_lib2.compiler.function_model import FunctionBindingConfig
|
|
21
22
|
from nsj_rest_lib2.compiler.edl_model.trait_property_meta_model import (
|
|
22
23
|
TraitPropertyMetaModel,
|
|
23
24
|
)
|
|
@@ -41,6 +42,7 @@ class EDLPropertyCompiler:
|
|
|
41
42
|
entity_model: EntityModelBase,
|
|
42
43
|
entity_models: dict[str, EntityModel],
|
|
43
44
|
prefx_class_name: str,
|
|
45
|
+
function_bindings: FunctionBindingConfig | None = None,
|
|
44
46
|
) -> tuple[
|
|
45
47
|
list[ast.stmt],
|
|
46
48
|
list[ast.stmt],
|
|
@@ -76,6 +78,9 @@ class EDLPropertyCompiler:
|
|
|
76
78
|
|
|
77
79
|
# pk_key = pk_keys[0]
|
|
78
80
|
|
|
81
|
+
function_bindings = function_bindings or FunctionBindingConfig()
|
|
82
|
+
self._function_bindings = function_bindings
|
|
83
|
+
|
|
79
84
|
# Instanciando as listas de retorno
|
|
80
85
|
ast_dto_attributes = []
|
|
81
86
|
ast_entity_attributes = []
|
|
@@ -433,6 +438,50 @@ class EDLPropertyCompiler:
|
|
|
433
438
|
),
|
|
434
439
|
]
|
|
435
440
|
|
|
441
|
+
insert_binding = self._function_bindings.insert_relations.get(pkey)
|
|
442
|
+
if insert_binding:
|
|
443
|
+
if (
|
|
444
|
+
insert_binding.field_name
|
|
445
|
+
and insert_binding.field_name != CompilerStrUtil.to_snake_case(pkey)
|
|
446
|
+
):
|
|
447
|
+
keywords.append(
|
|
448
|
+
ast.keyword(
|
|
449
|
+
arg="insert_function_field",
|
|
450
|
+
value=ast.Constant(value=insert_binding.field_name),
|
|
451
|
+
)
|
|
452
|
+
)
|
|
453
|
+
if insert_binding.function_type_class:
|
|
454
|
+
keywords.append(
|
|
455
|
+
ast.keyword(
|
|
456
|
+
arg="insert_function_type",
|
|
457
|
+
value=ast.Name(
|
|
458
|
+
id=insert_binding.function_type_class, ctx=ast.Load()
|
|
459
|
+
),
|
|
460
|
+
)
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
update_binding = self._function_bindings.update_relations.get(pkey)
|
|
464
|
+
if update_binding:
|
|
465
|
+
if (
|
|
466
|
+
update_binding.field_name
|
|
467
|
+
and update_binding.field_name != CompilerStrUtil.to_snake_case(pkey)
|
|
468
|
+
):
|
|
469
|
+
keywords.append(
|
|
470
|
+
ast.keyword(
|
|
471
|
+
arg="update_function_field",
|
|
472
|
+
value=ast.Constant(value=update_binding.field_name),
|
|
473
|
+
)
|
|
474
|
+
)
|
|
475
|
+
if update_binding.function_type_class:
|
|
476
|
+
keywords.append(
|
|
477
|
+
ast.keyword(
|
|
478
|
+
arg="update_function_type",
|
|
479
|
+
value=ast.Name(
|
|
480
|
+
id=update_binding.function_type_class, ctx=ast.Load()
|
|
481
|
+
),
|
|
482
|
+
)
|
|
483
|
+
)
|
|
484
|
+
|
|
436
485
|
# Tratando das opções básicas do descritor de propriedade
|
|
437
486
|
if properties_structure.required and pkey in properties_structure.required:
|
|
438
487
|
keywords.append(ast.keyword(arg="not_null", value=ast.Constant(True)))
|
|
@@ -518,6 +567,50 @@ class EDLPropertyCompiler:
|
|
|
518
567
|
),
|
|
519
568
|
]
|
|
520
569
|
|
|
570
|
+
insert_binding = self._function_bindings.insert_relations.get(pkey)
|
|
571
|
+
if insert_binding:
|
|
572
|
+
if (
|
|
573
|
+
insert_binding.field_name
|
|
574
|
+
and insert_binding.field_name != CompilerStrUtil.to_snake_case(pkey)
|
|
575
|
+
):
|
|
576
|
+
keywords.append(
|
|
577
|
+
ast.keyword(
|
|
578
|
+
arg="insert_function_field",
|
|
579
|
+
value=ast.Constant(value=insert_binding.field_name),
|
|
580
|
+
)
|
|
581
|
+
)
|
|
582
|
+
if insert_binding.function_type_class:
|
|
583
|
+
keywords.append(
|
|
584
|
+
ast.keyword(
|
|
585
|
+
arg="insert_function_type",
|
|
586
|
+
value=ast.Name(
|
|
587
|
+
id=insert_binding.function_type_class, ctx=ast.Load()
|
|
588
|
+
),
|
|
589
|
+
)
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
update_binding = self._function_bindings.update_relations.get(pkey)
|
|
593
|
+
if update_binding:
|
|
594
|
+
if (
|
|
595
|
+
update_binding.field_name
|
|
596
|
+
and update_binding.field_name != CompilerStrUtil.to_snake_case(pkey)
|
|
597
|
+
):
|
|
598
|
+
keywords.append(
|
|
599
|
+
ast.keyword(
|
|
600
|
+
arg="update_function_field",
|
|
601
|
+
value=ast.Constant(value=update_binding.field_name),
|
|
602
|
+
)
|
|
603
|
+
)
|
|
604
|
+
if update_binding.function_type_class:
|
|
605
|
+
keywords.append(
|
|
606
|
+
ast.keyword(
|
|
607
|
+
arg="update_function_type",
|
|
608
|
+
value=ast.Name(
|
|
609
|
+
id=update_binding.function_type_class, ctx=ast.Load()
|
|
610
|
+
),
|
|
611
|
+
)
|
|
612
|
+
)
|
|
613
|
+
|
|
521
614
|
# Tratando das opções básicas do descritor de propriedade
|
|
522
615
|
if properties_structure.required and pkey in properties_structure.required:
|
|
523
616
|
keywords.append(ast.keyword(arg="not_null", value=ast.Constant(True)))
|
|
@@ -861,6 +954,24 @@ class EDLPropertyCompiler:
|
|
|
861
954
|
)
|
|
862
955
|
)
|
|
863
956
|
|
|
957
|
+
insert_binding = self._function_bindings.insert_fields.get(pkey)
|
|
958
|
+
if insert_binding:
|
|
959
|
+
keywords.append(
|
|
960
|
+
ast.keyword(
|
|
961
|
+
arg="insert_function_field",
|
|
962
|
+
value=ast.Constant(value=insert_binding),
|
|
963
|
+
)
|
|
964
|
+
)
|
|
965
|
+
|
|
966
|
+
update_binding = self._function_bindings.update_fields.get(pkey)
|
|
967
|
+
if update_binding:
|
|
968
|
+
keywords.append(
|
|
969
|
+
ast.keyword(
|
|
970
|
+
arg="update_function_field",
|
|
971
|
+
value=ast.Constant(value=update_binding),
|
|
972
|
+
)
|
|
973
|
+
)
|
|
974
|
+
|
|
864
975
|
# Resolvendo o nome da propriedade no Entity
|
|
865
976
|
if (
|
|
866
977
|
properties_structure.entity_properties
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import uuid
|
|
2
|
+
from typing import Iterable
|
|
2
3
|
|
|
3
4
|
from nsj_rest_lib2.compiler.util.str_util import CompilerStrUtil
|
|
4
5
|
|
|
@@ -19,3 +20,24 @@ def compile_dto_class_name(entity_id: str, prefx_class_name: str = "") -> str:
|
|
|
19
20
|
|
|
20
21
|
def compile_entity_class_name(entity_id: str, prefx_class_name: str = "") -> str:
|
|
21
22
|
return f"{CompilerStrUtil.to_pascal_case(prefx_class_name)}{CompilerStrUtil.to_pascal_case(entity_id)}Entity"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def compile_function_class_name(
|
|
26
|
+
entity_id: str,
|
|
27
|
+
prefx_class_name: str,
|
|
28
|
+
path_parts: Iterable[str],
|
|
29
|
+
operation: str,
|
|
30
|
+
) -> str:
|
|
31
|
+
"""
|
|
32
|
+
Gera o nome da classe para FunctionTypes (insert/update),
|
|
33
|
+
incorporando o caminho dos relacionamentos (quando houver).
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
suffix = "InsertType" if operation == "insert" else "UpdateType"
|
|
37
|
+
path_suffix = "".join(CompilerStrUtil.to_pascal_case(part) for part in path_parts)
|
|
38
|
+
return (
|
|
39
|
+
f"{CompilerStrUtil.to_pascal_case(prefx_class_name)}"
|
|
40
|
+
f"{CompilerStrUtil.to_pascal_case(entity_id)}"
|
|
41
|
+
f"{path_suffix}"
|
|
42
|
+
f"{suffix}"
|
|
43
|
+
)
|
|
@@ -22,11 +22,12 @@ from nsj_rest_lib2.exception import MissingEntityConfigException
|
|
|
22
22
|
from nsj_rest_lib2.service.entity_loader import EntityLoader
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
def
|
|
25
|
+
def _get_query_args() -> tuple[str, str, bool]:
|
|
26
26
|
# Tentando ler do query args
|
|
27
27
|
query_args = request.args
|
|
28
28
|
tenant = query_args.get("tenant")
|
|
29
29
|
grupo_empresarial = query_args.get("grupo_empresarial")
|
|
30
|
+
force_reload = query_args.get("force_reload", "false").lower() == "true"
|
|
30
31
|
|
|
31
32
|
# Tentando ler do corpo da requisição
|
|
32
33
|
try:
|
|
@@ -40,7 +41,7 @@ def _get_tenant_grupo() -> tuple[str, str]:
|
|
|
40
41
|
except:
|
|
41
42
|
pass
|
|
42
43
|
|
|
43
|
-
return (str(tenant), str(grupo_empresarial))
|
|
44
|
+
return (str(tenant), str(grupo_empresarial), force_reload)
|
|
44
45
|
|
|
45
46
|
|
|
46
47
|
def _endpoint_name(func: Any, multidb: bool, root: str) -> str:
|
|
@@ -81,13 +82,8 @@ def setup_dynamic_routes(
|
|
|
81
82
|
if "entity_escopo" in kwargs:
|
|
82
83
|
entity_escopo = kwargs.pop("entity_escopo")
|
|
83
84
|
|
|
84
|
-
# Verificando se foi solicitado reload forçado do código
|
|
85
|
-
force_reload = False
|
|
86
|
-
if "force_reload" in kwargs:
|
|
87
|
-
force_reload = kwargs.pop("force_reload").lower() == "true"
|
|
88
|
-
|
|
89
85
|
# Lendo tenant e grupo_empresarial
|
|
90
|
-
tenant, grupo_empresarial =
|
|
86
|
+
tenant, grupo_empresarial, force_reload = _get_query_args()
|
|
91
87
|
|
|
92
88
|
try:
|
|
93
89
|
# Recuperando o código do DTO e Entity correspondente
|
|
@@ -98,6 +94,8 @@ def setup_dynamic_routes(
|
|
|
98
94
|
etities_dict,
|
|
99
95
|
api_expose,
|
|
100
96
|
api_verbs,
|
|
97
|
+
_insert_function_class_name,
|
|
98
|
+
_update_function_class_name,
|
|
101
99
|
) = entity_loader.load_entity_source(
|
|
102
100
|
entity_resource,
|
|
103
101
|
tenant,
|
|
@@ -140,13 +138,8 @@ def setup_dynamic_routes(
|
|
|
140
138
|
if "entity_escopo" in kwargs:
|
|
141
139
|
entity_escopo = kwargs.pop("entity_escopo")
|
|
142
140
|
|
|
143
|
-
# Verificando se foi solicitado reload forçado do código
|
|
144
|
-
force_reload = False
|
|
145
|
-
if "force_reload" in kwargs:
|
|
146
|
-
force_reload = kwargs.pop("force_reload").lower() == "true"
|
|
147
|
-
|
|
148
141
|
# Lendo tenant e grupo_empresarial
|
|
149
|
-
tenant, grupo_empresarial =
|
|
142
|
+
tenant, grupo_empresarial, force_reload = _get_query_args()
|
|
150
143
|
|
|
151
144
|
try:
|
|
152
145
|
# Recuperando o código do DTO e Entity correspondente
|
|
@@ -157,6 +150,8 @@ def setup_dynamic_routes(
|
|
|
157
150
|
etities_dict,
|
|
158
151
|
api_expose,
|
|
159
152
|
api_verbs,
|
|
153
|
+
_insert_function_class_name,
|
|
154
|
+
_update_function_class_name,
|
|
160
155
|
) = entity_loader.load_entity_source(
|
|
161
156
|
entity_resource,
|
|
162
157
|
tenant,
|
|
@@ -198,13 +193,8 @@ def setup_dynamic_routes(
|
|
|
198
193
|
if "entity_escopo" in kwargs:
|
|
199
194
|
entity_escopo = kwargs.pop("entity_escopo")
|
|
200
195
|
|
|
201
|
-
# Verificando se foi solicitado reload forçado do código
|
|
202
|
-
force_reload = False
|
|
203
|
-
if "force_reload" in kwargs:
|
|
204
|
-
force_reload = kwargs.pop("force_reload").lower() == "true"
|
|
205
|
-
|
|
206
196
|
# Lendo tenant e grupo_empresarial
|
|
207
|
-
tenant, grupo_empresarial =
|
|
197
|
+
tenant, grupo_empresarial, force_reload = _get_query_args()
|
|
208
198
|
|
|
209
199
|
try:
|
|
210
200
|
# Recuperando o código do DTO e Entity correspondente
|
|
@@ -215,6 +205,8 @@ def setup_dynamic_routes(
|
|
|
215
205
|
etities_dict,
|
|
216
206
|
api_expose,
|
|
217
207
|
api_verbs,
|
|
208
|
+
insert_function_class_name,
|
|
209
|
+
_update_function_class_name,
|
|
218
210
|
) = entity_loader.load_entity_source(
|
|
219
211
|
entity_resource,
|
|
220
212
|
tenant,
|
|
@@ -228,12 +220,19 @@ def setup_dynamic_routes(
|
|
|
228
220
|
return ("", 405, {})
|
|
229
221
|
|
|
230
222
|
# Executando o list pelo RestLib
|
|
223
|
+
insert_function_type_class = (
|
|
224
|
+
etities_dict.get(insert_function_class_name)
|
|
225
|
+
if insert_function_class_name
|
|
226
|
+
else None
|
|
227
|
+
)
|
|
228
|
+
|
|
231
229
|
route = PostRoute(
|
|
232
230
|
url=COLLECTION_DYNAMIC_ROUTE,
|
|
233
231
|
http_method="POST",
|
|
234
232
|
dto_class=etities_dict[dto_class_name],
|
|
235
233
|
entity_class=etities_dict[entity_class_name],
|
|
236
234
|
injector_factory=injector_factory,
|
|
235
|
+
insert_function_type_class=insert_function_type_class,
|
|
237
236
|
)
|
|
238
237
|
|
|
239
238
|
return route.handle_request(*args, **kwargs)
|
|
@@ -256,13 +255,8 @@ def setup_dynamic_routes(
|
|
|
256
255
|
if "entity_escopo" in kwargs:
|
|
257
256
|
entity_escopo = kwargs.pop("entity_escopo")
|
|
258
257
|
|
|
259
|
-
# Verificando se foi solicitado reload forçado do código
|
|
260
|
-
force_reload = False
|
|
261
|
-
if "force_reload" in kwargs:
|
|
262
|
-
force_reload = kwargs.pop("force_reload").lower() == "true"
|
|
263
|
-
|
|
264
258
|
# Lendo tenant e grupo_empresarial
|
|
265
|
-
tenant, grupo_empresarial =
|
|
259
|
+
tenant, grupo_empresarial, force_reload = _get_query_args()
|
|
266
260
|
|
|
267
261
|
try:
|
|
268
262
|
# Recuperando o código do DTO e Entity correspondente
|
|
@@ -273,6 +267,8 @@ def setup_dynamic_routes(
|
|
|
273
267
|
etities_dict,
|
|
274
268
|
api_expose,
|
|
275
269
|
api_verbs,
|
|
270
|
+
_insert_function_class_name,
|
|
271
|
+
update_function_class_name,
|
|
276
272
|
) = entity_loader.load_entity_source(
|
|
277
273
|
entity_resource,
|
|
278
274
|
tenant,
|
|
@@ -286,12 +282,19 @@ def setup_dynamic_routes(
|
|
|
286
282
|
return ("", 405, {})
|
|
287
283
|
|
|
288
284
|
# Executando o list pelo RestLib
|
|
285
|
+
update_function_type_class = (
|
|
286
|
+
etities_dict.get(update_function_class_name)
|
|
287
|
+
if update_function_class_name
|
|
288
|
+
else None
|
|
289
|
+
)
|
|
290
|
+
|
|
289
291
|
route = PutRoute(
|
|
290
292
|
url=ONE_DYNAMIC_ROUTE,
|
|
291
293
|
http_method="PUT",
|
|
292
294
|
dto_class=etities_dict[dto_class_name],
|
|
293
295
|
entity_class=etities_dict[entity_class_name],
|
|
294
296
|
injector_factory=injector_factory,
|
|
297
|
+
update_function_type_class=update_function_type_class,
|
|
295
298
|
)
|
|
296
299
|
|
|
297
300
|
return route.handle_request(*args, **kwargs)
|
|
@@ -314,13 +317,8 @@ def setup_dynamic_routes(
|
|
|
314
317
|
if "entity_escopo" in kwargs:
|
|
315
318
|
entity_escopo = kwargs.pop("entity_escopo")
|
|
316
319
|
|
|
317
|
-
# Verificando se foi solicitado reload forçado do código
|
|
318
|
-
force_reload = False
|
|
319
|
-
if "force_reload" in kwargs:
|
|
320
|
-
force_reload = kwargs.pop("force_reload").lower() == "true"
|
|
321
|
-
|
|
322
320
|
# Lendo tenant e grupo_empresarial
|
|
323
|
-
tenant, grupo_empresarial =
|
|
321
|
+
tenant, grupo_empresarial, force_reload = _get_query_args()
|
|
324
322
|
|
|
325
323
|
try:
|
|
326
324
|
# Recuperando o código do DTO e Entity correspondente
|
|
@@ -331,6 +329,8 @@ def setup_dynamic_routes(
|
|
|
331
329
|
etities_dict,
|
|
332
330
|
api_expose,
|
|
333
331
|
api_verbs,
|
|
332
|
+
_insert_function_class_name,
|
|
333
|
+
_update_function_class_name,
|
|
334
334
|
) = entity_loader.load_entity_source(
|
|
335
335
|
entity_resource,
|
|
336
336
|
tenant,
|
|
@@ -372,13 +372,8 @@ def setup_dynamic_routes(
|
|
|
372
372
|
if "entity_escopo" in kwargs:
|
|
373
373
|
entity_escopo = kwargs.pop("entity_escopo")
|
|
374
374
|
|
|
375
|
-
# Verificando se foi solicitado reload forçado do código
|
|
376
|
-
force_reload = False
|
|
377
|
-
if "force_reload" in kwargs:
|
|
378
|
-
force_reload = kwargs.pop("force_reload").lower() == "true"
|
|
379
|
-
|
|
380
375
|
# Lendo tenant e grupo_empresarial
|
|
381
|
-
tenant, grupo_empresarial =
|
|
376
|
+
tenant, grupo_empresarial, force_reload = _get_query_args()
|
|
382
377
|
|
|
383
378
|
try:
|
|
384
379
|
# Recuperando o código do DTO e Entity correspondente
|
|
@@ -389,6 +384,8 @@ def setup_dynamic_routes(
|
|
|
389
384
|
etities_dict,
|
|
390
385
|
api_expose,
|
|
391
386
|
api_verbs,
|
|
387
|
+
_insert_function_class_name,
|
|
388
|
+
_update_function_class_name,
|
|
392
389
|
) = entity_loader.load_entity_source(
|
|
393
390
|
entity_resource,
|
|
394
391
|
tenant,
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
from typing import Any, Dict, Iterator, Optional
|
|
6
|
+
|
|
7
|
+
from nsj_rest_lib2.compiler.edl_model.entity_model import EntityModel
|
|
8
|
+
from nsj_rest_lib2.compiler.edl_model.entity_model_base import EntityModelBase
|
|
9
|
+
from nsj_rest_lib2.compiler.model import CompilerResult
|
|
10
|
+
from nsj_rest_lib2.compiler.util.type_naming_util import compile_namespace_keys
|
|
11
|
+
from nsj_rest_lib2.redis_config import set_redis
|
|
12
|
+
from nsj_rest_lib2.settings import ESCOPO_RESTLIB2
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class EntityConfigWriter:
|
|
16
|
+
"""
|
|
17
|
+
Serializa o resultado da compilação e publica no Redis usando o mesmo
|
|
18
|
+
layout consumido pelo EntityLoader.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, escopo: str = ESCOPO_RESTLIB2) -> None:
|
|
22
|
+
self._escopo = escopo or ESCOPO_RESTLIB2
|
|
23
|
+
|
|
24
|
+
def publish(
|
|
25
|
+
self,
|
|
26
|
+
entity_model: EntityModelBase,
|
|
27
|
+
compiler_result: CompilerResult,
|
|
28
|
+
*,
|
|
29
|
+
entity_hash: str | None = None,
|
|
30
|
+
) -> Dict[str, Any]:
|
|
31
|
+
"""
|
|
32
|
+
Serializa e grava o resultado da compilação no Redis.
|
|
33
|
+
|
|
34
|
+
:return: Payload serializado (útil para inspeção/testes).
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
payload = self.build_payload(
|
|
38
|
+
entity_model, compiler_result, entity_hash=entity_hash
|
|
39
|
+
)
|
|
40
|
+
namespace_key = self._resolve_namespace_key(entity_model)
|
|
41
|
+
resource = self._resolve_resource(entity_model)
|
|
42
|
+
|
|
43
|
+
set_redis(
|
|
44
|
+
"entity_config",
|
|
45
|
+
self._escopo,
|
|
46
|
+
namespace_key,
|
|
47
|
+
resource,
|
|
48
|
+
json.dumps(payload, ensure_ascii=False),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
return payload
|
|
52
|
+
|
|
53
|
+
def build_payload(
|
|
54
|
+
self,
|
|
55
|
+
entity_model: EntityModelBase,
|
|
56
|
+
compiler_result: CompilerResult,
|
|
57
|
+
*,
|
|
58
|
+
entity_hash: str | None = None,
|
|
59
|
+
) -> Dict[str, Any]:
|
|
60
|
+
"""
|
|
61
|
+
Constrói o dicionário serializável que representa a entidade compilada.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
resource = self._resolve_resource(entity_model)
|
|
65
|
+
relations = [
|
|
66
|
+
rd.to_dict()
|
|
67
|
+
for rd in (compiler_result.relations_dependencies or [])
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
"dto_class_name": compiler_result.dto_class_name,
|
|
72
|
+
"entity_class_name": compiler_result.entity_class_name,
|
|
73
|
+
"insert_function_class_name": compiler_result.insert_function_class_name,
|
|
74
|
+
"source_insert_function": compiler_result.source_insert_function,
|
|
75
|
+
"update_function_class_name": compiler_result.update_function_class_name,
|
|
76
|
+
"source_update_function": compiler_result.source_update_function,
|
|
77
|
+
"source_dto": compiler_result.dto_code,
|
|
78
|
+
"source_entity": compiler_result.entity_code,
|
|
79
|
+
"entity_hash": entity_hash
|
|
80
|
+
if entity_hash is not None
|
|
81
|
+
else self._build_entity_hash(compiler_result),
|
|
82
|
+
"api_expose": compiler_result.api_expose,
|
|
83
|
+
"api_resource": resource,
|
|
84
|
+
"api_verbs": compiler_result.api_verbs or [],
|
|
85
|
+
"relations_dependencies": relations,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
def _resolve_namespace_key(self, entity_model: EntityModelBase) -> str:
|
|
89
|
+
tenant = getattr(entity_model, "tenant", None)
|
|
90
|
+
grupo_empresarial = getattr(entity_model, "grupo_empresarial", None)
|
|
91
|
+
|
|
92
|
+
grupo_key, tenant_key, default_key = compile_namespace_keys(
|
|
93
|
+
tenant,
|
|
94
|
+
grupo_empresarial,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
if (
|
|
98
|
+
tenant
|
|
99
|
+
and tenant != 0
|
|
100
|
+
and grupo_empresarial
|
|
101
|
+
and str(grupo_empresarial) != "00000000-0000-0000-0000-000000000000"
|
|
102
|
+
):
|
|
103
|
+
return grupo_key
|
|
104
|
+
if tenant and tenant != 0:
|
|
105
|
+
return tenant_key
|
|
106
|
+
return default_key
|
|
107
|
+
|
|
108
|
+
def _resolve_resource(self, entity_model: EntityModelBase) -> str:
|
|
109
|
+
if not isinstance(entity_model, EntityModel) or not entity_model.api:
|
|
110
|
+
raise ValueError(
|
|
111
|
+
"EntityModel precisa possuir bloco de API para publicação no Redis."
|
|
112
|
+
)
|
|
113
|
+
if not entity_model.api.resource:
|
|
114
|
+
raise ValueError("api.resource é obrigatório para publicação no Redis.")
|
|
115
|
+
return entity_model.api.resource
|
|
116
|
+
|
|
117
|
+
def _build_entity_hash(self, compiler_result: CompilerResult) -> str:
|
|
118
|
+
hasher = hashlib.sha256()
|
|
119
|
+
|
|
120
|
+
for content in self._iter_hash_chunks(
|
|
121
|
+
compiler_result.dto_code,
|
|
122
|
+
compiler_result.entity_code,
|
|
123
|
+
compiler_result.source_insert_function,
|
|
124
|
+
compiler_result.source_update_function,
|
|
125
|
+
):
|
|
126
|
+
hasher.update(content)
|
|
127
|
+
|
|
128
|
+
return hasher.hexdigest()
|
|
129
|
+
|
|
130
|
+
@staticmethod
|
|
131
|
+
def _iter_hash_chunks(*chunks: Optional[str]) -> Iterator[bytes]:
|
|
132
|
+
for chunk in chunks:
|
|
133
|
+
if chunk:
|
|
134
|
+
yield chunk.encode("utf-8")
|
|
@@ -24,6 +24,8 @@ class LoadedEntity:
|
|
|
24
24
|
self.api_expose: bool = False
|
|
25
25
|
self.api_verbs: list[str] = []
|
|
26
26
|
self.relations_dependencies: list[RelationDependency] = []
|
|
27
|
+
self.insert_function_class_name: str | None = None
|
|
28
|
+
self.update_function_class_name: str | None = None
|
|
27
29
|
|
|
28
30
|
|
|
29
31
|
class Namespace:
|
|
@@ -48,7 +50,7 @@ class EntityLoader:
|
|
|
48
50
|
grupo_empresarial: str | None,
|
|
49
51
|
escopo: str = ESCOPO_RESTLIB2,
|
|
50
52
|
force_reload: bool = False,
|
|
51
|
-
) -> tuple[str, str, dict, bool, list[str]]:
|
|
53
|
+
) -> tuple[str, str, dict, bool, list[str], str | None, str | None]:
|
|
52
54
|
# Assumind o escopo default se necessário
|
|
53
55
|
if not escopo:
|
|
54
56
|
escopo = ESCOPO_RESTLIB2
|
|
@@ -77,6 +79,8 @@ class EntityLoader:
|
|
|
77
79
|
api_expose = loaded_entity.api_expose
|
|
78
80
|
api_verbs = loaded_entity.api_verbs
|
|
79
81
|
relations_dependencies = loaded_entity.relations_dependencies
|
|
82
|
+
insert_function_class_name = loaded_entity.insert_function_class_name
|
|
83
|
+
update_function_class_name = loaded_entity.update_function_class_name
|
|
80
84
|
|
|
81
85
|
# Verificando se alguma de suas dependências precisariam ser recarregadas
|
|
82
86
|
for rd in relations_dependencies:
|
|
@@ -122,6 +126,8 @@ class EntityLoader:
|
|
|
122
126
|
entities_dict,
|
|
123
127
|
api_expose,
|
|
124
128
|
api_verbs,
|
|
129
|
+
insert_function_class_name,
|
|
130
|
+
update_function_class_name,
|
|
125
131
|
)
|
|
126
132
|
|
|
127
133
|
# Desempacotando resultado
|
|
@@ -143,6 +149,8 @@ class EntityLoader:
|
|
|
143
149
|
entities_dict,
|
|
144
150
|
api_expose,
|
|
145
151
|
api_verbs,
|
|
152
|
+
insert_function_class_name,
|
|
153
|
+
update_function_class_name,
|
|
146
154
|
)
|
|
147
155
|
else:
|
|
148
156
|
(
|
|
@@ -167,6 +175,8 @@ class EntityLoader:
|
|
|
167
175
|
entities_dict,
|
|
168
176
|
api_expose,
|
|
169
177
|
api_verbs,
|
|
178
|
+
insert_function_class_name,
|
|
179
|
+
update_function_class_name,
|
|
170
180
|
)
|
|
171
181
|
|
|
172
182
|
# Se não conseguir recuperar a entidade, procura no redis:
|
|
@@ -195,9 +205,15 @@ class EntityLoader:
|
|
|
195
205
|
raise RuntimeError(
|
|
196
206
|
f"Erro desconhecido carregando entidade: {entity_resource}"
|
|
197
207
|
)
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
208
|
+
(
|
|
209
|
+
dto_class_name,
|
|
210
|
+
entity_class_name,
|
|
211
|
+
namespace,
|
|
212
|
+
api_expose,
|
|
213
|
+
api_verbs,
|
|
214
|
+
insert_function_class_name,
|
|
215
|
+
update_function_class_name,
|
|
216
|
+
) = result_execute
|
|
201
217
|
|
|
202
218
|
return (
|
|
203
219
|
dto_class_name,
|
|
@@ -205,6 +221,8 @@ class EntityLoader:
|
|
|
205
221
|
namespace.entities_dict,
|
|
206
222
|
api_expose,
|
|
207
223
|
api_verbs,
|
|
224
|
+
insert_function_class_name,
|
|
225
|
+
update_function_class_name,
|
|
208
226
|
)
|
|
209
227
|
|
|
210
228
|
def clear_namespaces(self):
|
|
@@ -235,7 +253,7 @@ class EntityLoader:
|
|
|
235
253
|
entity_config_key: str,
|
|
236
254
|
entity_resource: str,
|
|
237
255
|
check_refresh: bool = False,
|
|
238
|
-
) -> tuple[str, str, Namespace, bool, list[str]] | None:
|
|
256
|
+
) -> tuple[str, str, Namespace, bool, list[str], str | None, str | None] | None:
|
|
239
257
|
# Interpretando o json de configuração da entidade
|
|
240
258
|
try:
|
|
241
259
|
entity_config = json.loads(entity_config_str)
|
|
@@ -249,6 +267,14 @@ class EntityLoader:
|
|
|
249
267
|
api_expose = entity_config["api_expose"]
|
|
250
268
|
# api_resource = entity_config["api_resource"]
|
|
251
269
|
api_verbs = entity_config["api_verbs"]
|
|
270
|
+
insert_function_class_name = entity_config.get(
|
|
271
|
+
"insert_function_class_name"
|
|
272
|
+
)
|
|
273
|
+
insert_function_code = entity_config.get("source_insert_function")
|
|
274
|
+
update_function_class_name = entity_config.get(
|
|
275
|
+
"update_function_class_name"
|
|
276
|
+
)
|
|
277
|
+
update_function_code = entity_config.get("source_update_function")
|
|
252
278
|
relations_dependencies = [
|
|
253
279
|
RelationDependency().from_dict(rd)
|
|
254
280
|
for rd in entity_config.get("relations_dependencies", [])
|
|
@@ -331,6 +357,20 @@ class EntityLoader:
|
|
|
331
357
|
get_logger().debug(f"Entity source:\n{source_entity}")
|
|
332
358
|
get_logger().debug(f"DTO source:\n{source_dto}")
|
|
333
359
|
|
|
360
|
+
if insert_function_code:
|
|
361
|
+
self._safe_exec(
|
|
362
|
+
insert_function_code,
|
|
363
|
+
namespace.entities_dict,
|
|
364
|
+
"Insert Function source",
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
if update_function_code:
|
|
368
|
+
self._safe_exec(
|
|
369
|
+
update_function_code,
|
|
370
|
+
namespace.entities_dict,
|
|
371
|
+
"Update Function source",
|
|
372
|
+
)
|
|
373
|
+
|
|
334
374
|
self._safe_exec(source_entity, namespace.entities_dict, "Entity source")
|
|
335
375
|
self._safe_exec(source_dto, namespace.entities_dict, "DTO source")
|
|
336
376
|
|
|
@@ -342,10 +382,20 @@ class EntityLoader:
|
|
|
342
382
|
loaded_entity.api_expose = api_expose
|
|
343
383
|
loaded_entity.api_verbs = api_verbs
|
|
344
384
|
loaded_entity.relations_dependencies = relations_dependencies
|
|
385
|
+
loaded_entity.insert_function_class_name = insert_function_class_name
|
|
386
|
+
loaded_entity.update_function_class_name = update_function_class_name
|
|
345
387
|
|
|
346
388
|
namespace.loaded_entities[entity_resource] = loaded_entity
|
|
347
389
|
|
|
348
|
-
return (
|
|
390
|
+
return (
|
|
391
|
+
dto_class_name,
|
|
392
|
+
entity_class_name,
|
|
393
|
+
namespace,
|
|
394
|
+
api_expose,
|
|
395
|
+
api_verbs,
|
|
396
|
+
insert_function_class_name,
|
|
397
|
+
update_function_class_name,
|
|
398
|
+
)
|
|
349
399
|
|
|
350
400
|
def _safe_exec(self, source_code, context, description):
|
|
351
401
|
try:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nsj_rest_lib2
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.27
|
|
4
4
|
Summary: Biblioteca para permitir a distribuição de rotas dinâmicas numa API, configuradas por meio de EDLs declarativos (em formato JSON).
|
|
5
5
|
Home-page: https://github.com/Nasajon/nsj_rest_lib2
|
|
6
6
|
Author: Nasajon Sistemas
|