nsj-rest-lib2 0.0.7__py3-none-any.whl → 0.0.9__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.
@@ -1,13 +1,24 @@
1
1
  import ast
2
+ import re
2
3
 
3
4
  from nsj_rest_lib2.compiler.compiler_structures import (
4
5
  IndexCompilerStructure,
5
6
  PropertiesCompilerStructure,
6
7
  )
7
8
  from nsj_rest_lib2.compiler.edl_model.entity_model import EntityModel
8
- from nsj_rest_lib2.compiler.edl_model.primitives import PrimitiveTypes
9
+ from nsj_rest_lib2.compiler.edl_model.primitives import (
10
+ CardinalityTypes,
11
+ PrimitiveTypes,
12
+ REGEX_EXTERNAL_REF,
13
+ REGEX_INTERNAL_REF,
14
+ )
9
15
  from nsj_rest_lib2.compiler.edl_model.property_meta_model import PropertyMetaModel
10
16
  from nsj_rest_lib2.compiler.util.str_util import CompilerStrUtil
17
+ from nsj_rest_lib2.compiler.util.type_naming_util import (
18
+ compile_dto_class_name,
19
+ compile_entity_class_name,
20
+ compile_namespace_keys,
21
+ )
11
22
  from nsj_rest_lib2.compiler.util.type_util import TypeUtil
12
23
 
13
24
  # TODO pattern
@@ -22,278 +33,430 @@ class EDLPropertyCompiler:
22
33
  properties_structure: PropertiesCompilerStructure,
23
34
  map_unique_by_property: dict[str, IndexCompilerStructure],
24
35
  entity_model: EntityModel,
25
- ) -> tuple[list[ast.stmt], list[ast.stmt], list[str], list[ast.stmt]]:
36
+ entity_models: dict[str, EntityModel],
37
+ ) -> tuple[
38
+ list[ast.stmt],
39
+ list[ast.stmt],
40
+ list[str],
41
+ list[ast.stmt],
42
+ list[tuple[str, str, str]],
43
+ ]:
26
44
 
27
45
  # TODO Criar opção de campo calculado?
28
46
 
47
+ # Descobrindo os atributos marcados como PK (e recuperando a chave primária)
48
+ # pk_keys = []
49
+ # for pkey in properties_structure.properties:
50
+ # prop = properties_structure.properties[pkey]
51
+
52
+ # if isinstance(prop.type, PrimitiveTypes):
53
+ # if prop.pk:
54
+ # pk_keys.append(pkey)
55
+
56
+ # if len(pk_keys) > 1:
57
+ # raise Exception(
58
+ # f"Entidade '{entity_model.id}' possui mais de uma chave primária (ainda não suportado): {pk_keys}"
59
+ # )
60
+ # elif len(pk_keys) == 0:
61
+ # raise Exception(
62
+ # f"Entidade '{entity_model.id}' não tem nenhuma chave primária (ainda não suportado)"
63
+ # )
64
+
65
+ # pk_key = pk_keys[0]
66
+
67
+ # Instanciando as listas de retorno
29
68
  ast_dto_attributes = []
30
69
  ast_entity_attributes = []
31
70
  props_pk = []
32
71
  enum_classes = []
72
+ related_imports = []
33
73
 
34
74
  if properties_structure.properties is None:
35
75
  return (ast_dto_attributes, ast_entity_attributes, props_pk, enum_classes)
36
76
 
37
77
  for pkey in properties_structure.properties:
38
78
  prop = properties_structure.properties[pkey]
39
- enum_class_name = None
40
79
 
41
80
  # DTO
42
81
  ## Tratando propriedade simples (não array, não object)
43
- if prop.type not in [PrimitiveTypes.ARRAY, PrimitiveTypes.OBJECT]:
44
- keywords = []
82
+ if isinstance(prop.type, PrimitiveTypes):
83
+ self.compile_simple_property(
84
+ properties_structure,
85
+ map_unique_by_property,
86
+ entity_model,
87
+ ast_dto_attributes,
88
+ ast_entity_attributes,
89
+ props_pk,
90
+ enum_classes,
91
+ pkey,
92
+ prop,
93
+ )
45
94
 
46
- if prop.pk:
47
- keywords.append(ast.keyword(arg="pk", value=ast.Constant(True)))
48
- props_pk.append(pkey)
95
+ elif isinstance(prop.type, str):
96
+ external_match = re.match(REGEX_EXTERNAL_REF, prop.type)
49
97
 
50
- if prop.key_alternative:
51
- keywords.append(
52
- ast.keyword(arg="candidate_key", value=ast.Constant(True))
53
- )
98
+ if external_match:
99
+ # Resolvendo o id da entidade
100
+ related_entity_id = external_match.group(2)
54
101
 
55
- if (
56
- properties_structure.main_properties
57
- and pkey in properties_structure.main_properties
58
- ):
59
- keywords.append(ast.keyword(arg="resume", value=ast.Constant(True)))
60
-
61
- if (
62
- properties_structure.required
63
- and pkey in properties_structure.required
64
- ):
65
- keywords.append(
66
- ast.keyword(arg="not_null", value=ast.Constant(True))
102
+ # Resolvendo o nome das classes de DTO e Entity
103
+ related_dto_class_name = compile_dto_class_name(related_entity_id)
104
+ related_entity_class_name = compile_entity_class_name(
105
+ related_entity_id
67
106
  )
68
107
 
69
- if (
70
- properties_structure.partition_data
71
- and pkey in properties_structure.partition_data
72
- ):
73
- keywords.append(
74
- ast.keyword(arg="partition_data", value=ast.Constant(True))
75
- )
108
+ # Resolvendo o caminho do import
109
+ related_entity_key = external_match.group(0)
76
110
 
77
- if pkey in map_unique_by_property:
78
- unique = map_unique_by_property[pkey].index_model
79
- keywords.append(
80
- ast.keyword(
81
- arg="unique",
82
- value=ast.Constant(unique.name),
83
- )
84
- )
85
-
86
- if (
87
- prop.default
88
- ): # TODO Verificar esse modo de tratar valores default (principalmente expressões)
89
- keywords.append(
90
- ast.keyword(
91
- arg="default_value",
92
- value=ast.Name(str(prop.default), ctx=ast.Load()),
111
+ related_entity = entity_models.get(related_entity_key)
112
+ if not related_entity:
113
+ raise Exception(
114
+ f"Entidade '{entity_model.id}' possui uma referência externa para uma entidade inexistente: '{related_entity_key}', por meio da propriedade: '{pkey}'."
93
115
  )
94
- )
95
-
96
- if prop.trim:
97
- keywords.append(ast.keyword(arg="strip", value=ast.Constant(True)))
98
-
99
- max = None
100
- min = None
101
- if prop.type in [PrimitiveTypes.STRING, PrimitiveTypes.EMAIL]:
102
- if prop.max_length:
103
- max = prop.max_length
104
- elif prop.min_length:
105
- min = prop.min_length
106
- elif prop.type in [PrimitiveTypes.INTEGER, PrimitiveTypes.NUMBER]:
107
- if prop.minimum:
108
- min = prop.minimum
109
- elif prop.maximum:
110
- max = prop.maximum
111
-
112
- if max:
113
- keywords.append(
114
- ast.keyword(arg="max", value=ast.Constant(prop.max_length))
115
- )
116
- if min:
117
- keywords.append(
118
- ast.keyword(arg="min", value=ast.Constant(prop.min_length))
119
- )
120
116
 
121
- if (
122
- properties_structure.search_properties
123
- and pkey in properties_structure.search_properties
124
- ):
125
- keywords.append(ast.keyword(arg="search", value=ast.Constant(True)))
126
- else:
127
- keywords.append(
128
- ast.keyword(arg="search", value=ast.Constant(False))
117
+ tenant = related_entity.tenant
118
+ grupo_empresarial = related_entity.grupo_empresarial
119
+ grupo_key, tenant_key, default_key = compile_namespace_keys(
120
+ tenant, grupo_empresarial
129
121
  )
130
122
 
131
- if (
132
- properties_structure.metric_label
133
- and pkey in properties_structure.metric_label
134
- ):
135
- keywords.append(
136
- ast.keyword(arg="metric_label", value=ast.Constant(True))
123
+ if (
124
+ tenant
125
+ and tenant != 0
126
+ and grupo_empresarial
127
+ and grupo_empresarial != "00000000-0000-0000-0000-000000000000"
128
+ ):
129
+ related_import = grupo_key
130
+ elif tenant and tenant != 0:
131
+ related_import = tenant_key
132
+ else:
133
+ related_import = default_key
134
+
135
+ related_imports.append(
136
+ (
137
+ related_import,
138
+ related_dto_class_name,
139
+ related_entity_class_name,
140
+ )
137
141
  )
138
142
 
139
- if prop.type == PrimitiveTypes.CPF and not prop.validator:
140
- keywords.append(
141
- ast.keyword(
142
- arg="validator",
143
- value=ast.Attribute(
144
- value=ast.Call(
145
- func=ast.Name(
146
- id="DTOFieldValidators", ctx=ast.Load()
147
- ),
148
- args=[],
149
- keywords=[],
143
+ # Instanciando o ast
144
+ if prop.cardinality == CardinalityTypes.C1_N:
145
+ # Para relacionamentos 1_N
146
+ keywords = [
147
+ ast.keyword(
148
+ arg="dto_type",
149
+ value=ast.Name(
150
+ id=related_dto_class_name, ctx=ast.Load()
150
151
  ),
151
- attr="validate_cpf",
152
- ctx=ast.Load(),
153
152
  ),
154
- )
155
- )
156
- elif prop.type == PrimitiveTypes.CNPJ and not prop.validator:
157
- keywords.append(
158
- ast.keyword(
159
- arg="validator",
160
- value=ast.Attribute(
161
- value=ast.Call(
162
- func=ast.Name(
163
- id="DTOFieldValidators", ctx=ast.Load()
164
- ),
165
- args=[],
166
- keywords=[],
153
+ ast.keyword(
154
+ arg="entity_type",
155
+ value=ast.Name(
156
+ id=related_entity_class_name, ctx=ast.Load()
167
157
  ),
168
- attr="validate_cnpj",
169
- ctx=ast.Load(),
170
158
  ),
159
+ ]
160
+
161
+ # Resolvendo a coluna usada no relacionamento
162
+ if (
163
+ not properties_structure.entity_properties
164
+ or pkey not in properties_structure.entity_properties
165
+ or not properties_structure.entity_properties[
166
+ pkey
167
+ ].relation_column
168
+ ):
169
+ raise Exception(
170
+ f"Propriedade '{pkey}' possui um relacionamento, mas nenhuma coluna de relacioanamento foi apontada na propriedade correspondente no repository."
171
+ )
172
+
173
+ relation_column = properties_structure.entity_properties[
174
+ pkey
175
+ ].relation_column
176
+
177
+ keywords.append(
178
+ ast.keyword(
179
+ arg="related_entity_field",
180
+ value=ast.Constant(value=relation_column),
181
+ )
171
182
  )
172
- )
173
- elif prop.type == PrimitiveTypes.CPF_CNPJ and not prop.validator:
174
- keywords.append(
175
- ast.keyword(
176
- arg="validator",
177
- value=ast.Attribute(
178
- value=ast.Call(
179
- func=ast.Name(
180
- id="DTOFieldValidators", ctx=ast.Load()
181
- ),
182
- args=[],
183
- keywords=[],
184
- ),
185
- attr="validate_cpf_or_cnpj",
186
- ctx=ast.Load(),
183
+
184
+ ast_attr = ast.AnnAssign(
185
+ target=ast.Name(
186
+ id=CompilerStrUtil.to_snake_case(pkey), ctx=ast.Store()
187
187
  ),
188
- )
189
- )
190
- elif prop.type == PrimitiveTypes.EMAIL and not prop.validator:
191
- keywords.append(
192
- ast.keyword(
193
- arg="validator",
194
- value=ast.Attribute(
195
- value=ast.Call(
196
- func=ast.Name(
197
- id="DTOFieldValidators", ctx=ast.Load()
198
- ),
199
- args=[],
200
- keywords=[],
201
- ),
202
- attr="validate_email",
188
+ annotation=ast.Name(
189
+ id="list",
203
190
  ctx=ast.Load(),
204
191
  ),
205
- )
206
- )
207
- elif prop.validator:
208
- keywords.append(
209
- ast.keyword(
210
- arg="validator",
211
- value=ast.Name(prop.validator, ctx=ast.Load()),
212
- )
213
- )
214
-
215
- if prop.immutable:
216
- keywords.append(
217
- ast.keyword(arg="read_only", value=ast.Constant(True))
218
- )
219
-
220
- if prop.on_save:
221
- keywords.append(
222
- ast.keyword(
223
- arg="convert_to_entity",
224
- value=ast.Name(prop.on_save, ctx=ast.Load()),
225
- )
226
- )
227
-
228
- if prop.on_retrieve:
229
- keywords.append(
230
- ast.keyword(
231
- arg="convert_from_entity",
232
- value=ast.Name(id=prop.on_retrieve, ctx=ast.Load()),
233
- )
234
- )
235
-
236
- if prop.domain_config:
237
- result = self._compile_domain_config(pkey, prop, entity_model)
238
- if not result:
239
- raise Exception(
240
- f"Erro desconhecido ao compilar a propriedade {pkey}"
192
+ value=ast.Call(
193
+ func=ast.Name(id="DTOListField", ctx=ast.Load()),
194
+ args=[],
195
+ keywords=keywords,
196
+ ),
197
+ simple=1,
241
198
  )
242
199
 
243
- enum_class_name, ast_enum_class = result
244
- enum_classes.append(ast_enum_class)
200
+ ast_dto_attributes.append(ast_attr)
201
+ else:
202
+ # TODO
203
+ pass
245
204
 
246
- # Instanciando o atributo AST
247
- if enum_class_name:
248
- prop_type = enum_class_name
205
+ elif re.match(REGEX_INTERNAL_REF, prop.type):
206
+ # TODO
207
+ pass
249
208
  else:
250
- prop_type = TypeUtil.property_type_to_python_type(prop.type)
209
+ raise Exception(f"Tipo de propriedade não suportado: {prop.type}")
210
+
211
+ return (
212
+ ast_dto_attributes,
213
+ ast_entity_attributes,
214
+ props_pk,
215
+ enum_classes,
216
+ related_imports,
217
+ )
251
218
 
252
- ast_attr = ast.AnnAssign(
253
- target=ast.Name(
254
- id=CompilerStrUtil.to_snake_case(pkey), ctx=ast.Store()
219
+ def compile_simple_property(
220
+ self,
221
+ properties_structure,
222
+ map_unique_by_property,
223
+ entity_model,
224
+ ast_dto_attributes,
225
+ ast_entity_attributes,
226
+ props_pk,
227
+ enum_classes,
228
+ pkey,
229
+ prop,
230
+ ):
231
+ enum_class_name = None
232
+ keywords = []
233
+
234
+ if prop.pk:
235
+ keywords.append(ast.keyword(arg="pk", value=ast.Constant(True)))
236
+ props_pk.append(pkey)
237
+
238
+ if prop.key_alternative:
239
+ keywords.append(ast.keyword(arg="candidate_key", value=ast.Constant(True)))
240
+
241
+ if (
242
+ properties_structure.main_properties
243
+ and pkey in properties_structure.main_properties
244
+ ):
245
+ keywords.append(ast.keyword(arg="resume", value=ast.Constant(True)))
246
+
247
+ if properties_structure.required and pkey in properties_structure.required:
248
+ keywords.append(ast.keyword(arg="not_null", value=ast.Constant(True)))
249
+
250
+ if (
251
+ properties_structure.partition_data
252
+ and pkey in properties_structure.partition_data
253
+ ):
254
+ keywords.append(ast.keyword(arg="partition_data", value=ast.Constant(True)))
255
+
256
+ if pkey in map_unique_by_property:
257
+ unique = map_unique_by_property[pkey].index_model
258
+ keywords.append(
259
+ ast.keyword(
260
+ arg="unique",
261
+ value=ast.Constant(unique.name),
262
+ )
263
+ )
264
+
265
+ if (
266
+ prop.default
267
+ ): # TODO Verificar esse modo de tratar valores default (principalmente expressões)
268
+ keywords.append(
269
+ ast.keyword(
270
+ arg="default_value",
271
+ value=ast.Name(str(prop.default), ctx=ast.Load()),
272
+ )
273
+ )
274
+
275
+ if prop.trim:
276
+ keywords.append(ast.keyword(arg="strip", value=ast.Constant(True)))
277
+
278
+ max = None
279
+ min = None
280
+ if prop.type in [PrimitiveTypes.STRING, PrimitiveTypes.EMAIL]:
281
+ if prop.max_length:
282
+ max = prop.max_length
283
+ elif prop.min_length:
284
+ min = prop.min_length
285
+ elif prop.type in [PrimitiveTypes.INTEGER, PrimitiveTypes.NUMBER]:
286
+ if prop.minimum:
287
+ min = prop.minimum
288
+ elif prop.maximum:
289
+ max = prop.maximum
290
+
291
+ if max:
292
+ keywords.append(ast.keyword(arg="max", value=ast.Constant(prop.max_length)))
293
+ if min:
294
+ keywords.append(ast.keyword(arg="min", value=ast.Constant(prop.min_length)))
295
+
296
+ if (
297
+ properties_structure.search_properties
298
+ and pkey in properties_structure.search_properties
299
+ ):
300
+ keywords.append(ast.keyword(arg="search", value=ast.Constant(True)))
301
+ else:
302
+ keywords.append(ast.keyword(arg="search", value=ast.Constant(False)))
303
+
304
+ if (
305
+ properties_structure.metric_label
306
+ and pkey in properties_structure.metric_label
307
+ ):
308
+ keywords.append(ast.keyword(arg="metric_label", value=ast.Constant(True)))
309
+
310
+ if prop.type == PrimitiveTypes.CPF and not prop.validator:
311
+ keywords.append(
312
+ ast.keyword(
313
+ arg="validator",
314
+ value=ast.Attribute(
315
+ value=ast.Call(
316
+ func=ast.Name(id="DTOFieldValidators", ctx=ast.Load()),
317
+ args=[],
318
+ keywords=[],
319
+ ),
320
+ attr="validate_cpf",
321
+ ctx=ast.Load(),
255
322
  ),
256
- annotation=ast.Name(
257
- id=prop_type,
323
+ )
324
+ )
325
+ elif prop.type == PrimitiveTypes.CNPJ and not prop.validator:
326
+ keywords.append(
327
+ ast.keyword(
328
+ arg="validator",
329
+ value=ast.Attribute(
330
+ value=ast.Call(
331
+ func=ast.Name(id="DTOFieldValidators", ctx=ast.Load()),
332
+ args=[],
333
+ keywords=[],
334
+ ),
335
+ attr="validate_cnpj",
258
336
  ctx=ast.Load(),
259
337
  ),
260
- value=ast.Call(
261
- func=ast.Name(id="DTOField", ctx=ast.Load()),
262
- args=[],
263
- keywords=keywords,
338
+ )
339
+ )
340
+ elif prop.type == PrimitiveTypes.CPF_CNPJ and not prop.validator:
341
+ keywords.append(
342
+ ast.keyword(
343
+ arg="validator",
344
+ value=ast.Attribute(
345
+ value=ast.Call(
346
+ func=ast.Name(id="DTOFieldValidators", ctx=ast.Load()),
347
+ args=[],
348
+ keywords=[],
349
+ ),
350
+ attr="validate_cpf_or_cnpj",
351
+ ctx=ast.Load(),
352
+ ),
353
+ )
354
+ )
355
+ elif prop.type == PrimitiveTypes.EMAIL and not prop.validator:
356
+ keywords.append(
357
+ ast.keyword(
358
+ arg="validator",
359
+ value=ast.Attribute(
360
+ value=ast.Call(
361
+ func=ast.Name(id="DTOFieldValidators", ctx=ast.Load()),
362
+ args=[],
363
+ keywords=[],
364
+ ),
365
+ attr="validate_email",
366
+ ctx=ast.Load(),
264
367
  ),
265
- simple=1,
266
368
  )
369
+ )
370
+ elif prop.validator:
371
+ keywords.append(
372
+ ast.keyword(
373
+ arg="validator",
374
+ value=ast.Name(prop.validator, ctx=ast.Load()),
375
+ )
376
+ )
267
377
 
268
- ast_dto_attributes.append(ast_attr)
378
+ if prop.immutable:
379
+ keywords.append(ast.keyword(arg="read_only", value=ast.Constant(True)))
269
380
 
270
- # 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
381
+ if prop.on_save:
382
+ keywords.append(
383
+ ast.keyword(
384
+ arg="convert_to_entity",
385
+ value=ast.Name(prop.on_save, ctx=ast.Load()),
386
+ )
387
+ )
280
388
 
281
- ast_entity_attr = ast.AnnAssign(
282
- target=ast.Name(
283
- id=CompilerStrUtil.to_snake_case(entity_field_name),
284
- ctx=ast.Store(),
285
- ),
286
- annotation=ast.Name(
287
- id=TypeUtil.property_type_to_python_type(prop.type),
288
- ctx=ast.Load(),
289
- ),
290
- value=ast.Constant(value=None),
291
- simple=1,
389
+ if prop.on_retrieve:
390
+ keywords.append(
391
+ ast.keyword(
392
+ arg="convert_from_entity",
393
+ value=ast.Name(id=prop.on_retrieve, ctx=ast.Load()),
394
+ )
395
+ )
396
+
397
+ if prop.domain_config:
398
+ result = self._compile_domain_config(pkey, prop, entity_model)
399
+ if not result:
400
+ raise Exception(f"Erro desconhecido ao compilar a propriedade {pkey}")
401
+
402
+ enum_class_name, ast_enum_class = result
403
+ enum_classes.append(ast_enum_class)
404
+
405
+ # Resolvendo o nome da propriedade no Entity
406
+ if (
407
+ properties_structure.entity_properties
408
+ and pkey in properties_structure.entity_properties
409
+ ):
410
+ entity_field_name = properties_structure.entity_properties[pkey].column
411
+ else:
412
+ entity_field_name = pkey
413
+
414
+ # Escrevendo, se necessário, o alias para o nome da entity
415
+ if entity_field_name != pkey:
416
+ keywords.append(
417
+ ast.keyword(
418
+ arg="entity_field",
419
+ value=ast.Constant(value=entity_field_name),
292
420
  )
421
+ )
293
422
 
294
- ast_entity_attributes.append(ast_entity_attr)
423
+ # Instanciando o atributo AST
424
+ if enum_class_name:
425
+ prop_type = enum_class_name
426
+ else:
427
+ prop_type = TypeUtil.property_type_to_python_type(prop.type)
428
+
429
+ ast_attr = ast.AnnAssign(
430
+ target=ast.Name(id=CompilerStrUtil.to_snake_case(pkey), ctx=ast.Store()),
431
+ annotation=ast.Name(
432
+ id=prop_type,
433
+ ctx=ast.Load(),
434
+ ),
435
+ value=ast.Call(
436
+ func=ast.Name(id="DTOField", ctx=ast.Load()),
437
+ args=[],
438
+ keywords=keywords,
439
+ ),
440
+ simple=1,
441
+ )
442
+
443
+ ast_dto_attributes.append(ast_attr)
444
+
445
+ # Entity
446
+ ast_entity_attr = ast.AnnAssign(
447
+ target=ast.Name(
448
+ id=CompilerStrUtil.to_snake_case(entity_field_name),
449
+ ctx=ast.Store(),
450
+ ),
451
+ annotation=ast.Name(
452
+ id=TypeUtil.property_type_to_python_type(prop.type),
453
+ ctx=ast.Load(),
454
+ ),
455
+ value=ast.Constant(value=None),
456
+ simple=1,
457
+ )
295
458
 
296
- return ast_dto_attributes, ast_entity_attributes, props_pk, enum_classes
459
+ ast_entity_attributes.append(ast_entity_attr)
297
460
 
298
461
  def _compile_domain_config(
299
462
  self,