nsj-rest-lib2 0.0.25__tar.gz → 0.0.27__tar.gz
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-0.0.25 → nsj_rest_lib2-0.0.27}/PKG-INFO +1 -1
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/compiler.py +81 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/dto_compiler.py +1 -1
- nsj_rest_lib2-0.0.27/nsj_rest_lib2/compiler/edl_model/api_model.py +116 -0
- nsj_rest_lib2-0.0.27/nsj_rest_lib2/compiler/function_compiler.py +550 -0
- nsj_rest_lib2-0.0.27/nsj_rest_lib2/compiler/function_model.py +70 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/model.py +4 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/property_compiler.py +111 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/util/type_naming_util.py +22 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/controller/dynamic_controller.py +35 -38
- nsj_rest_lib2-0.0.27/nsj_rest_lib2/service/entity_config_writer.py +134 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/service/entity_loader.py +56 -6
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2.egg-info/PKG-INFO +1 -1
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2.egg-info/SOURCES.txt +6 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/setup.cfg +1 -1
- nsj_rest_lib2-0.0.25/nsj_rest_lib2/compiler/edl_model/api_model.py +0 -23
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/README.md +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/__init__.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/__init__.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/ai_compiler.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/compiler_structures.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/__init__.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/ai_entity_edl.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/column_meta_model.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/entity_model.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/entity_model_base.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/entity_model_root.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/index_model.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/primitives.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/property_meta_model.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/repository_model.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/trait_property_meta_model.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/entity_compiler.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/util/__init__.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/util/str_util.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/util/type_util.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/controller/__init__.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/exception.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/redis_config.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/service/__init__.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/settings.py +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2.egg-info/dependency_links.txt +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2.egg-info/requires.txt +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2.egg-info/top_level.txt +0 -0
- {nsj_rest_lib2-0.0.25 → nsj_rest_lib2-0.0.27}/pyproject.toml +0 -0
|
@@ -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
|
|
@@ -8,6 +8,14 @@ from nsj_rest_lib2.compiler.compiler_structures import (
|
|
|
8
8
|
PropertiesCompilerStructure,
|
|
9
9
|
)
|
|
10
10
|
from nsj_rest_lib2.compiler.dto_compiler import DTOCompiler
|
|
11
|
+
from nsj_rest_lib2.compiler.function_compiler import (
|
|
12
|
+
FunctionCompiler,
|
|
13
|
+
inject_function_bindings,
|
|
14
|
+
)
|
|
15
|
+
from nsj_rest_lib2.compiler.function_model import (
|
|
16
|
+
FunctionBindingConfig,
|
|
17
|
+
FunctionCompilationOutput,
|
|
18
|
+
)
|
|
11
19
|
from nsj_rest_lib2.compiler.edl_model.entity_model_base import EntityModelBase
|
|
12
20
|
from nsj_rest_lib2.compiler.edl_model.entity_model_root import EntityModelRoot
|
|
13
21
|
from nsj_rest_lib2.compiler.edl_model.primitives import REGEX_EXTERNAL_REF
|
|
@@ -31,6 +39,7 @@ class EDLCompiler:
|
|
|
31
39
|
self._properties_compiler = EDLPropertyCompiler()
|
|
32
40
|
self._dto_compiler = DTOCompiler()
|
|
33
41
|
self._entity_compiler = EntityCompiler()
|
|
42
|
+
self._function_compiler = FunctionCompiler()
|
|
34
43
|
|
|
35
44
|
def compile_models(
|
|
36
45
|
self, entity_models: dict[str, EntityModel]
|
|
@@ -130,6 +139,45 @@ class EDLCompiler:
|
|
|
130
139
|
properties_structure, entity_model, entity_models
|
|
131
140
|
)
|
|
132
141
|
|
|
142
|
+
function_bindings = FunctionBindingConfig()
|
|
143
|
+
insert_output = FunctionCompilationOutput()
|
|
144
|
+
update_output = FunctionCompilationOutput()
|
|
145
|
+
insert_function_code = ""
|
|
146
|
+
update_function_code = ""
|
|
147
|
+
|
|
148
|
+
if isinstance(entity_model, EntityModel) and entity_model.api:
|
|
149
|
+
handlers = {}
|
|
150
|
+
if entity_model.api.handlers:
|
|
151
|
+
handlers = {
|
|
152
|
+
(verb or "").lower(): handler
|
|
153
|
+
for verb, handler in entity_model.api.handlers.items()
|
|
154
|
+
if handler
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
insert_output = self._function_compiler.compile_insert(
|
|
158
|
+
entity_model,
|
|
159
|
+
properties_structure,
|
|
160
|
+
handlers.get("post"),
|
|
161
|
+
prefx_class_name,
|
|
162
|
+
)
|
|
163
|
+
update_output = self._function_compiler.compile_update(
|
|
164
|
+
entity_model,
|
|
165
|
+
properties_structure,
|
|
166
|
+
handlers.get("put"),
|
|
167
|
+
prefx_class_name,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
inject_function_bindings(
|
|
171
|
+
function_bindings,
|
|
172
|
+
insert_output,
|
|
173
|
+
update_output,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
if insert_output.code:
|
|
177
|
+
insert_function_code += insert_output.code + "\n\n"
|
|
178
|
+
if update_output.code:
|
|
179
|
+
update_function_code += update_output.code + "\n\n"
|
|
180
|
+
|
|
133
181
|
# Criando a lista de atributos do DTO e da Entity; e recuperando as chaves primarias
|
|
134
182
|
(
|
|
135
183
|
ast_dto_attributes,
|
|
@@ -146,6 +194,7 @@ class EDLCompiler:
|
|
|
146
194
|
entity_model,
|
|
147
195
|
entity_models,
|
|
148
196
|
prefx_class_name,
|
|
197
|
+
function_bindings=function_bindings,
|
|
149
198
|
)
|
|
150
199
|
|
|
151
200
|
# Adicionando os imports da extensão parcial
|
|
@@ -195,6 +244,14 @@ class EDLCompiler:
|
|
|
195
244
|
relations_dependencies_complete.extend(
|
|
196
245
|
component_compiled.relations_dependencies
|
|
197
246
|
)
|
|
247
|
+
if component_compiled.source_insert_function:
|
|
248
|
+
insert_function_code += (
|
|
249
|
+
component_compiled.source_insert_function + "\n\n"
|
|
250
|
+
)
|
|
251
|
+
if component_compiled.source_update_function:
|
|
252
|
+
update_function_code += (
|
|
253
|
+
component_compiled.source_update_function + "\n\n"
|
|
254
|
+
)
|
|
198
255
|
|
|
199
256
|
# Gerando o código do DTO
|
|
200
257
|
dto_class_name, code_dto = self._dto_compiler.compile(
|
|
@@ -243,6 +300,17 @@ class EDLCompiler:
|
|
|
243
300
|
compiler_result.dto_class_name = dto_class_name
|
|
244
301
|
compiler_result.dto_code = dto_code
|
|
245
302
|
compiler_result.relations_dependencies = relations_dependencies_complete
|
|
303
|
+
compiler_result.insert_function_class_name = insert_output.class_name
|
|
304
|
+
compiler_result.update_function_class_name = update_output.class_name
|
|
305
|
+
|
|
306
|
+
insert_code_compiled = insert_function_code.strip()
|
|
307
|
+
update_code_compiled = update_function_code.strip()
|
|
308
|
+
compiler_result.source_insert_function = (
|
|
309
|
+
insert_code_compiled if insert_code_compiled else None
|
|
310
|
+
)
|
|
311
|
+
compiler_result.source_update_function = (
|
|
312
|
+
update_code_compiled if update_code_compiled else None
|
|
313
|
+
)
|
|
246
314
|
|
|
247
315
|
# Compilando questões das APIs
|
|
248
316
|
if isinstance(entity_model, EntityModel):
|
|
@@ -706,6 +774,19 @@ if __name__ == "__main__":
|
|
|
706
774
|
f.write(f"DTO: {compiler_result.dto_class_name}\n")
|
|
707
775
|
f.write(f"{compiler_result.dto_code}\n")
|
|
708
776
|
f.write("\n")
|
|
777
|
+
if compiler_result.insert_function_class_name:
|
|
778
|
+
f.write("==========================================================\n")
|
|
779
|
+
f.write(
|
|
780
|
+
f"Insert Function Type: {compiler_result.insert_function_class_name}\n"
|
|
781
|
+
)
|
|
782
|
+
f.write(f"{compiler_result.source_insert_function or ''}\n")
|
|
783
|
+
if compiler_result.update_function_class_name:
|
|
784
|
+
f.write("==========================================================\n")
|
|
785
|
+
f.write(
|
|
786
|
+
f"Update Function Type: {compiler_result.update_function_class_name}\n"
|
|
787
|
+
)
|
|
788
|
+
f.write(f"{compiler_result.source_update_function or ''}\n")
|
|
789
|
+
f.write("\n")
|
|
709
790
|
f.write("==========================================================\n")
|
|
710
791
|
f.write(f"API Expose: {compiler_result.api_expose}\n")
|
|
711
792
|
f.write(f"API Route Path: {compiler_result.api_resource}\n")
|
|
@@ -89,7 +89,7 @@ class DTOCompiler:
|
|
|
89
89
|
),
|
|
90
90
|
# from nsj_rest_lib.descriptor import DTOAggregator
|
|
91
91
|
ast.ImportFrom(
|
|
92
|
-
module="nsj_rest_lib.descriptor",
|
|
92
|
+
module="nsj_rest_lib.descriptor.dto_aggregator",
|
|
93
93
|
names=[ast.alias(name="DTOAggregator", asname=None)],
|
|
94
94
|
level=0,
|
|
95
95
|
),
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List, Literal, Optional
|
|
4
|
+
|
|
5
|
+
from pydantic import AliasChoices, BaseModel, Field
|
|
6
|
+
|
|
7
|
+
APIVerbs = Literal["GET", "POST", "PUT", "DELETE", "PATCH"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class HandlerMapping(BaseModel):
|
|
11
|
+
attr: str = Field(..., description="Nome do atributo no tipo composto de destino.")
|
|
12
|
+
from_: Optional[str] = Field(
|
|
13
|
+
default=None,
|
|
14
|
+
validation_alias=AliasChoices("from", "from_"),
|
|
15
|
+
serialization_alias="from",
|
|
16
|
+
description="Path de origem no payload (ex.: body.estabelecimento).",
|
|
17
|
+
)
|
|
18
|
+
as_: Optional[str] = Field(
|
|
19
|
+
default=None,
|
|
20
|
+
validation_alias=AliasChoices("as", "as_"),
|
|
21
|
+
serialization_alias="as",
|
|
22
|
+
description="Tipo composto do elemento quando houver arrays (ex.: ns.t_item[]).",
|
|
23
|
+
)
|
|
24
|
+
mapping: Optional[List["HandlerMapping"]] = Field(
|
|
25
|
+
default=None,
|
|
26
|
+
description="Sub-mapeamento utilizado quando 'from' aponta para coleções.",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class HandlerArgBinding(BaseModel):
|
|
31
|
+
type_name: str = Field(
|
|
32
|
+
...,
|
|
33
|
+
description="Nome qualificado do tipo composto esperado pela função no banco.",
|
|
34
|
+
)
|
|
35
|
+
mapping: List[HandlerMapping] = Field(
|
|
36
|
+
...,
|
|
37
|
+
description="Mapeamento dos campos do payload para os atributos do tipo composto.",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class HandlerCall(BaseModel):
|
|
42
|
+
arg_binding: HandlerArgBinding = Field(
|
|
43
|
+
...,
|
|
44
|
+
description="Configuração de binding do payload para o tipo composto.",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class HandlerResult(BaseModel):
|
|
49
|
+
expected: Literal["empty", "entity_row"] = Field(
|
|
50
|
+
default="empty",
|
|
51
|
+
description="Define o formato esperado do retorno da função.",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class HandlerError(BaseModel):
|
|
56
|
+
sqlstate: Optional[str] = Field(
|
|
57
|
+
default=None,
|
|
58
|
+
description="Código SQLSTATE tratado explicitamente.",
|
|
59
|
+
)
|
|
60
|
+
http_status: Optional[int] = Field(
|
|
61
|
+
default=None,
|
|
62
|
+
description="Código HTTP retornado quando o SQLSTATE for encontrado.",
|
|
63
|
+
)
|
|
64
|
+
message: Optional[str] = Field(
|
|
65
|
+
default=None,
|
|
66
|
+
description="Mensagem alternativa retornada quando o erro for capturado.",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class HandlerConfig(BaseModel):
|
|
71
|
+
impl: Literal["pg_function"] = Field(
|
|
72
|
+
...,
|
|
73
|
+
description="Somente funções PostgreSQL (pg_function) são suportadas neste estágio.",
|
|
74
|
+
)
|
|
75
|
+
function_ref: str = Field(
|
|
76
|
+
...,
|
|
77
|
+
description="Referência qualificada para a função no banco (ex.: schema.fn_nome).",
|
|
78
|
+
)
|
|
79
|
+
call: Optional[HandlerCall] = Field(
|
|
80
|
+
default=None,
|
|
81
|
+
description="Configuração de chamada (binding de argumentos).",
|
|
82
|
+
)
|
|
83
|
+
result: HandlerResult = Field(
|
|
84
|
+
default_factory=HandlerResult,
|
|
85
|
+
description="Especificação do que se espera da função.",
|
|
86
|
+
)
|
|
87
|
+
errors: Optional[List[HandlerError]] = Field(
|
|
88
|
+
default=None,
|
|
89
|
+
description="Tratamento específico para SQLSTATE conhecidos.",
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class APIModel(BaseModel):
|
|
94
|
+
resource: str = Field(
|
|
95
|
+
...,
|
|
96
|
+
description="Nome do recurso REST (rota base dos endpoints; exemplo: 'clientes').",
|
|
97
|
+
)
|
|
98
|
+
expose: Optional[bool] = Field(
|
|
99
|
+
default=True,
|
|
100
|
+
description="Indica se a API deve ser exposta (padrão: True).",
|
|
101
|
+
)
|
|
102
|
+
verbs: Optional[List[APIVerbs]] = Field(
|
|
103
|
+
default=["GET", "POST", "PUT", "DELETE", "PATCH"],
|
|
104
|
+
description="Lista de verbos HTTP suportados pela API (padrão: todos).",
|
|
105
|
+
)
|
|
106
|
+
default_sort: Optional[List[str]] = Field(
|
|
107
|
+
None,
|
|
108
|
+
description="Lista de campos usados na ordenação padrão (padrão: se nada for fornecido, será usada, ao menos, a PK).",
|
|
109
|
+
)
|
|
110
|
+
handlers: Optional[Dict[str, HandlerConfig]] = Field(
|
|
111
|
+
default=None,
|
|
112
|
+
description="Mapeamento opcional de verbos para handlers implementados via funções pg_function.",
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
APIModel.model_rebuild()
|