nsj-rest-lib2 0.0.7__tar.gz → 0.0.9__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 (40) hide show
  1. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/PKG-INFO +2 -1
  2. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/compiler.py +53 -16
  3. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/dto_compiler.py +27 -1
  4. nsj_rest_lib2-0.0.9/nsj_rest_lib2/compiler/edl_model/column_meta_model.py +16 -0
  5. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/edl_model/entity_model.py +10 -2
  6. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/edl_model/primitives.py +17 -5
  7. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/edl_model/property_meta_model.py +15 -3
  8. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/edl_model/trait_property_meta_model.py +2 -2
  9. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/entity_compiler.py +2 -1
  10. nsj_rest_lib2-0.0.9/nsj_rest_lib2/compiler/property_compiler.py +522 -0
  11. nsj_rest_lib2-0.0.9/nsj_rest_lib2/compiler/util/type_naming_util.py +21 -0
  12. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/controller/dynamic_controller.py +92 -44
  13. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/service/entity_loader.py +125 -42
  14. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2.egg-info/PKG-INFO +2 -1
  15. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2.egg-info/SOURCES.txt +2 -0
  16. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2.egg-info/requires.txt +1 -0
  17. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/setup.cfg +2 -1
  18. nsj_rest_lib2-0.0.7/nsj_rest_lib2/compiler/edl_model/column_meta_model.py +0 -6
  19. nsj_rest_lib2-0.0.7/nsj_rest_lib2/compiler/property_compiler.py +0 -359
  20. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/README.md +0 -0
  21. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/__init__.py +0 -0
  22. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/__init__.py +0 -0
  23. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/ai_compiler.py +0 -0
  24. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/compiler_structures.py +0 -0
  25. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/edl_model/__init__.py +0 -0
  26. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/edl_model/ai_entity_edl.py +0 -0
  27. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/edl_model/api_model.py +0 -0
  28. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/edl_model/index_model.py +0 -0
  29. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/edl_model/repository_model.py +0 -0
  30. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/util/__init__.py +0 -0
  31. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/util/str_util.py +0 -0
  32. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/compiler/util/type_util.py +0 -0
  33. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/controller/__init__.py +0 -0
  34. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/exception.py +0 -0
  35. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/redis_config.py +0 -0
  36. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/service/__init__.py +0 -0
  37. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2/settings.py +0 -0
  38. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2.egg-info/dependency_links.txt +0 -0
  39. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/nsj_rest_lib2.egg-info/top_level.txt +0 -0
  40. {nsj_rest_lib2-0.0.7 → nsj_rest_lib2-0.0.9}/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.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
 
@@ -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,14 +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
 
16
- # TODO Rever a questão do tempo de expiração ser renovado, na leitura do redis
18
+ # TODO Autenticação nas rotas
19
+ # TODO Carregar, dinamicamente, em memória, o código compilado das dependÊncias por relacionamento
17
20
  # TODO Atualizar o status da entidade pelo worker de compilação (e talvez parar uma compilação, quando se delete uma entidade)
18
21
  # TODO Relacionamentos
19
22
  # TODO Classes Abstratas
20
23
  # TODO Partial Classes
21
24
  # TODO Migrations
22
- # TODO Migrar para a nsj_rest_lib2
23
- # TODO Alterar o padrão de nomenclatura para snake_case
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)
24
27
 
25
28
 
26
29
  class CompilerResult:
@@ -29,7 +32,9 @@ class CompilerResult:
29
32
  self.dto_code: str | None = None
30
33
  self.entity_class_name: str | None = None
31
34
  self.entity_code: str | None = None
32
- # TODO Informacoes das rotas
35
+ self.api_expose: bool | None = None
36
+ self.api_resource: str | None = None
37
+ self.api_verbs: list[str] | None = None
33
38
 
34
39
 
35
40
  class EDLCompiler:
@@ -103,17 +108,22 @@ class EDLCompiler:
103
108
  )
104
109
 
105
110
  # Criando a lista de atributos do DTO e da Entity; e recuperando as chaves primarias
106
- ast_dto_attributes, ast_entity_attributes, props_pk, enum_classes = (
107
- self._properties_compiler.compile(
108
- properties_structure,
109
- map_unique_by_property,
110
- entity_model,
111
- )
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,
112
122
  )
113
123
 
114
124
  # Gerando o código do DTO
115
125
  dto_class_name, code_dto = self._dto_compiler.compile(
116
- entity_model, ast_dto_attributes, enum_classes
126
+ entity_model, ast_dto_attributes, enum_classes, related_imports
117
127
  )
118
128
 
119
129
  # Gerando o código da Entity
@@ -121,13 +131,18 @@ class EDLCompiler:
121
131
  entity_model, ast_entity_attributes, props_pk
122
132
  )
123
133
 
124
- # Retornando o resultado
134
+ # Construindo o resultado
125
135
  compiler_result = CompilerResult()
126
136
  compiler_result.entity_class_name = entity_class_name
127
137
  compiler_result.entity_code = code_entity
128
138
  compiler_result.dto_class_name = dto_class_name
129
139
  compiler_result.dto_code = code_dto
130
140
 
141
+ # Compilando questões das APIs
142
+ compiler_result.api_expose = entity_model.api.expose
143
+ compiler_result.api_resource = entity_model.api.resource
144
+ compiler_result.api_verbs = entity_model.api.verbs
145
+
131
146
  return compiler_result
132
147
 
133
148
  def _make_properties_structures(
@@ -228,16 +243,27 @@ class EDLCompiler:
228
243
 
229
244
  def _list_dependencies(self, entity_model: EntityModel) -> list[str]:
230
245
  entities: list[str] = []
246
+
231
247
  if entity_model.trait_from:
232
248
  entities.append(entity_model.trait_from)
233
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
+
234
260
  return entities
235
261
 
236
262
 
237
263
  def get_files_from_directory(directory):
238
264
  files = []
239
265
  for file in os.listdir(directory):
240
- if file.endswith(".json"):
266
+ if file.endswith(".json") or file.endswith(".yml") or file.endswith(".yaml"):
241
267
  files.append(os.path.join(directory, file))
242
268
  return files
243
269
 
@@ -246,6 +272,7 @@ if __name__ == "__main__":
246
272
  import argparse
247
273
  import json
248
274
  import os
275
+ import yaml
249
276
 
250
277
  parser = argparse.ArgumentParser(
251
278
  description="Compila arquivos EDL para classes Python"
@@ -263,13 +290,16 @@ if __name__ == "__main__":
263
290
 
264
291
  entities = {}
265
292
  for file in files:
266
- with open(file) as f:
267
- 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)
268
298
 
269
299
  # Instanciando o objeto de modelo de entidade a partir do JSON,
270
300
  # e já realizando as validações básicas de tipo e estrutura.
271
301
  print(f"Validando arquivo: {file}")
272
- entity_model = EntityModel(**edl_json)
302
+ entity_model = EntityModel(**edl)
273
303
 
274
304
  complete_entity_id = f"{entity_model.escopo}/{entity_model.id}"
275
305
  entities[complete_entity_id] = entity_model
@@ -286,3 +316,10 @@ if __name__ == "__main__":
286
316
  print(f"DTO: {compiler_result.dto_class_name}")
287
317
  print(f"{compiler_result.dto_code}")
288
318
  print("\n")
319
+
320
+ print("==========================================================")
321
+ print("API Expose: ", compiler_result.api_expose)
322
+ print("API Route Path: ", compiler_result.api_resource)
323
+ print("API Verbs: ", compiler_result.api_verbs)
324
+ print("==========================================================")
325
+ print("\n")
@@ -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())],
@@ -0,0 +1,16 @@
1
+ from pydantic import BaseModel, Field, model_validator
2
+ from typing import List, Optional, Literal
3
+
4
+
5
+ class ColumnMetaModel(BaseModel):
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
 
@@ -60,7 +62,13 @@ class EntityModel(BaseModel):
60
62
  repository: RepositoryModel = Field(
61
63
  ..., description="Configurações de mapeamento para o banco de dados."
62
64
  )
63
- api: Optional[APIModel] = Field(
64
- None,
65
+ api: APIModel = Field(
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())],