nsj-rest-lib2 0.0.8__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,3 +1,4 @@
1
+ import re
1
2
  from typing import Any
2
3
 
3
4
  from nsj_rest_lib2.compiler.compiler_structures import (
@@ -5,6 +6,7 @@ from nsj_rest_lib2.compiler.compiler_structures import (
5
6
  PropertiesCompilerStructure,
6
7
  )
7
8
  from nsj_rest_lib2.compiler.dto_compiler import DTOCompiler
9
+ from nsj_rest_lib2.compiler.edl_model.primitives import REGEX_EXTERNAL_REF
8
10
  from nsj_rest_lib2.compiler.edl_model.repository_model import RepositoryModel
9
11
  from nsj_rest_lib2.compiler.entity_compiler import EntityCompiler
10
12
  from nsj_rest_lib2.compiler.property_compiler import EDLPropertyCompiler
@@ -13,11 +15,15 @@ from nsj_rest_lib2.compiler.edl_model.entity_model import EntityModel
13
15
 
14
16
  from nsj_rest_lib2.settings import get_logger
15
17
 
18
+ # TODO Autenticação nas rotas
19
+ # TODO Carregar, dinamicamente, em memória, o código compilado das dependÊncias por relacionamento
16
20
  # TODO Atualizar o status da entidade pelo worker de compilação (e talvez parar uma compilação, quando se delete uma entidade)
17
21
  # TODO Relacionamentos
18
22
  # TODO Classes Abstratas
19
23
  # TODO Partial Classes
20
24
  # TODO Migrations
25
+ # TODO Adicionar autenticação aos endpoints dinâmicos
26
+ # TODO Criar imagem docker base para as aplicações, usando venv (para poderem atualizar o pydantic)
21
27
 
22
28
 
23
29
  class CompilerResult:
@@ -102,17 +108,22 @@ class EDLCompiler:
102
108
  )
103
109
 
104
110
  # Criando a lista de atributos do DTO e da Entity; e recuperando as chaves primarias
105
- ast_dto_attributes, ast_entity_attributes, props_pk, enum_classes = (
106
- self._properties_compiler.compile(
107
- properties_structure,
108
- map_unique_by_property,
109
- entity_model,
110
- )
111
+ (
112
+ ast_dto_attributes,
113
+ ast_entity_attributes,
114
+ props_pk,
115
+ enum_classes,
116
+ related_imports,
117
+ ) = self._properties_compiler.compile(
118
+ properties_structure,
119
+ map_unique_by_property,
120
+ entity_model,
121
+ entity_models,
111
122
  )
112
123
 
113
124
  # Gerando o código do DTO
114
125
  dto_class_name, code_dto = self._dto_compiler.compile(
115
- entity_model, ast_dto_attributes, enum_classes
126
+ entity_model, ast_dto_attributes, enum_classes, related_imports
116
127
  )
117
128
 
118
129
  # Gerando o código da Entity
@@ -232,16 +243,27 @@ class EDLCompiler:
232
243
 
233
244
  def _list_dependencies(self, entity_model: EntityModel) -> list[str]:
234
245
  entities: list[str] = []
246
+
235
247
  if entity_model.trait_from:
236
248
  entities.append(entity_model.trait_from)
237
249
 
250
+ # Populando com as dependências de propriedades de relacionamento 1_N
251
+ for pkey in entity_model.properties:
252
+ prop = entity_model.properties[pkey]
253
+
254
+ if isinstance(prop.type, str):
255
+ external_match = re.match(REGEX_EXTERNAL_REF, prop.type)
256
+ if external_match:
257
+ external_dependency = external_match.group(0)
258
+ entities.append(external_dependency)
259
+
238
260
  return entities
239
261
 
240
262
 
241
263
  def get_files_from_directory(directory):
242
264
  files = []
243
265
  for file in os.listdir(directory):
244
- if file.endswith(".json"):
266
+ if file.endswith(".json") or file.endswith(".yml") or file.endswith(".yaml"):
245
267
  files.append(os.path.join(directory, file))
246
268
  return files
247
269
 
@@ -250,6 +272,7 @@ if __name__ == "__main__":
250
272
  import argparse
251
273
  import json
252
274
  import os
275
+ import yaml
253
276
 
254
277
  parser = argparse.ArgumentParser(
255
278
  description="Compila arquivos EDL para classes Python"
@@ -267,13 +290,16 @@ if __name__ == "__main__":
267
290
 
268
291
  entities = {}
269
292
  for file in files:
270
- with open(file) as f:
271
- edl_json = json.load(f)
293
+ with open(file, "r") as f:
294
+ if file.endswith(".json"):
295
+ edl = json.load(f)
296
+ else:
297
+ edl = yaml.safe_load(f)
272
298
 
273
299
  # Instanciando o objeto de modelo de entidade a partir do JSON,
274
300
  # e já realizando as validações básicas de tipo e estrutura.
275
301
  print(f"Validando arquivo: {file}")
276
- entity_model = EntityModel(**edl_json)
302
+ entity_model = EntityModel(**edl)
277
303
 
278
304
  complete_entity_id = f"{entity_model.escopo}/{entity_model.id}"
279
305
  entities[complete_entity_id] = entity_model
@@ -4,6 +4,7 @@ import black
4
4
 
5
5
  from nsj_rest_lib2.compiler.edl_model.entity_model import EntityModel
6
6
  from nsj_rest_lib2.compiler.util.str_util import CompilerStrUtil
7
+ from nsj_rest_lib2.compiler.util.type_naming_util import compile_dto_class_name
7
8
 
8
9
 
9
10
  class DTOCompiler:
@@ -15,6 +16,7 @@ class DTOCompiler:
15
16
  entity_model: EntityModel,
16
17
  ast_dto_attributes: list[ast.stmt],
17
18
  enum_classes: list[ast.stmt],
19
+ related_imports: list[tuple[str, str, str]],
18
20
  ) -> tuple[str, str]:
19
21
  """
20
22
  Compila o código do DTO a partir do AST e retorna o código compilado.
@@ -31,6 +33,7 @@ class DTOCompiler:
31
33
  :return: Código compilado do DTO
32
34
  :rtype: str
33
35
  """
36
+ # Criando o ast dos imports
34
37
  imports = [
35
38
  # import datetime
36
39
  ast.Import(names=[ast.alias(name="datetime", asname=None)]),
@@ -50,6 +53,12 @@ class DTOCompiler:
50
53
  names=[ast.alias(name="DTOField", asname=None)],
51
54
  level=0,
52
55
  ),
56
+ # from nsj_rest_lib.descriptor.dto_list_field import DTOField
57
+ ast.ImportFrom(
58
+ module="nsj_rest_lib.descriptor.dto_list_field",
59
+ names=[ast.alias(name="DTOListField", asname=None)],
60
+ level=0,
61
+ ),
53
62
  # from nsj_rest_lib.descriptor.dto_field_validators import DTOFieldValidators
54
63
  ast.ImportFrom(
55
64
  module="nsj_rest_lib.descriptor.dto_field_validators",
@@ -64,7 +73,24 @@ class DTOCompiler:
64
73
  ),
65
74
  ]
66
75
 
67
- class_name = f"{CompilerStrUtil.to_pascal_case(entity_model.id)}DTO"
76
+ for import_ in related_imports:
77
+ imports.append(
78
+ ast.ImportFrom(
79
+ module=f"dynamic.{import_[0]}",
80
+ names=[ast.alias(name=import_[1])],
81
+ level=0,
82
+ )
83
+ )
84
+ imports.append(
85
+ ast.ImportFrom(
86
+ module=f"dynamic.{import_[0]}",
87
+ names=[ast.alias(name=import_[2])],
88
+ level=0,
89
+ )
90
+ )
91
+
92
+ # Criando o ast da classe
93
+ class_name = compile_dto_class_name(entity_model.id)
68
94
  ast_class = ast.ClassDef(
69
95
  name=class_name,
70
96
  bases=[ast.Name(id="DTOBase", ctx=ast.Load())],
@@ -1,6 +1,16 @@
1
- from pydantic import BaseModel, Field
1
+ from pydantic import BaseModel, Field, model_validator
2
2
  from typing import List, Optional, Literal
3
3
 
4
4
 
5
5
  class ColumnMetaModel(BaseModel):
6
- column: str = Field(..., description="Nome da coluna no banco de dados.")
6
+ column: Optional[str] = Field(None, description="Nome da coluna no banco de dados.")
7
+ relation_column: Optional[str] = Field(
8
+ None,
9
+ description="Nome da coluna usada para relacionamento com outra entidade (para um relacionamento 1_N, indica a coluna da entidade relacionada, que aponta para a PK da entidade corrente).",
10
+ )
11
+
12
+ @model_validator(mode="after")
13
+ def check_columns(self):
14
+ if self.column is None and self.relation_column is None:
15
+ raise ValueError("column or relation_column must be provided")
16
+ return self
@@ -1,3 +1,5 @@
1
+ import uuid
2
+
1
3
  from pydantic import BaseModel, Field
2
4
  from typing import Dict, List, Optional
3
5
 
@@ -64,3 +66,9 @@ class EntityModel(BaseModel):
64
66
  ...,
65
67
  description="Definição da API REST associada ao modelo, com todos os seus endpoints.",
66
68
  )
69
+
70
+ # Propriedades de controle da compilação (não fazem parte do JSON de representação das entidades)
71
+ tenant: int = Field(default=0, exclude=True)
72
+ grupo_empresarial: uuid.UUID = Field(
73
+ default=uuid.UUID("00000000-0000-0000-0000-000000000000"), exclude=True
74
+ )
@@ -1,5 +1,13 @@
1
1
  import enum
2
- from typing import List
2
+
3
+ from typing import Annotated, List, Union
4
+ from pydantic import StringConstraints
5
+
6
+ REGEX_EXTERNAL_REF = r"^(\w+)\/(\w+)$"
7
+ REGEX_INTERNAL_REF = r"^#\/(\w+)\/(\w+)$"
8
+
9
+ ExternalRefType = Annotated[str, StringConstraints(pattern=REGEX_EXTERNAL_REF)]
10
+ InternalRefType = Annotated[str, StringConstraints(pattern=REGEX_INTERNAL_REF)]
3
11
 
4
12
 
5
13
  class PrimitiveTypes(enum.Enum):
@@ -8,8 +16,6 @@ class PrimitiveTypes(enum.Enum):
8
16
  NUMBER = "number"
9
17
  INTEGER = "integer"
10
18
  BOOLEAN = "boolean"
11
- ARRAY = "array"
12
- OBJECT = "object"
13
19
  UUID = "uuid"
14
20
  CURRENCY = "currency"
15
21
  QUANTITY = "quantity"
@@ -21,13 +27,13 @@ class PrimitiveTypes(enum.Enum):
21
27
  DATETIME = "datetime"
22
28
 
23
29
 
30
+ PropertyType = Union[PrimitiveTypes, ExternalRefType, InternalRefType]
31
+
24
32
  MAPPING_PRIMITIVE_TYPES_TO_PYTHON = {
25
33
  PrimitiveTypes.STRING: "str",
26
34
  PrimitiveTypes.NUMBER: "float",
27
35
  PrimitiveTypes.INTEGER: "int",
28
36
  PrimitiveTypes.BOOLEAN: "bool",
29
- PrimitiveTypes.ARRAY: "List",
30
- PrimitiveTypes.OBJECT: "dict",
31
37
  PrimitiveTypes.UUID: "uuid.UUID",
32
38
  PrimitiveTypes.CURRENCY: "float",
33
39
  PrimitiveTypes.QUANTITY: "float",
@@ -41,3 +47,9 @@ MAPPING_PRIMITIVE_TYPES_TO_PYTHON = {
41
47
 
42
48
  BasicTypes = int | bool | float | str
43
49
  DefaultTypes = BasicTypes | List[BasicTypes]
50
+
51
+
52
+ class CardinalityTypes(enum.Enum):
53
+ C1_1 = "1_1"
54
+ C1_N = "1_N"
55
+ CN_N = "N_N"
@@ -1,8 +1,8 @@
1
- from pydantic import BaseModel, Field
1
+ from pydantic import BaseModel, Field, model_validator
2
2
  from typing import List, Optional
3
3
 
4
4
  from nsj_rest_lib2.compiler.edl_model.primitives import BasicTypes, DefaultTypes
5
- from nsj_rest_lib2.compiler.edl_model.primitives import PrimitiveTypes
5
+ from nsj_rest_lib2.compiler.edl_model.primitives import CardinalityTypes, PropertyType
6
6
 
7
7
 
8
8
  class DomainConfigModel(BaseModel):
@@ -13,7 +13,7 @@ class DomainConfigModel(BaseModel):
13
13
 
14
14
 
15
15
  class PropertyMetaModel(BaseModel):
16
- type: PrimitiveTypes = Field(..., description="Tipo da propriedade.")
16
+ type: PropertyType = Field(..., description="Tipo da propriedade.")
17
17
  label: Optional[str] = Field(None, description="Rótulo da propriedade.")
18
18
  description: Optional[str] = Field(None, description="Descrição da propriedade.")
19
19
  default: Optional[DefaultTypes] = Field(
@@ -28,6 +28,10 @@ class PropertyMetaModel(BaseModel):
28
28
  description="Indica se a propriedade é parte de uma chave alternativa (chave natural).",
29
29
  alias="keyAlternative",
30
30
  )
31
+ cardinality: Optional[CardinalityTypes] = Field(
32
+ None,
33
+ description="Cardinalidade do relacionamento (válido para propriedades do tipo 'array' ou 'object').",
34
+ )
31
35
  # Validação
32
36
  max_length: Optional[int] = Field(
33
37
  None, description="Comprimento máximo (para strings)."
@@ -80,3 +84,11 @@ class PropertyMetaModel(BaseModel):
80
84
  None,
81
85
  description="Função de conversão do tipo da entidade para o tipo da API (ex.: converter uuid para string).",
82
86
  )
87
+
88
+ @model_validator(mode="after")
89
+ def check_cardinality_required(self):
90
+ if isinstance(self.type, str) and self.cardinality is None:
91
+ raise ValueError(
92
+ "The property 'cardinality' is required when type point to other entity."
93
+ )
94
+ return self
@@ -1,10 +1,10 @@
1
1
  from pydantic import BaseModel, Field
2
2
 
3
- from nsj_rest_lib2.compiler.edl_model.primitives import BasicTypes, PrimitiveTypes
3
+ from nsj_rest_lib2.compiler.edl_model.primitives import BasicTypes, PropertyType
4
4
 
5
5
 
6
6
  class TraitPropertyMetaModel(BaseModel):
7
- type: PrimitiveTypes = Field(..., description="Tipo da propriedade.")
7
+ type: PropertyType = Field(..., description="Tipo da propriedade.")
8
8
  value: BasicTypes = Field(
9
9
  ..., description="Valor fixo da propriedade de condicionamento do trait."
10
10
  )
@@ -5,6 +5,7 @@ import black
5
5
  from nsj_rest_lib2.compiler.edl_model.entity_model import EntityModel
6
6
  from nsj_rest_lib2.compiler.edl_model.repository_model import RepositoryModel
7
7
  from nsj_rest_lib2.compiler.util.str_util import CompilerStrUtil
8
+ from nsj_rest_lib2.compiler.util.type_naming_util import compile_entity_class_name
8
9
 
9
10
 
10
11
  class EntityCompiler:
@@ -66,7 +67,7 @@ class EntityCompiler:
66
67
  if CompilerStrUtil.to_snake_case(props_pk[0]) not in default_order_fields:
67
68
  default_order_fields.append(CompilerStrUtil.to_snake_case(props_pk[0]))
68
69
 
69
- class_name = f"{CompilerStrUtil.to_pascal_case(entity_model.id)}Entity"
70
+ class_name = compile_entity_class_name(entity_model.id)
70
71
  ast_class = ast.ClassDef(
71
72
  name=class_name,
72
73
  bases=[ast.Name(id="EntityBase", ctx=ast.Load())],
@@ -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,288 +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 = []
45
-
46
- if prop.pk:
47
- keywords.append(ast.keyword(arg="pk", value=ast.Constant(True)))
48
- props_pk.append(pkey)
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
+ )
49
94
 
50
- if prop.key_alternative:
51
- keywords.append(
52
- ast.keyword(arg="candidate_key", value=ast.Constant(True))
53
- )
95
+ elif isinstance(prop.type, str):
96
+ external_match = re.match(REGEX_EXTERNAL_REF, prop.type)
54
97
 
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))
67
- )
98
+ if external_match:
99
+ # Resolvendo o id da entidade
100
+ related_entity_id = external_match.group(2)
68
101
 
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))
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
75
106
  )
76
107
 
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
- )
108
+ # Resolvendo o caminho do import
109
+ related_entity_key = external_match.group(0)
85
110
 
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
116
 
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
-
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)
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
- )
200
+ ast_dto_attributes.append(ast_attr)
201
+ else:
202
+ # TODO
203
+ pass
265
204
 
266
- # Instanciando o atributo AST
267
- if enum_class_name:
268
- prop_type = enum_class_name
205
+ elif re.match(REGEX_INTERNAL_REF, prop.type):
206
+ # TODO
207
+ pass
269
208
  else:
270
- 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
+ )
271
218
 
272
- ast_attr = ast.AnnAssign(
273
- target=ast.Name(
274
- id=CompilerStrUtil.to_snake_case(pkey), ctx=ast.Store()
275
- ),
276
- annotation=ast.Name(
277
- id=prop_type,
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",
278
321
  ctx=ast.Load(),
279
322
  ),
280
- value=ast.Call(
281
- func=ast.Name(id="DTOField", ctx=ast.Load()),
282
- args=[],
283
- keywords=keywords,
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",
336
+ ctx=ast.Load(),
284
337
  ),
285
- simple=1,
286
338
  )
287
-
288
- ast_dto_attributes.append(ast_attr)
289
-
290
- # Entity
291
- ast_entity_attr = ast.AnnAssign(
292
- target=ast.Name(
293
- id=CompilerStrUtil.to_snake_case(entity_field_name),
294
- ctx=ast.Store(),
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(),
295
352
  ),
296
- annotation=ast.Name(
297
- id=TypeUtil.property_type_to_python_type(prop.type),
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",
298
366
  ctx=ast.Load(),
299
367
  ),
300
- value=ast.Constant(value=None),
301
- simple=1,
302
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
+ )
303
377
 
304
- ast_entity_attributes.append(ast_entity_attr)
378
+ if prop.immutable:
379
+ keywords.append(ast.keyword(arg="read_only", value=ast.Constant(True)))
380
+
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
+ )
388
+
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),
420
+ )
421
+ )
422
+
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
+ )
305
458
 
306
- return ast_dto_attributes, ast_entity_attributes, props_pk, enum_classes
459
+ ast_entity_attributes.append(ast_entity_attr)
307
460
 
308
461
  def _compile_domain_config(
309
462
  self,
@@ -0,0 +1,21 @@
1
+ import uuid
2
+
3
+ from nsj_rest_lib2.compiler.util.str_util import CompilerStrUtil
4
+
5
+
6
+ def compile_namespace_keys(
7
+ tenant: str | int | None, grupo_empresarial: str | uuid.UUID | None
8
+ ) -> tuple[str, str, str]:
9
+ grupo_key = f"tenant_{tenant}.ge_{grupo_empresarial}"
10
+ tenant_key = f"tenant_{tenant}"
11
+ default_key = "default"
12
+
13
+ return (grupo_key, tenant_key, default_key)
14
+
15
+
16
+ def compile_dto_class_name(entity_id: str) -> str:
17
+ return f"{CompilerStrUtil.to_pascal_case(entity_id)}DTO"
18
+
19
+
20
+ def compile_entity_class_name(entity_id: str) -> str:
21
+ return f"{CompilerStrUtil.to_pascal_case(entity_id)}Entity"
@@ -6,6 +6,7 @@ import types
6
6
 
7
7
  from nsj_rest_lib.settings import get_logger
8
8
 
9
+ from nsj_rest_lib2.compiler.util.type_naming_util import compile_namespace_keys
9
10
  from nsj_rest_lib2.exception import MissingEntityConfigException
10
11
  from nsj_rest_lib2.redis_config import get_redis
11
12
  from nsj_rest_lib2.settings import ESCOPO_RESTLIB2, MIN_TIME_SOURCE_REFRESH
@@ -44,9 +45,9 @@ class EntityLoader:
44
45
  grupo_empresarial: str | None,
45
46
  ) -> tuple[str, str, dict, bool, list[str]]:
46
47
  # Montando as chaves dos namespaces
47
- grupo_key = f"tenant_{tenant}.ge_{grupo_empresarial}"
48
- tenant_key = f"tenant_{tenant}"
49
- default_key = "default"
48
+ grupo_key, tenant_key, default_key = compile_namespace_keys(
49
+ tenant, grupo_empresarial
50
+ )
50
51
 
51
52
  result = self._load_entity_source_from_memory(
52
53
  entity_resource, grupo_key, tenant_key, default_key
@@ -182,6 +183,18 @@ class EntityLoader:
182
183
  with self._lock:
183
184
  namespaces_dict.clear()
184
185
 
186
+ def _ensure_dynamic_package(self):
187
+ """
188
+ Garante que exista um pacote 'dynamic' em sys.modules.
189
+ """
190
+ pkg = sys.modules.get("dynamic")
191
+ if pkg is None:
192
+ pkg = types.ModuleType("dynamic")
193
+ pkg.__path__ = [] # marca como pacote
194
+ pkg.__package__ = "dynamic"
195
+ sys.modules["dynamic"] = pkg
196
+ return pkg
197
+
185
198
  def _execute_entity_source(
186
199
  self,
187
200
  entity_config_str: str,
@@ -233,19 +246,32 @@ class EntityLoader:
233
246
 
234
247
  # Carregando a entidade no namespace
235
248
  with self._lock:
249
+ self._ensure_dynamic_package()
250
+
236
251
  namespace = namespaces_dict.get(entity_config_key)
237
252
  if namespace is None:
238
253
  namespace = Namespace()
239
254
  namespace.key = entity_config_key
240
255
  namespaces_dict[entity_config_key] = namespace
241
256
 
242
- # Executando o código da entidade
243
- module = types.ModuleType(entity_config_key)
244
- sys.modules[entity_config_key] = module
245
- module.__dict__["__builtins__"] = __builtins__
257
+ # Hot reload: removendo o módulo do sys.modules, se existir
258
+ full_name = f"dynamic.{entity_config_key}"
259
+ # if full_name in sys.modules:
260
+ # sys.modules.pop(full_name)
246
261
 
247
- namespace.module = module
248
- namespace.entities_dict = module.__dict__
262
+ # Executando o código da entidade
263
+ module = sys.modules.get(full_name)
264
+ if not module:
265
+ module = types.ModuleType(full_name)
266
+ module.__package__ = "dynamic"
267
+ module.__dict__["__builtins__"] = __builtins__
268
+ sys.modules[full_name] = module
269
+
270
+ parent = sys.modules["dynamic"]
271
+ setattr(parent, entity_config_key, module)
272
+
273
+ namespace.module = module
274
+ namespace.entities_dict = module.__dict__
249
275
 
250
276
  self._safe_exec(source_dto, namespace.entities_dict, "DTO source")
251
277
  self._safe_exec(source_entity, namespace.entities_dict, "Entity source")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nsj_rest_lib2
3
- Version: 0.0.8
3
+ Version: 0.0.9
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
@@ -17,6 +17,7 @@ Requires-Dist: redis<7.0.0,>=6.4.0
17
17
  Requires-Dist: nsj-multi-database-lib<3.0.0,>=2.0.1
18
18
  Requires-Dist: pydantic<3.0.0,>=2.11.9
19
19
  Requires-Dist: black<26.0.0,>=25.1.0
20
+ Requires-Dist: pyyaml>7.0.0,>=6.0.3
20
21
 
21
22
  # nsj_rest_lib2
22
23
 
@@ -4,29 +4,30 @@ nsj_rest_lib2/redis_config.py,sha256=4KLcvYS3nJO7PMQgF6F9_j6r-TyqcS7TBbd3LEQuKDU
4
4
  nsj_rest_lib2/settings.py,sha256=Hn_o1HZmievnYb8D1kNT2Nq-OEjxbyNjOiOpbnFsMwE,367
5
5
  nsj_rest_lib2/compiler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  nsj_rest_lib2/compiler/ai_compiler.py,sha256=shAtN4T0ai_52qh15L3mK1QbeC6glHOR6C3J3gj14II,9029
7
- nsj_rest_lib2/compiler/compiler.py,sha256=oFuHBSQekXYhYREAiiHARC9Rpr5ZKUlgh5aDQ8bqslE,11143
7
+ nsj_rest_lib2/compiler/compiler.py,sha256=wkREdCrQ6mq6-R-5nC5ZXDGNpSEIPjuSjt-NCxOS6to,12228
8
8
  nsj_rest_lib2/compiler/compiler_structures.py,sha256=2bM4_7lG1fytDGxJl6SU9pLsbspiNV36gVn9-O-23Q8,1009
9
- nsj_rest_lib2/compiler/dto_compiler.py,sha256=WyUM3V2_5r3Zn-teR1CNMgRKr9sH_yALzUe-VRDJOwY,3163
10
- nsj_rest_lib2/compiler/entity_compiler.py,sha256=ytcS-RPQTJtf56z4HqT3xQLBYzbd6UUPGsaGB1pj_EA,4240
11
- nsj_rest_lib2/compiler/property_compiler.py,sha256=ZJ3GLSbth1nGgxujUKjlR2lg-PeiOZ2NeqfqQuZm2xU,14396
9
+ nsj_rest_lib2/compiler/dto_compiler.py,sha256=GAKWFvks0Duqs2EsEr1-BFx2-Kny72jJMbl9ZyIEDXw,4125
10
+ nsj_rest_lib2/compiler/entity_compiler.py,sha256=zLXO6USY4Rr0Hnk4wGep5K8DiHxJv-W-BBz_-g4OhCA,4307
11
+ nsj_rest_lib2/compiler/property_compiler.py,sha256=RR5F-7D2nLG6ThjC0rdqwU3G5SMN1P5tBusZaAPwIMk,18865
12
12
  nsj_rest_lib2/compiler/edl_model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  nsj_rest_lib2/compiler/edl_model/ai_entity_edl.py,sha256=664QBDcOgVnyfwtUOXO1W7AKaZhueBG335x5DuogruY,7644
14
14
  nsj_rest_lib2/compiler/edl_model/api_model.py,sha256=pH0Uiq_64AGvkHqwY44TrulWWZXbi6M0EKJWUhSqKj0,837
15
- nsj_rest_lib2/compiler/edl_model/column_meta_model.py,sha256=V1VI0LslSDO6oB2cOQrTcBijBnWIPL7s4xNbI2Wb8Kk,195
16
- nsj_rest_lib2/compiler/edl_model/entity_model.py,sha256=lE4RS4776IsP5yoxHuGUV6B7G1_yxM0kb0ogFgSYVhs,3364
15
+ nsj_rest_lib2/compiler/edl_model/column_meta_model.py,sha256=3OLsRwEz66Cktzew6Hie3HZXK9u20GXlWUU0HtFtwfk,709
16
+ nsj_rest_lib2/compiler/edl_model/entity_model.py,sha256=sXVfC30P3-q2-fQ3XB_-3vpNjqFPIK5oBIVbwkXNFLU,3662
17
17
  nsj_rest_lib2/compiler/edl_model/index_model.py,sha256=cXWlu0hxtro5vvYoirkDW4R3PCnBW5oCCWjRJ6AX5zE,508
18
- nsj_rest_lib2/compiler/edl_model/primitives.py,sha256=VAzTbpkQAZWkeTdpoXL4FSaO1KEMTPXOxl6WxIJMWHk,1104
19
- nsj_rest_lib2/compiler/edl_model/property_meta_model.py,sha256=i7lu-JFvPzUDBdsHB6kspGUyCkqf_GuTRmKfpIZj-K0,3444
18
+ nsj_rest_lib2/compiler/edl_model/primitives.py,sha256=cWEys87xDpgotyRUXkzvFvY4LHeawzBEEyz0Xed18AQ,1454
19
+ nsj_rest_lib2/compiler/edl_model/property_meta_model.py,sha256=x2SApvI-5MZTErAHeOXnR6qfjflhSs8r6Y9KMtCykV0,3960
20
20
  nsj_rest_lib2/compiler/edl_model/repository_model.py,sha256=Vt1HxlaoifP4w5ij1laKDkD1-COBihE8EX1HkdEDUSo,977
21
- nsj_rest_lib2/compiler/edl_model/trait_property_meta_model.py,sha256=NA8eRh5rA0boFmFd-0sHLrilOoOQSeN-amN_4TXcGiA,358
21
+ nsj_rest_lib2/compiler/edl_model/trait_property_meta_model.py,sha256=ZC2oTvc9Y2Oiy4NLNHQLiMOLRWDAOdF8GJxOw4nqHdk,354
22
22
  nsj_rest_lib2/compiler/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  nsj_rest_lib2/compiler/util/str_util.py,sha256=lVP1yHhj1pOd6ULtTnkcfX6Gqrpe4yCBratHUhBNGcI,843
24
+ nsj_rest_lib2/compiler/util/type_naming_util.py,sha256=sahlxtYUPcksqlX1hygaoTF7vuD8tY8eosgOR04YLAs,612
24
25
  nsj_rest_lib2/compiler/util/type_util.py,sha256=HTKOH4uRTOY0YgoM8oUv_6cEcReE_bgKYXFBsQCb-3A,357
25
26
  nsj_rest_lib2/controller/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
27
  nsj_rest_lib2/controller/dynamic_controller.py,sha256=XMqxe1NW-NE5XwomXb4pSNdALQHpP74Hc26R4fnmXqg,15194
27
28
  nsj_rest_lib2/service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- nsj_rest_lib2/service/entity_loader.py,sha256=ITYnC7syPmSVct12flRpyQhMCA1jUiGSiu6539kQW9k,12525
29
- nsj_rest_lib2-0.0.8.dist-info/METADATA,sha256=Dd83C-bWpwER9sjSsUAFn0E9TrkNmS0qfKWaqDjBt0A,1324
30
- nsj_rest_lib2-0.0.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
31
- nsj_rest_lib2-0.0.8.dist-info/top_level.txt,sha256=L6zh0EfH8_rur7OJ8_V-El-XEMf4qg3bkF8ADgqLVIA,14
32
- nsj_rest_lib2-0.0.8.dist-info/RECORD,,
29
+ nsj_rest_lib2/service/entity_loader.py,sha256=PJX-cPPCllhZuqSZzj8ZX_0HZQBnt20dqLc9E0e0GtA,13472
30
+ nsj_rest_lib2-0.0.9.dist-info/METADATA,sha256=SGdzF8Wef-XXnNnH3Q1bKfM-fVAetqyXTGHHIiKDLAk,1360
31
+ nsj_rest_lib2-0.0.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
32
+ nsj_rest_lib2-0.0.9.dist-info/top_level.txt,sha256=L6zh0EfH8_rur7OJ8_V-El-XEMf4qg3bkF8ADgqLVIA,14
33
+ nsj_rest_lib2-0.0.9.dist-info/RECORD,,