nsj-rest-lib2 0.0.7__tar.gz → 0.0.8__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 (37) hide show
  1. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/PKG-INFO +1 -1
  2. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/compiler.py +16 -5
  3. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/edl_model/entity_model.py +2 -2
  4. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/property_compiler.py +20 -10
  5. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/controller/dynamic_controller.py +92 -44
  6. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/service/entity_loader.py +91 -34
  7. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2.egg-info/PKG-INFO +1 -1
  8. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/setup.cfg +1 -1
  9. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/README.md +0 -0
  10. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/__init__.py +0 -0
  11. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/__init__.py +0 -0
  12. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/ai_compiler.py +0 -0
  13. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/compiler_structures.py +0 -0
  14. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/dto_compiler.py +0 -0
  15. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/edl_model/__init__.py +0 -0
  16. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/edl_model/ai_entity_edl.py +0 -0
  17. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/edl_model/api_model.py +0 -0
  18. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/edl_model/column_meta_model.py +0 -0
  19. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/edl_model/index_model.py +0 -0
  20. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/edl_model/primitives.py +0 -0
  21. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/edl_model/property_meta_model.py +0 -0
  22. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/edl_model/repository_model.py +0 -0
  23. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/edl_model/trait_property_meta_model.py +0 -0
  24. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/entity_compiler.py +0 -0
  25. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/util/__init__.py +0 -0
  26. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/util/str_util.py +0 -0
  27. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/compiler/util/type_util.py +0 -0
  28. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/controller/__init__.py +0 -0
  29. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/exception.py +0 -0
  30. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/redis_config.py +0 -0
  31. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/service/__init__.py +0 -0
  32. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2/settings.py +0 -0
  33. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2.egg-info/SOURCES.txt +0 -0
  34. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2.egg-info/dependency_links.txt +0 -0
  35. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2.egg-info/requires.txt +0 -0
  36. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/nsj_rest_lib2.egg-info/top_level.txt +0 -0
  37. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.8}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nsj_rest_lib2
3
- Version: 0.0.7
3
+ Version: 0.0.8
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
@@ -13,14 +13,11 @@ from nsj_rest_lib2.compiler.edl_model.entity_model import EntityModel
13
13
 
14
14
  from nsj_rest_lib2.settings import get_logger
15
15
 
16
- # TODO Rever a questão do tempo de expiração ser renovado, na leitura do redis
17
16
  # TODO Atualizar o status da entidade pelo worker de compilação (e talvez parar uma compilação, quando se delete uma entidade)
18
17
  # TODO Relacionamentos
19
18
  # TODO Classes Abstratas
20
19
  # TODO Partial Classes
21
20
  # TODO Migrations
22
- # TODO Migrar para a nsj_rest_lib2
23
- # TODO Alterar o padrão de nomenclatura para snake_case
24
21
 
25
22
 
26
23
  class CompilerResult:
@@ -29,7 +26,9 @@ class CompilerResult:
29
26
  self.dto_code: str | None = None
30
27
  self.entity_class_name: str | None = None
31
28
  self.entity_code: str | None = None
32
- # TODO Informacoes das rotas
29
+ self.api_expose: bool | None = None
30
+ self.api_resource: str | None = None
31
+ self.api_verbs: list[str] | None = None
33
32
 
34
33
 
35
34
  class EDLCompiler:
@@ -121,13 +120,18 @@ class EDLCompiler:
121
120
  entity_model, ast_entity_attributes, props_pk
122
121
  )
123
122
 
124
- # Retornando o resultado
123
+ # Construindo o resultado
125
124
  compiler_result = CompilerResult()
126
125
  compiler_result.entity_class_name = entity_class_name
127
126
  compiler_result.entity_code = code_entity
128
127
  compiler_result.dto_class_name = dto_class_name
129
128
  compiler_result.dto_code = code_dto
130
129
 
130
+ # Compilando questões das APIs
131
+ compiler_result.api_expose = entity_model.api.expose
132
+ compiler_result.api_resource = entity_model.api.resource
133
+ compiler_result.api_verbs = entity_model.api.verbs
134
+
131
135
  return compiler_result
132
136
 
133
137
  def _make_properties_structures(
@@ -286,3 +290,10 @@ if __name__ == "__main__":
286
290
  print(f"DTO: {compiler_result.dto_class_name}")
287
291
  print(f"{compiler_result.dto_code}")
288
292
  print("\n")
293
+
294
+ print("==========================================================")
295
+ print("API Expose: ", compiler_result.api_expose)
296
+ print("API Route Path: ", compiler_result.api_resource)
297
+ print("API Verbs: ", compiler_result.api_verbs)
298
+ print("==========================================================")
299
+ print("\n")
@@ -60,7 +60,7 @@ class EntityModel(BaseModel):
60
60
  repository: RepositoryModel = Field(
61
61
  ..., description="Configurações de mapeamento para o banco de dados."
62
62
  )
63
- api: Optional[APIModel] = Field(
64
- None,
63
+ api: APIModel = Field(
64
+ ...,
65
65
  description="Definição da API REST associada ao modelo, com todos os seus endpoints.",
66
66
  )
@@ -243,6 +243,26 @@ class EDLPropertyCompiler:
243
243
  enum_class_name, ast_enum_class = result
244
244
  enum_classes.append(ast_enum_class)
245
245
 
246
+ # Resolvendo o nome da propriedade no Entity
247
+ if (
248
+ properties_structure.entity_properties
249
+ and pkey in properties_structure.entity_properties
250
+ ):
251
+ entity_field_name = properties_structure.entity_properties[
252
+ pkey
253
+ ].column
254
+ else:
255
+ entity_field_name = pkey
256
+
257
+ # Escrevendo, se necessário, o alias para o nome da entity
258
+ if entity_field_name != pkey:
259
+ keywords.append(
260
+ ast.keyword(
261
+ arg="entity_field",
262
+ value=ast.Constant(value=entity_field_name),
263
+ )
264
+ )
265
+
246
266
  # Instanciando o atributo AST
247
267
  if enum_class_name:
248
268
  prop_type = enum_class_name
@@ -268,16 +288,6 @@ class EDLPropertyCompiler:
268
288
  ast_dto_attributes.append(ast_attr)
269
289
 
270
290
  # Entity
271
- if (
272
- properties_structure.entity_properties
273
- and pkey in properties_structure.entity_properties
274
- ):
275
- entity_field_name = properties_structure.entity_properties[
276
- pkey
277
- ].column
278
- else:
279
- entity_field_name = pkey
280
-
281
291
  ast_entity_attr = ast.AnnAssign(
282
292
  target=ast.Name(
283
293
  id=CompilerStrUtil.to_snake_case(entity_field_name),
@@ -55,17 +55,17 @@ def setup_dynamic_routes(
55
55
  injector_factory: Any = None,
56
56
  ) -> None:
57
57
 
58
- COLLECTION_DYNAMIC_ROUTE = f"/{APP_NAME}/{dynamic_root_path}/<entity_id>"
59
- ONE_DYNAMIC_ROUTE = f"/{APP_NAME}/{dynamic_root_path}/<entity_id>/<id>"
58
+ COLLECTION_DYNAMIC_ROUTE = f"/{APP_NAME}/{dynamic_root_path}/<entity_resource>"
59
+ ONE_DYNAMIC_ROUTE = f"/{APP_NAME}/{dynamic_root_path}/<entity_resource>/<id>"
60
60
 
61
61
  def list_dynamic_wrapper(injector_factory: Any, *args: Any, **kwargs: Any) -> Any:
62
62
 
63
63
  def list_dynamic(*args: Any, **kwargs: Any):
64
64
  # Recuperando o identificador da entidade
65
- if "entity_id" not in kwargs:
65
+ if "entity_resource" not in kwargs:
66
66
  msg = "Faltando parâmetro identificador da entidade na URL."
67
67
  return (format_json_error(msg), 400, {**DEFAULT_RESP_HEADERS})
68
- entity_id = kwargs.pop("entity_id")
68
+ entity_resource = kwargs.pop("entity_resource")
69
69
 
70
70
  # Lendo tenant e grupo_empresarial
71
71
  tenant, grupo_empresarial = _get_tenant_grupo()
@@ -73,12 +73,20 @@ def setup_dynamic_routes(
73
73
  try:
74
74
  # Recuperando o código do DTO e Entity correspondente
75
75
  entity_loader = EntityLoader()
76
- dto_class_name, entity_class_name, etities_dict = (
77
- entity_loader.load_entity_source(
78
- entity_id, tenant, grupo_empresarial
79
- )
76
+ (
77
+ dto_class_name,
78
+ entity_class_name,
79
+ etities_dict,
80
+ api_expose,
81
+ api_verbs,
82
+ ) = entity_loader.load_entity_source(
83
+ entity_resource, tenant, grupo_empresarial
80
84
  )
81
85
 
86
+ # Verificando se essa API deve ser exposta
87
+ if not api_expose or "GET" not in api_verbs:
88
+ return ("", 405, {})
89
+
82
90
  # Executando o list pelo RestLib
83
91
  route = ListRoute(
84
92
  url=COLLECTION_DYNAMIC_ROUTE,
@@ -90,7 +98,7 @@ def setup_dynamic_routes(
90
98
 
91
99
  return route.handle_request(*args, **kwargs)
92
100
  except MissingEntityConfigException:
93
- msg = f"Entity configuration for {entity_id} not found."
101
+ msg = f"Entity configuration for {entity_resource} not found."
94
102
  return (format_json_error(msg), 412, {**DEFAULT_RESP_HEADERS})
95
103
 
96
104
  return list_dynamic
@@ -99,10 +107,10 @@ def setup_dynamic_routes(
99
107
 
100
108
  def get_dynamic(*args: Any, **kwargs: Any):
101
109
  # Recuperando o identificador da entidade
102
- if "entity_id" not in kwargs:
110
+ if "entity_resource" not in kwargs:
103
111
  msg = "Faltando parâmetro identificador da entidade na URL."
104
112
  return (format_json_error(msg), 400, {**DEFAULT_RESP_HEADERS})
105
- entity_id = kwargs.pop("entity_id")
113
+ entity_resource = kwargs.pop("entity_resource")
106
114
 
107
115
  # Lendo tenant e grupo_empresarial
108
116
  tenant, grupo_empresarial = _get_tenant_grupo()
@@ -110,12 +118,20 @@ def setup_dynamic_routes(
110
118
  try:
111
119
  # Recuperando o código do DTO e Entity correspondente
112
120
  entity_loader = EntityLoader()
113
- dto_class_name, entity_class_name, etities_dict = (
114
- entity_loader.load_entity_source(
115
- entity_id, tenant, grupo_empresarial
116
- )
121
+ (
122
+ dto_class_name,
123
+ entity_class_name,
124
+ etities_dict,
125
+ api_expose,
126
+ api_verbs,
127
+ ) = entity_loader.load_entity_source(
128
+ entity_resource, tenant, grupo_empresarial
117
129
  )
118
130
 
131
+ # Verificando se essa API deve ser exposta
132
+ if not api_expose or "GET" not in api_verbs:
133
+ return ("", 405, {})
134
+
119
135
  # Executando o list pelo RestLib
120
136
  route = GetRoute(
121
137
  url=ONE_DYNAMIC_ROUTE,
@@ -127,7 +143,7 @@ def setup_dynamic_routes(
127
143
 
128
144
  return route.handle_request(*args, **kwargs)
129
145
  except MissingEntityConfigException:
130
- msg = f"Entity configuration for {entity_id} not found."
146
+ msg = f"Entity configuration for {entity_resource} not found."
131
147
  return (format_json_error(msg), 412, {**DEFAULT_RESP_HEADERS})
132
148
 
133
149
  return get_dynamic
@@ -135,10 +151,10 @@ def setup_dynamic_routes(
135
151
  def post_dynamic_wrapper(injector_factory: Any, *args: Any, **kwargs: Any) -> Any:
136
152
  def post_dynamic(*args: Any, **kwargs: Any):
137
153
  # Recuperando o identificador da entidade
138
- if "entity_id" not in kwargs:
154
+ if "entity_resource" not in kwargs:
139
155
  msg = "Faltando parâmetro identificador da entidade na URL."
140
156
  return (format_json_error(msg), 400, {**DEFAULT_RESP_HEADERS})
141
- entity_id = kwargs.pop("entity_id")
157
+ entity_resource = kwargs.pop("entity_resource")
142
158
 
143
159
  # Lendo tenant e grupo_empresarial
144
160
  tenant, grupo_empresarial = _get_tenant_grupo()
@@ -146,12 +162,20 @@ def setup_dynamic_routes(
146
162
  try:
147
163
  # Recuperando o código do DTO e Entity correspondente
148
164
  entity_loader = EntityLoader()
149
- dto_class_name, entity_class_name, etities_dict = (
150
- entity_loader.load_entity_source(
151
- entity_id, tenant, grupo_empresarial
152
- )
165
+ (
166
+ dto_class_name,
167
+ entity_class_name,
168
+ etities_dict,
169
+ api_expose,
170
+ api_verbs,
171
+ ) = entity_loader.load_entity_source(
172
+ entity_resource, tenant, grupo_empresarial
153
173
  )
154
174
 
175
+ # Verificando se essa API deve ser exposta
176
+ if not api_expose or "POST" not in api_verbs:
177
+ return ("", 405, {})
178
+
155
179
  # Executando o list pelo RestLib
156
180
  route = PostRoute(
157
181
  url=COLLECTION_DYNAMIC_ROUTE,
@@ -163,7 +187,7 @@ def setup_dynamic_routes(
163
187
 
164
188
  return route.handle_request(*args, **kwargs)
165
189
  except MissingEntityConfigException:
166
- msg = f"Entity configuration for {entity_id} not found."
190
+ msg = f"Entity configuration for {entity_resource} not found."
167
191
  return (format_json_error(msg), 412, {**DEFAULT_RESP_HEADERS})
168
192
 
169
193
  return post_dynamic
@@ -171,10 +195,10 @@ def setup_dynamic_routes(
171
195
  def put_dynamic_wrapper(injector_factory: Any, *args: Any, **kwargs: Any) -> Any:
172
196
  def put_dynamic(*args: Any, **kwargs: Any):
173
197
  # Recuperando o identificador da entidade
174
- if "entity_id" not in kwargs:
198
+ if "entity_resource" not in kwargs:
175
199
  msg = "Faltando parâmetro identificador da entidade na URL."
176
200
  return (format_json_error(msg), 400, {**DEFAULT_RESP_HEADERS})
177
- entity_id = kwargs.pop("entity_id")
201
+ entity_resource = kwargs.pop("entity_resource")
178
202
 
179
203
  # Lendo tenant e grupo_empresarial
180
204
  tenant, grupo_empresarial = _get_tenant_grupo()
@@ -182,12 +206,20 @@ def setup_dynamic_routes(
182
206
  try:
183
207
  # Recuperando o código do DTO e Entity correspondente
184
208
  entity_loader = EntityLoader()
185
- dto_class_name, entity_class_name, etities_dict = (
186
- entity_loader.load_entity_source(
187
- entity_id, tenant, grupo_empresarial
188
- )
209
+ (
210
+ dto_class_name,
211
+ entity_class_name,
212
+ etities_dict,
213
+ api_expose,
214
+ api_verbs,
215
+ ) = entity_loader.load_entity_source(
216
+ entity_resource, tenant, grupo_empresarial
189
217
  )
190
218
 
219
+ # Verificando se essa API deve ser exposta
220
+ if not api_expose or "PUT" not in api_verbs:
221
+ return ("", 405, {})
222
+
191
223
  # Executando o list pelo RestLib
192
224
  route = PutRoute(
193
225
  url=ONE_DYNAMIC_ROUTE,
@@ -199,7 +231,7 @@ def setup_dynamic_routes(
199
231
 
200
232
  return route.handle_request(*args, **kwargs)
201
233
  except MissingEntityConfigException:
202
- msg = f"Entity configuration for {entity_id} not found."
234
+ msg = f"Entity configuration for {entity_resource} not found."
203
235
  return (format_json_error(msg), 412, {**DEFAULT_RESP_HEADERS})
204
236
 
205
237
  return put_dynamic
@@ -207,10 +239,10 @@ def setup_dynamic_routes(
207
239
  def patch_dynamic_wrapper(injector_factory: Any, *args: Any, **kwargs: Any) -> Any:
208
240
  def patch_dynamic(*args: Any, **kwargs: Any):
209
241
  # Recuperando o identificador da entidade
210
- if "entity_id" not in kwargs:
242
+ if "entity_resource" not in kwargs:
211
243
  msg = "Faltando parâmetro identificador da entidade na URL."
212
244
  return (format_json_error(msg), 400, {**DEFAULT_RESP_HEADERS})
213
- entity_id = kwargs.pop("entity_id")
245
+ entity_resource = kwargs.pop("entity_resource")
214
246
 
215
247
  # Lendo tenant e grupo_empresarial
216
248
  tenant, grupo_empresarial = _get_tenant_grupo()
@@ -218,12 +250,20 @@ def setup_dynamic_routes(
218
250
  try:
219
251
  # Recuperando o código do DTO e Entity correspondente
220
252
  entity_loader = EntityLoader()
221
- dto_class_name, entity_class_name, etities_dict = (
222
- entity_loader.load_entity_source(
223
- entity_id, tenant, grupo_empresarial
224
- )
253
+ (
254
+ dto_class_name,
255
+ entity_class_name,
256
+ etities_dict,
257
+ api_expose,
258
+ api_verbs,
259
+ ) = entity_loader.load_entity_source(
260
+ entity_resource, tenant, grupo_empresarial
225
261
  )
226
262
 
263
+ # Verificando se essa API deve ser exposta
264
+ if not api_expose or "PATCH" not in api_verbs:
265
+ return ("", 405, {})
266
+
227
267
  # Executando o list pelo RestLib
228
268
  route = PatchRoute(
229
269
  url=ONE_DYNAMIC_ROUTE,
@@ -235,7 +275,7 @@ def setup_dynamic_routes(
235
275
 
236
276
  return route.handle_request(*args, **kwargs)
237
277
  except MissingEntityConfigException:
238
- msg = f"Entity configuration for {entity_id} not found."
278
+ msg = f"Entity configuration for {entity_resource} not found."
239
279
  return (format_json_error(msg), 412, {**DEFAULT_RESP_HEADERS})
240
280
 
241
281
  return patch_dynamic
@@ -243,10 +283,10 @@ def setup_dynamic_routes(
243
283
  def delete_dynamic_wrapper(injector_factory: Any, *args: Any, **kwargs: Any) -> Any:
244
284
  def delete_dynamic(*args: Any, **kwargs: Any):
245
285
  # Recuperando o identificador da entidade
246
- if "entity_id" not in kwargs:
286
+ if "entity_resource" not in kwargs:
247
287
  msg = "Faltando parâmetro identificador da entidade na URL."
248
288
  return (format_json_error(msg), 400, {**DEFAULT_RESP_HEADERS})
249
- entity_id = kwargs.pop("entity_id")
289
+ entity_resource = kwargs.pop("entity_resource")
250
290
 
251
291
  # Lendo tenant e grupo_empresarial
252
292
  tenant, grupo_empresarial = _get_tenant_grupo()
@@ -254,12 +294,20 @@ def setup_dynamic_routes(
254
294
  try:
255
295
  # Recuperando o código do DTO e Entity correspondente
256
296
  entity_loader = EntityLoader()
257
- dto_class_name, entity_class_name, etities_dict = (
258
- entity_loader.load_entity_source(
259
- entity_id, tenant, grupo_empresarial
260
- )
297
+ (
298
+ dto_class_name,
299
+ entity_class_name,
300
+ etities_dict,
301
+ api_expose,
302
+ api_verbs,
303
+ ) = entity_loader.load_entity_source(
304
+ entity_resource, tenant, grupo_empresarial
261
305
  )
262
306
 
307
+ # Verificando se essa API deve ser exposta
308
+ if not api_expose or "DELETE" not in api_verbs:
309
+ return ("", 405, {})
310
+
263
311
  # Executando o list pelo RestLib
264
312
  route = DeleteRoute(
265
313
  url=ONE_DYNAMIC_ROUTE,
@@ -271,7 +319,7 @@ def setup_dynamic_routes(
271
319
 
272
320
  return route.handle_request(*args, **kwargs)
273
321
  except MissingEntityConfigException:
274
- msg = f"Entity configuration for {entity_id} not found."
322
+ msg = f"Entity configuration for {entity_resource} not found."
275
323
  return (format_json_error(msg), 412, {**DEFAULT_RESP_HEADERS})
276
324
 
277
325
  return delete_dynamic
@@ -18,6 +18,8 @@ class LoadedEntity:
18
18
  self.entity_class_name: str = ""
19
19
  self.entity_hash: str = ""
20
20
  self.loaded_at: datetime.datetime = datetime.datetime.now()
21
+ self.api_expose: bool = False
22
+ self.api_verbs: list[str] = []
21
23
 
22
24
 
23
25
  class Namespace:
@@ -37,17 +39,17 @@ class EntityLoader:
37
39
 
38
40
  def load_entity_source(
39
41
  self,
40
- entity_id: str,
42
+ entity_resource: str,
41
43
  tenant: str | None,
42
44
  grupo_empresarial: str | None,
43
- ) -> tuple[str, str, dict]:
45
+ ) -> tuple[str, str, dict, bool, list[str]]:
44
46
  # Montando as chaves dos namespaces
45
47
  grupo_key = f"tenant_{tenant}.ge_{grupo_empresarial}"
46
48
  tenant_key = f"tenant_{tenant}"
47
49
  default_key = "default"
48
50
 
49
51
  result = self._load_entity_source_from_memory(
50
- entity_id, grupo_key, tenant_key, default_key
52
+ entity_resource, grupo_key, tenant_key, default_key
51
53
  )
52
54
 
53
55
  # Se conseguiu carregar da memória, verifica se houve alteração no hash, em relação ao redis
@@ -58,24 +60,39 @@ class EntityLoader:
58
60
  namespace,
59
61
  ) = result
60
62
 
61
- loaded_entity = namespace.loaded_entities[entity_id]
63
+ loaded_entity = namespace.loaded_entities[entity_resource]
62
64
  dto_class_name = loaded_entity.dto_class_name
63
65
  entity_class_name = loaded_entity.entity_class_name
64
66
  entities_dict = namespace.entities_dict
67
+ api_expose = loaded_entity.api_expose
68
+ api_verbs = loaded_entity.api_verbs
65
69
 
66
70
  # Se o tempo entre o carregamento e agora for maior do que MIN_TIME_SOURCE_REFRESH minutos,
67
71
  # verifica se precisa de refresh
68
72
  time_diff = datetime.datetime.now() - loaded_entity.loaded_at
69
73
 
70
74
  if time_diff.total_seconds() >= MIN_TIME_SOURCE_REFRESH * 60:
75
+ # Renovando o tempo de refresh
76
+ loaded_entity.loaded_at = datetime.datetime.now()
77
+
71
78
  # Recuperando do Redis direto pela key (faz uma só chamada ao redis)
72
79
  loaded_config = self._load_entity_config_from_redis(
73
- entity_id, grupo_key, tenant_key, default_key, entity_config_key
80
+ entity_resource,
81
+ grupo_key,
82
+ tenant_key,
83
+ default_key,
84
+ entity_config_key,
74
85
  )
75
86
 
76
87
  # Se não achar no redis, usa o que estava em memória
77
88
  if not loaded_config:
78
- return (dto_class_name, entity_class_name, entities_dict)
89
+ return (
90
+ dto_class_name,
91
+ entity_class_name,
92
+ entities_dict,
93
+ api_expose,
94
+ api_verbs,
95
+ )
79
96
 
80
97
  # Desempacotando resultado
81
98
  entity_config_key, entity_config_str = loaded_config
@@ -84,23 +101,47 @@ class EntityLoader:
84
101
  result_execute = self._execute_entity_source(
85
102
  entity_config_str,
86
103
  entity_config_key,
87
- entity_id,
104
+ entity_resource,
88
105
  check_refresh=True,
89
106
  )
90
107
 
91
108
  # Se não carregou novo código, usa o que estava em memória
92
109
  if result_execute is None:
93
- return (dto_class_name, entity_class_name, entities_dict)
110
+ return (
111
+ dto_class_name,
112
+ entity_class_name,
113
+ entities_dict,
114
+ api_expose,
115
+ api_verbs,
116
+ )
94
117
  else:
95
- dto_class_name, entity_class_name, namespace = result_execute
96
- return (dto_class_name, entity_class_name, namespace.entities_dict)
118
+ (
119
+ dto_class_name,
120
+ entity_class_name,
121
+ namespace,
122
+ api_expose,
123
+ api_verbs,
124
+ ) = result_execute
125
+ return (
126
+ dto_class_name,
127
+ entity_class_name,
128
+ namespace.entities_dict,
129
+ api_expose,
130
+ api_verbs,
131
+ )
97
132
  else:
98
133
  # Se não deu o intervalo de verificação do refresh, retorna o que está em memória
99
- return (dto_class_name, entity_class_name, entities_dict)
134
+ return (
135
+ dto_class_name,
136
+ entity_class_name,
137
+ entities_dict,
138
+ api_expose,
139
+ api_verbs,
140
+ )
100
141
 
101
142
  # Se não conseguir recuperar a entidade, procura no redis:
102
143
  loaded_config = self._load_entity_config_from_redis(
103
- entity_id, grupo_key, tenant_key, default_key, None
144
+ entity_resource, grupo_key, tenant_key, default_key, None
104
145
  )
105
146
 
106
147
  # Se também não achar no redis, lanca exceção
@@ -112,14 +153,24 @@ class EntityLoader:
112
153
 
113
154
  # Executando o código da entidade
114
155
  result_execute = self._execute_entity_source(
115
- entity_config_str, entity_config_key, entity_id
156
+ entity_config_str, entity_config_key, entity_resource
116
157
  )
117
158
 
118
159
  if result_execute is None:
119
- raise RuntimeError(f"Erro desconhecido carregando entidade: {entity_id}")
120
- dto_class_name, entity_class_name, namespace = result_execute
160
+ raise RuntimeError(
161
+ f"Erro desconhecido carregando entidade: {entity_resource}"
162
+ )
163
+ dto_class_name, entity_class_name, namespace, api_expose, api_verbs = (
164
+ result_execute
165
+ )
121
166
 
122
- return (dto_class_name, entity_class_name, namespace.entities_dict)
167
+ return (
168
+ dto_class_name,
169
+ entity_class_name,
170
+ namespace.entities_dict,
171
+ api_expose,
172
+ api_verbs,
173
+ )
123
174
 
124
175
  def clear_namespaces(self):
125
176
  """
@@ -135,9 +186,9 @@ class EntityLoader:
135
186
  self,
136
187
  entity_config_str: str,
137
188
  entity_config_key: str,
138
- entity_id: str,
189
+ entity_resource: str,
139
190
  check_refresh: bool = False,
140
- ) -> tuple[str, str, Namespace] | None:
191
+ ) -> tuple[str, str, Namespace, bool, list[str]] | None:
141
192
  # Interpretando o json de configuração da entidade
142
193
  try:
143
194
  entity_config = json.loads(entity_config_str)
@@ -147,14 +198,18 @@ class EntityLoader:
147
198
  source_dto = entity_config["source_dto"]
148
199
  source_entity = entity_config["source_entity"]
149
200
  entity_hash = entity_config["entity_hash"]
201
+
202
+ api_expose = entity_config["api_expose"]
203
+ # api_resource = entity_config["api_resource"]
204
+ api_verbs = entity_config["api_verbs"]
150
205
  except json.JSONDecodeError as e:
151
206
  if not check_refresh:
152
207
  raise RuntimeError(
153
- f"Erro ao decodificar JSON da entidade {entity_id}; na chave {entity_config_key}: {e}"
208
+ f"Erro ao decodificar JSON da entidade {entity_resource}; na chave {entity_config_key}: {e}"
154
209
  )
155
210
  else:
156
211
  get_logger().error(
157
- f"Erro ao decodificar JSON da entidade {entity_id}; na chave {entity_config_key}: {e}"
212
+ f"Erro ao decodificar JSON da entidade {entity_resource}; na chave {entity_config_key}: {e}"
158
213
  )
159
214
  return None
160
215
 
@@ -164,7 +219,7 @@ class EntityLoader:
164
219
  if not loaded_namespace:
165
220
  return None
166
221
 
167
- loaded_entity = loaded_namespace.loaded_entities.get(entity_id)
222
+ loaded_entity = loaded_namespace.loaded_entities.get(entity_resource)
168
223
  if not loaded_entity:
169
224
  return None
170
225
 
@@ -173,7 +228,7 @@ class EntityLoader:
173
228
 
174
229
  # Imprimindo alerta de load no log
175
230
  get_logger().debug(
176
- f"Carregando entidade {entity_id} no namespace {entity_config_key}."
231
+ f"Carregando entidade {entity_resource} no namespace {entity_config_key}."
177
232
  )
178
233
 
179
234
  # Carregando a entidade no namespace
@@ -200,10 +255,12 @@ class EntityLoader:
200
255
  loaded_entity.dto_class_name = dto_class_name
201
256
  loaded_entity.entity_class_name = entity_class_name
202
257
  loaded_entity.entity_hash = entity_hash
258
+ loaded_entity.api_expose = api_expose
259
+ loaded_entity.api_verbs = api_verbs
203
260
 
204
- namespace.loaded_entities[entity_id] = loaded_entity
261
+ namespace.loaded_entities[entity_resource] = loaded_entity
205
262
 
206
- return (dto_class_name, entity_class_name, namespace)
263
+ return (dto_class_name, entity_class_name, namespace, api_expose, api_verbs)
207
264
 
208
265
  def _safe_exec(self, source_code, context, description):
209
266
  try:
@@ -214,35 +271,35 @@ class EntityLoader:
214
271
 
215
272
  def _load_entity_config_from_redis(
216
273
  self,
217
- entity_id: str,
274
+ entity_resource: str,
218
275
  grupo_key: str,
219
276
  tenant_key: str,
220
277
  default_key: str,
221
278
  entity_config_key: str | None,
222
279
  ) -> tuple[str, str] | None:
223
280
  get_logger().debug(
224
- f"Procurando a configuração da entidade {entity_id} no redis"
281
+ f"Procurando a configuração da entidade {entity_resource} no redis"
225
282
  )
226
283
 
227
284
  if entity_config_key is not None:
228
285
  entity_config_str = get_redis(
229
- "entity_config", ESCOPO_RESTLIB2, entity_config_key, entity_id
286
+ "entity_config", ESCOPO_RESTLIB2, entity_config_key, entity_resource
230
287
  )
231
288
 
232
289
  else:
233
290
  entity_config_key = grupo_key
234
291
  entity_config_str = get_redis(
235
- "entity_config", ESCOPO_RESTLIB2, grupo_key, entity_id
292
+ "entity_config", ESCOPO_RESTLIB2, grupo_key, entity_resource
236
293
  )
237
294
  if entity_config_str is None:
238
295
  entity_config_key = tenant_key
239
296
  entity_config_str = get_redis(
240
- "entity_config", ESCOPO_RESTLIB2, tenant_key, entity_id
297
+ "entity_config", ESCOPO_RESTLIB2, tenant_key, entity_resource
241
298
  )
242
299
  if entity_config_str is None:
243
300
  entity_config_key = default_key
244
301
  entity_config_str = get_redis(
245
- "entity_config", ESCOPO_RESTLIB2, default_key, entity_id
302
+ "entity_config", ESCOPO_RESTLIB2, default_key, entity_resource
246
303
  )
247
304
 
248
305
  # Se não encontrar no redis, retorna None
@@ -253,7 +310,7 @@ class EntityLoader:
253
310
 
254
311
  def _load_entity_source_from_memory(
255
312
  self,
256
- entity_id: str,
313
+ entity_resource: str,
257
314
  grupo_key: str,
258
315
  tenant_key: str,
259
316
  default_key: str,
@@ -263,19 +320,19 @@ class EntityLoader:
263
320
 
264
321
  # Pesquisando a entidade no namespace mais específico (grupo_empresarial)
265
322
  grupo_namespace = namespaces_dict.get(grupo_key)
266
- if grupo_namespace and entity_id in grupo_namespace.loaded_entities:
323
+ if grupo_namespace and entity_resource in grupo_namespace.loaded_entities:
267
324
  entity_config_key = grupo_key
268
325
  namespace = grupo_namespace
269
326
 
270
327
  # Pesquisando a entidade no namespace intermediário (tenant)
271
328
  tenant_namespace = namespaces_dict.get(tenant_key)
272
- if tenant_namespace and entity_id in tenant_namespace.loaded_entities:
329
+ if tenant_namespace and entity_resource in tenant_namespace.loaded_entities:
273
330
  entity_config_key = tenant_key
274
331
  namespace = tenant_namespace
275
332
 
276
333
  # Pesquisando a entidade no namespace padrão (default)
277
334
  default_namespace = namespaces_dict.get(default_key)
278
- if default_namespace and entity_id in default_namespace.loaded_entities:
335
+ if default_namespace and entity_resource in default_namespace.loaded_entities:
279
336
  entity_config_key = default_key
280
337
  namespace = default_namespace
281
338
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nsj_rest_lib2
3
- Version: 0.0.7
3
+ Version: 0.0.8
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
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = nsj_rest_lib2
3
- version = 0.0.7
3
+ version = 0.0.8
4
4
  author = Nasajon Sistemas
5
5
  author_email = contact.dev@nasajon.com.br
6
6
  description = Biblioteca para permitir a distribuição de rotas dinâmicas numa API, configuradas por meio de EDLs declarativos (em formato JSON).
File without changes