nsj-rest-lib2 0.0.26__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.
Files changed (45) hide show
  1. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/PKG-INFO +1 -1
  2. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/compiler.py +81 -0
  3. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/dto_compiler.py +1 -1
  4. nsj_rest_lib2-0.0.27/nsj_rest_lib2/compiler/edl_model/api_model.py +116 -0
  5. nsj_rest_lib2-0.0.27/nsj_rest_lib2/compiler/function_compiler.py +550 -0
  6. nsj_rest_lib2-0.0.27/nsj_rest_lib2/compiler/function_model.py +70 -0
  7. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/model.py +4 -0
  8. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/property_compiler.py +111 -0
  9. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/util/type_naming_util.py +22 -0
  10. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/controller/dynamic_controller.py +26 -0
  11. nsj_rest_lib2-0.0.27/nsj_rest_lib2/service/entity_config_writer.py +134 -0
  12. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/service/entity_loader.py +56 -6
  13. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2.egg-info/PKG-INFO +1 -1
  14. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2.egg-info/SOURCES.txt +6 -0
  15. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/setup.cfg +1 -1
  16. nsj_rest_lib2-0.0.26/nsj_rest_lib2/compiler/edl_model/api_model.py +0 -23
  17. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/README.md +0 -0
  18. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/__init__.py +0 -0
  19. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/__init__.py +0 -0
  20. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/ai_compiler.py +0 -0
  21. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/compiler_structures.py +0 -0
  22. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/__init__.py +0 -0
  23. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/ai_entity_edl.py +0 -0
  24. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/column_meta_model.py +0 -0
  25. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/entity_model.py +0 -0
  26. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/entity_model_base.py +0 -0
  27. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/entity_model_root.py +0 -0
  28. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/index_model.py +0 -0
  29. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/primitives.py +0 -0
  30. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/property_meta_model.py +0 -0
  31. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/repository_model.py +0 -0
  32. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/edl_model/trait_property_meta_model.py +0 -0
  33. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/entity_compiler.py +0 -0
  34. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/util/__init__.py +0 -0
  35. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/util/str_util.py +0 -0
  36. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/compiler/util/type_util.py +0 -0
  37. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/controller/__init__.py +0 -0
  38. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/exception.py +0 -0
  39. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/redis_config.py +0 -0
  40. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/service/__init__.py +0 -0
  41. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2/settings.py +0 -0
  42. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2.egg-info/dependency_links.txt +0 -0
  43. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2.egg-info/requires.txt +0 -0
  44. {nsj_rest_lib2-0.0.26 → nsj_rest_lib2-0.0.27}/nsj_rest_lib2.egg-info/top_level.txt +0 -0
  45. {nsj_rest_lib2-0.0.26 → 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.26
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()