nsj-rest-lib2 0.0.21__tar.gz → 0.0.22__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.
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/PKG-INFO +1 -14
- nsj_rest_lib2-0.0.22/README.md +6 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/compiler.py +3 -13
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/primitives.py +8 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/property_meta_model.py +0 -1
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/property_compiler.py +267 -20
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/util/str_util.py +10 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/service/entity_loader.py +0 -1
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2.egg-info/PKG-INFO +1 -14
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/setup.cfg +1 -1
- nsj_rest_lib2-0.0.21/README.md +0 -19
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/__init__.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/__init__.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/ai_compiler.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/compiler_structures.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/dto_compiler.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/__init__.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/ai_entity_edl.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/api_model.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/column_meta_model.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/entity_model.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/entity_model_base.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/entity_model_root.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/index_model.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/repository_model.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/trait_property_meta_model.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/entity_compiler.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/model.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/util/__init__.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/util/type_naming_util.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/util/type_util.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/controller/__init__.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/controller/dynamic_controller.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/exception.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/redis_config.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/service/__init__.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/settings.py +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2.egg-info/SOURCES.txt +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2.egg-info/dependency_links.txt +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2.egg-info/requires.txt +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2.egg-info/top_level.txt +0 -0
- {nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nsj_rest_lib2
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.22
|
|
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
|
|
@@ -25,16 +25,3 @@ Biblioteca para permitir a distribuição de rotas dinâmicas numa API, configur
|
|
|
25
25
|
|
|
26
26
|
[ESPECIFICAÇÃO DO MODELO DE ENTIDADES](docs/especificacao.md)
|
|
27
27
|
|
|
28
|
-
## TODO
|
|
29
|
-
* Valores default
|
|
30
|
-
* Usar trait_properties como valor default
|
|
31
|
-
* Não está carregando a lista de dependências de execução, para os components
|
|
32
|
-
* Implementar gravação de entidades com extensão parcial
|
|
33
|
-
* Unificar o arquivo redis_config.py
|
|
34
|
-
* Usar pydantic, ou similar, para transformar a configuração das entidades, no redis, num objeto
|
|
35
|
-
* Rever modo de usar o InjectFactory (talvez dando ciência, ao RestLib, do padrão multibanco)
|
|
36
|
-
* Implementar e documentar campos join
|
|
37
|
-
* Implementar e documentar conjuntos
|
|
38
|
-
* Dar erro ao haver conflito de nomes das propriedades (por qualquer tipo de herança)
|
|
39
|
-
* Rotas para o inline
|
|
40
|
-
* inline será para composição (arquivo externo é agregação)
|
|
@@ -25,18 +25,6 @@ from nsj_rest_lib2.compiler.edl_model.entity_model import EntityModel
|
|
|
25
25
|
|
|
26
26
|
from nsj_rest_lib2.settings import get_logger
|
|
27
27
|
|
|
28
|
-
# TODO GET e POST de relacionamentos 1X1
|
|
29
|
-
# TODO Revisar compilação de valores default (sensível a tipos)
|
|
30
|
-
# TODO Implementar suporte a conjuntos
|
|
31
|
-
# TODO Autenticação nas rotas
|
|
32
|
-
# TODO Atualizar o status da entidade pelo worker de compilação (e talvez parar uma compilação, quando se delete uma entidade)
|
|
33
|
-
# TODO Classes Abstratas
|
|
34
|
-
# TODO Partial Classes
|
|
35
|
-
# TODO Migrations
|
|
36
|
-
# TODO Criar imagem docker base para as aplicações, usando venv (para poderem atualizar o pydantic)
|
|
37
|
-
|
|
38
|
-
# TODO Suporte ao "min_items" dos relacionamentos no RestLib1
|
|
39
|
-
|
|
40
28
|
|
|
41
29
|
class EDLCompiler:
|
|
42
30
|
def __init__(self) -> None:
|
|
@@ -117,7 +105,9 @@ class EDLCompiler:
|
|
|
117
105
|
f"Entidade base '{entity_model.partial_of}' da extensão parcial '{entity_model.id}' é inválida."
|
|
118
106
|
)
|
|
119
107
|
|
|
120
|
-
self._validate_partial_model(
|
|
108
|
+
self._validate_partial_model(
|
|
109
|
+
entity_model, base_model_candidate, entity_models
|
|
110
|
+
)
|
|
121
111
|
partial_metadata = self._build_partial_metadata(
|
|
122
112
|
entity_model, base_model_candidate
|
|
123
113
|
)
|
{nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/primitives.py
RENAMED
|
@@ -48,6 +48,14 @@ MAPPING_PRIMITIVE_TYPES_TO_PYTHON = {
|
|
|
48
48
|
BasicTypes = int | bool | float | str
|
|
49
49
|
DefaultTypes = BasicTypes | List[BasicTypes]
|
|
50
50
|
|
|
51
|
+
STR_BASED_TYPES = {
|
|
52
|
+
PrimitiveTypes.STRING,
|
|
53
|
+
PrimitiveTypes.EMAIL,
|
|
54
|
+
PrimitiveTypes.CPF,
|
|
55
|
+
PrimitiveTypes.CNPJ,
|
|
56
|
+
PrimitiveTypes.CPF_CNPJ,
|
|
57
|
+
}
|
|
58
|
+
|
|
51
59
|
|
|
52
60
|
class CardinalityTypes(enum.Enum):
|
|
53
61
|
C1_1 = "1_1"
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import ast
|
|
2
|
+
import datetime
|
|
2
3
|
import re
|
|
4
|
+
import uuid
|
|
3
5
|
|
|
4
6
|
from nsj_rest_lib2.compiler.compiler_structures import (
|
|
5
7
|
IndexCompilerStructure,
|
|
@@ -13,6 +15,7 @@ from nsj_rest_lib2.compiler.edl_model.primitives import (
|
|
|
13
15
|
PrimitiveTypes,
|
|
14
16
|
REGEX_EXTERNAL_REF,
|
|
15
17
|
REGEX_INTERNAL_REF,
|
|
18
|
+
STR_BASED_TYPES,
|
|
16
19
|
)
|
|
17
20
|
from nsj_rest_lib2.compiler.edl_model.property_meta_model import PropertyMetaModel
|
|
18
21
|
from nsj_rest_lib2.compiler.edl_model.trait_property_meta_model import (
|
|
@@ -27,10 +30,6 @@ from nsj_rest_lib2.compiler.util.type_naming_util import (
|
|
|
27
30
|
)
|
|
28
31
|
from nsj_rest_lib2.compiler.util.type_util import TypeUtil
|
|
29
32
|
|
|
30
|
-
# TODO pattern
|
|
31
|
-
# TODO lowercase
|
|
32
|
-
# TODO uppercase
|
|
33
|
-
|
|
34
33
|
|
|
35
34
|
class EDLPropertyCompiler:
|
|
36
35
|
|
|
@@ -51,9 +50,6 @@ class EDLPropertyCompiler:
|
|
|
51
50
|
list[RelationDependency],
|
|
52
51
|
list[tuple[str, BasicTypes]],
|
|
53
52
|
]:
|
|
54
|
-
|
|
55
|
-
# TODO Criar opção de campo calculado?
|
|
56
|
-
|
|
57
53
|
# Descobrindo os atributos marcados como PK (e recuperando a chave primária)
|
|
58
54
|
# TODO Verificar se devemos manter essa verificação
|
|
59
55
|
pk_keys = []
|
|
@@ -64,8 +60,8 @@ class EDLPropertyCompiler:
|
|
|
64
60
|
if prop.pk:
|
|
65
61
|
pk_keys.append(pkey)
|
|
66
62
|
|
|
67
|
-
is_partial_extension = (
|
|
68
|
-
|
|
63
|
+
is_partial_extension = isinstance(entity_model, EntityModel) and bool(
|
|
64
|
+
entity_model.partial_of
|
|
69
65
|
)
|
|
70
66
|
|
|
71
67
|
if not entity_model.mixin:
|
|
@@ -944,16 +940,6 @@ class EDLPropertyCompiler:
|
|
|
944
940
|
)
|
|
945
941
|
)
|
|
946
942
|
|
|
947
|
-
if (
|
|
948
|
-
prop.default
|
|
949
|
-
): # TODO Verificar esse modo de tratar valores default (principalmente expressões)
|
|
950
|
-
keywords.append(
|
|
951
|
-
ast.keyword(
|
|
952
|
-
arg="default_value",
|
|
953
|
-
value=ast.Name(str(prop.default), ctx=ast.Load()),
|
|
954
|
-
)
|
|
955
|
-
)
|
|
956
|
-
|
|
957
943
|
if prop.trim:
|
|
958
944
|
keywords.append(ast.keyword(arg="strip", value=ast.Constant(True)))
|
|
959
945
|
|
|
@@ -1086,6 +1072,15 @@ class EDLPropertyCompiler:
|
|
|
1086
1072
|
enum_class_name, ast_enum_class = result
|
|
1087
1073
|
aux_classes.append(ast_enum_class)
|
|
1088
1074
|
|
|
1075
|
+
default_value_ast = self._build_default_value_ast(pkey, prop, enum_class_name)
|
|
1076
|
+
if default_value_ast is not None:
|
|
1077
|
+
keywords.append(
|
|
1078
|
+
ast.keyword(
|
|
1079
|
+
arg="default_value",
|
|
1080
|
+
value=default_value_ast,
|
|
1081
|
+
)
|
|
1082
|
+
)
|
|
1083
|
+
|
|
1089
1084
|
# Resolvendo o nome da propriedade no Entity
|
|
1090
1085
|
if (
|
|
1091
1086
|
properties_structure.entity_properties
|
|
@@ -1118,6 +1113,258 @@ class EDLPropertyCompiler:
|
|
|
1118
1113
|
|
|
1119
1114
|
ast_entity_attributes.append(ast_entity_attr)
|
|
1120
1115
|
|
|
1116
|
+
def _build_default_value_ast(
|
|
1117
|
+
self,
|
|
1118
|
+
pkey: str,
|
|
1119
|
+
prop: PropertyMetaModel,
|
|
1120
|
+
enum_class_name: str | None,
|
|
1121
|
+
) -> ast.expr | None:
|
|
1122
|
+
default_value = prop.default
|
|
1123
|
+
if default_value is None:
|
|
1124
|
+
return None
|
|
1125
|
+
|
|
1126
|
+
if prop.domain_config and enum_class_name:
|
|
1127
|
+
return self._build_enum_default_value_ast(
|
|
1128
|
+
pkey, prop, enum_class_name, default_value
|
|
1129
|
+
)
|
|
1130
|
+
|
|
1131
|
+
if not isinstance(prop.type, PrimitiveTypes):
|
|
1132
|
+
raise ValueError(
|
|
1133
|
+
f"Propriedade '{pkey}' não suporta valor default para relacionamentos."
|
|
1134
|
+
)
|
|
1135
|
+
|
|
1136
|
+
return self._build_primitive_default_value_ast(pkey, prop, default_value)
|
|
1137
|
+
|
|
1138
|
+
def _build_enum_default_value_ast(
|
|
1139
|
+
self,
|
|
1140
|
+
pkey: str,
|
|
1141
|
+
prop: PropertyMetaModel,
|
|
1142
|
+
enum_class_name: str,
|
|
1143
|
+
default_value: object,
|
|
1144
|
+
) -> ast.expr:
|
|
1145
|
+
target_option = None
|
|
1146
|
+
for option in prop.domain_config or []:
|
|
1147
|
+
if option.value == default_value:
|
|
1148
|
+
target_option = option
|
|
1149
|
+
break
|
|
1150
|
+
|
|
1151
|
+
if option.mapped_value is not None and option.mapped_value == default_value:
|
|
1152
|
+
target_option = option
|
|
1153
|
+
break
|
|
1154
|
+
|
|
1155
|
+
if not target_option:
|
|
1156
|
+
raise ValueError(
|
|
1157
|
+
f"Propriedade '{pkey}' possui valor default '{default_value}' que não corresponde a nenhuma opção do enum."
|
|
1158
|
+
)
|
|
1159
|
+
|
|
1160
|
+
enum_member_name = CompilerStrUtil.to_enum_member_name(target_option.value)
|
|
1161
|
+
|
|
1162
|
+
return ast.Attribute(
|
|
1163
|
+
value=ast.Name(id=enum_class_name, ctx=ast.Load()),
|
|
1164
|
+
attr=enum_member_name,
|
|
1165
|
+
ctx=ast.Load(),
|
|
1166
|
+
)
|
|
1167
|
+
|
|
1168
|
+
def _build_primitive_default_value_ast(
|
|
1169
|
+
self,
|
|
1170
|
+
pkey: str,
|
|
1171
|
+
prop: PropertyMetaModel,
|
|
1172
|
+
default_value: object,
|
|
1173
|
+
) -> ast.expr:
|
|
1174
|
+
primitive_type = prop.type
|
|
1175
|
+
|
|
1176
|
+
if isinstance(default_value, str):
|
|
1177
|
+
expression_ast = self._build_python_expression_from_string(default_value)
|
|
1178
|
+
if expression_ast is not None:
|
|
1179
|
+
return expression_ast
|
|
1180
|
+
|
|
1181
|
+
if primitive_type in STR_BASED_TYPES:
|
|
1182
|
+
if not isinstance(default_value, str):
|
|
1183
|
+
raise ValueError(
|
|
1184
|
+
f"Propriedade '{pkey}' exige valor default textual, recebido '{default_value}'."
|
|
1185
|
+
)
|
|
1186
|
+
return ast.Constant(value=default_value)
|
|
1187
|
+
|
|
1188
|
+
if primitive_type == PrimitiveTypes.BOOLEAN:
|
|
1189
|
+
if isinstance(default_value, bool):
|
|
1190
|
+
return ast.Constant(value=default_value)
|
|
1191
|
+
raise ValueError(
|
|
1192
|
+
f"Propriedade '{pkey}' exige valor default booleano, recebido '{default_value}'."
|
|
1193
|
+
)
|
|
1194
|
+
|
|
1195
|
+
if primitive_type == PrimitiveTypes.INTEGER:
|
|
1196
|
+
return self._build_numeric_constant_default_ast(
|
|
1197
|
+
pkey,
|
|
1198
|
+
default_value,
|
|
1199
|
+
int,
|
|
1200
|
+
"inteiro",
|
|
1201
|
+
forbid_fraction=True,
|
|
1202
|
+
)
|
|
1203
|
+
|
|
1204
|
+
if primitive_type in (
|
|
1205
|
+
PrimitiveTypes.NUMBER,
|
|
1206
|
+
PrimitiveTypes.CURRENCY,
|
|
1207
|
+
PrimitiveTypes.QUANTITY,
|
|
1208
|
+
):
|
|
1209
|
+
return self._build_numeric_constant_default_ast(
|
|
1210
|
+
pkey,
|
|
1211
|
+
default_value,
|
|
1212
|
+
float,
|
|
1213
|
+
"numérico",
|
|
1214
|
+
)
|
|
1215
|
+
|
|
1216
|
+
if primitive_type == PrimitiveTypes.UUID:
|
|
1217
|
+
return self._build_uuid_default_ast(pkey, default_value)
|
|
1218
|
+
|
|
1219
|
+
if primitive_type == PrimitiveTypes.DATE:
|
|
1220
|
+
return self._build_iso_datetime_default_ast(
|
|
1221
|
+
pkey,
|
|
1222
|
+
default_value,
|
|
1223
|
+
target="date",
|
|
1224
|
+
)
|
|
1225
|
+
|
|
1226
|
+
if primitive_type == PrimitiveTypes.DATETIME:
|
|
1227
|
+
return self._build_iso_datetime_default_ast(
|
|
1228
|
+
pkey,
|
|
1229
|
+
default_value,
|
|
1230
|
+
target="datetime",
|
|
1231
|
+
)
|
|
1232
|
+
|
|
1233
|
+
raise ValueError(
|
|
1234
|
+
f"Propriedade '{pkey}' não suporta valor default para o tipo '{primitive_type.value}'."
|
|
1235
|
+
)
|
|
1236
|
+
|
|
1237
|
+
def _build_numeric_constant_default_ast(
|
|
1238
|
+
self,
|
|
1239
|
+
pkey: str,
|
|
1240
|
+
default_value: object,
|
|
1241
|
+
cast_type: type,
|
|
1242
|
+
type_label: str,
|
|
1243
|
+
*,
|
|
1244
|
+
forbid_fraction: bool = False,
|
|
1245
|
+
) -> ast.expr:
|
|
1246
|
+
if isinstance(default_value, bool):
|
|
1247
|
+
raise ValueError(
|
|
1248
|
+
f"Propriedade '{pkey}' exige valor default {type_label}, recebido '{default_value}'."
|
|
1249
|
+
)
|
|
1250
|
+
|
|
1251
|
+
value_to_convert = (
|
|
1252
|
+
default_value.strip()
|
|
1253
|
+
if isinstance(default_value, str)
|
|
1254
|
+
else default_value
|
|
1255
|
+
)
|
|
1256
|
+
|
|
1257
|
+
if forbid_fraction and isinstance(value_to_convert, float):
|
|
1258
|
+
if not value_to_convert.is_integer():
|
|
1259
|
+
raise ValueError(
|
|
1260
|
+
f"Propriedade '{pkey}' exige valor default inteiro, recebido '{default_value}'."
|
|
1261
|
+
)
|
|
1262
|
+
|
|
1263
|
+
try:
|
|
1264
|
+
converted_value = cast_type(value_to_convert)
|
|
1265
|
+
except (TypeError, ValueError) as exc:
|
|
1266
|
+
raise ValueError(
|
|
1267
|
+
f"Propriedade '{pkey}' exige valor default {type_label}, recebido '{default_value}'."
|
|
1268
|
+
) from exc
|
|
1269
|
+
|
|
1270
|
+
if forbid_fraction and isinstance(value_to_convert, float):
|
|
1271
|
+
converted_value = int(converted_value)
|
|
1272
|
+
|
|
1273
|
+
return ast.Constant(value=converted_value)
|
|
1274
|
+
|
|
1275
|
+
def _build_uuid_default_ast(
|
|
1276
|
+
self,
|
|
1277
|
+
pkey: str,
|
|
1278
|
+
default_value: object,
|
|
1279
|
+
) -> ast.expr:
|
|
1280
|
+
if isinstance(default_value, uuid.UUID):
|
|
1281
|
+
uuid_value = str(default_value)
|
|
1282
|
+
elif isinstance(default_value, str):
|
|
1283
|
+
try:
|
|
1284
|
+
uuid_value = str(uuid.UUID(default_value))
|
|
1285
|
+
except ValueError as exc:
|
|
1286
|
+
raise ValueError(
|
|
1287
|
+
f"Propriedade '{pkey}' exige UUID válido ou expressão Python, recebido '{default_value}'."
|
|
1288
|
+
) from exc
|
|
1289
|
+
else:
|
|
1290
|
+
raise ValueError(
|
|
1291
|
+
f"Propriedade '{pkey}' exige UUID válido ou expressão Python, recebido '{default_value}'."
|
|
1292
|
+
)
|
|
1293
|
+
|
|
1294
|
+
return ast.Call(
|
|
1295
|
+
func=ast.Attribute(
|
|
1296
|
+
value=ast.Name(id="uuid", ctx=ast.Load()),
|
|
1297
|
+
attr="UUID",
|
|
1298
|
+
ctx=ast.Load(),
|
|
1299
|
+
),
|
|
1300
|
+
args=[ast.Constant(value=uuid_value)],
|
|
1301
|
+
keywords=[],
|
|
1302
|
+
)
|
|
1303
|
+
|
|
1304
|
+
def _build_iso_datetime_default_ast(
|
|
1305
|
+
self,
|
|
1306
|
+
pkey: str,
|
|
1307
|
+
default_value: object,
|
|
1308
|
+
*,
|
|
1309
|
+
target: str,
|
|
1310
|
+
) -> ast.expr:
|
|
1311
|
+
if target == "date":
|
|
1312
|
+
parser = datetime.date
|
|
1313
|
+
else:
|
|
1314
|
+
parser = datetime.datetime
|
|
1315
|
+
|
|
1316
|
+
if isinstance(default_value, parser):
|
|
1317
|
+
iso_value = default_value.isoformat()
|
|
1318
|
+
elif isinstance(default_value, str):
|
|
1319
|
+
iso_value = default_value.strip()
|
|
1320
|
+
else:
|
|
1321
|
+
raise ValueError(
|
|
1322
|
+
f"Propriedade '{pkey}' exige {target} em formato ISO ou expressão Python, recebido '{default_value}'."
|
|
1323
|
+
)
|
|
1324
|
+
|
|
1325
|
+
try:
|
|
1326
|
+
parser.fromisoformat(iso_value)
|
|
1327
|
+
except ValueError as exc:
|
|
1328
|
+
raise ValueError(
|
|
1329
|
+
f"Propriedade '{pkey}' exige {target} em formato ISO ou expressão Python, recebido '{default_value}'."
|
|
1330
|
+
) from exc
|
|
1331
|
+
|
|
1332
|
+
return ast.Call(
|
|
1333
|
+
func=ast.Attribute(
|
|
1334
|
+
value=ast.Attribute(
|
|
1335
|
+
value=ast.Name(id="datetime", ctx=ast.Load()),
|
|
1336
|
+
attr=target,
|
|
1337
|
+
ctx=ast.Load(),
|
|
1338
|
+
),
|
|
1339
|
+
attr="fromisoformat",
|
|
1340
|
+
ctx=ast.Load(),
|
|
1341
|
+
),
|
|
1342
|
+
args=[ast.Constant(value=iso_value)],
|
|
1343
|
+
keywords=[],
|
|
1344
|
+
)
|
|
1345
|
+
|
|
1346
|
+
def _build_python_expression_from_string(self, expression: str) -> ast.expr | None:
|
|
1347
|
+
try:
|
|
1348
|
+
parsed_expr = ast.parse(expression, mode="eval").body
|
|
1349
|
+
except SyntaxError:
|
|
1350
|
+
return None
|
|
1351
|
+
|
|
1352
|
+
if self._is_safe_python_expression(parsed_expr):
|
|
1353
|
+
return parsed_expr
|
|
1354
|
+
|
|
1355
|
+
return None
|
|
1356
|
+
|
|
1357
|
+
def _is_safe_python_expression(self, node: ast.AST) -> bool:
|
|
1358
|
+
if isinstance(node, ast.Name):
|
|
1359
|
+
return True
|
|
1360
|
+
if isinstance(node, ast.Attribute):
|
|
1361
|
+
return self._is_safe_python_expression(node.value)
|
|
1362
|
+
if isinstance(node, ast.Call):
|
|
1363
|
+
if node.keywords or node.args:
|
|
1364
|
+
return False
|
|
1365
|
+
return self._is_safe_python_expression(node.func)
|
|
1366
|
+
return False
|
|
1367
|
+
|
|
1121
1368
|
def _compile_domain_config(
|
|
1122
1369
|
self,
|
|
1123
1370
|
pkey: str,
|
|
@@ -1139,7 +1386,7 @@ class EDLPropertyCompiler:
|
|
|
1139
1386
|
# Compilando as opções do enum
|
|
1140
1387
|
ast_values = []
|
|
1141
1388
|
for value in prop.domain_config:
|
|
1142
|
-
value_name = CompilerStrUtil.
|
|
1389
|
+
value_name = CompilerStrUtil.to_enum_member_name(value.value)
|
|
1143
1390
|
|
|
1144
1391
|
if use_mapped_value and value.mapped_value is None:
|
|
1145
1392
|
raise Exception(
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
class CompilerStrUtil:
|
|
2
5
|
@staticmethod
|
|
3
6
|
def to_camel_case(snake_str: str) -> str:
|
|
@@ -20,3 +23,10 @@ class CompilerStrUtil:
|
|
|
20
23
|
snake_str += "_"
|
|
21
24
|
snake_str += char.lower()
|
|
22
25
|
return snake_str
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def to_enum_member_name(raw_value: str) -> str:
|
|
29
|
+
"""Converte um valor livre para o nome de membro enum padronizado."""
|
|
30
|
+
sanitized = re.sub(r"[^0-9A-Za-z]+", "_", raw_value.strip())
|
|
31
|
+
sanitized = sanitized.strip("_")
|
|
32
|
+
return CompilerStrUtil.to_snake_case(sanitized).upper()
|
|
@@ -15,7 +15,6 @@ from nsj_rest_lib2.redis_config import get_redis
|
|
|
15
15
|
from nsj_rest_lib2.settings import ESCOPO_RESTLIB2, MIN_TIME_SOURCE_REFRESH
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
# TODO Verificar se está atualizando o loaded_at, quando o hash não muda
|
|
19
18
|
class LoadedEntity:
|
|
20
19
|
def __init__(self):
|
|
21
20
|
self.dto_class_name: str = ""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nsj_rest_lib2
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.22
|
|
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
|
|
@@ -25,16 +25,3 @@ Biblioteca para permitir a distribuição de rotas dinâmicas numa API, configur
|
|
|
25
25
|
|
|
26
26
|
[ESPECIFICAÇÃO DO MODELO DE ENTIDADES](docs/especificacao.md)
|
|
27
27
|
|
|
28
|
-
## TODO
|
|
29
|
-
* Valores default
|
|
30
|
-
* Usar trait_properties como valor default
|
|
31
|
-
* Não está carregando a lista de dependências de execução, para os components
|
|
32
|
-
* Implementar gravação de entidades com extensão parcial
|
|
33
|
-
* Unificar o arquivo redis_config.py
|
|
34
|
-
* Usar pydantic, ou similar, para transformar a configuração das entidades, no redis, num objeto
|
|
35
|
-
* Rever modo de usar o InjectFactory (talvez dando ciência, ao RestLib, do padrão multibanco)
|
|
36
|
-
* Implementar e documentar campos join
|
|
37
|
-
* Implementar e documentar conjuntos
|
|
38
|
-
* Dar erro ao haver conflito de nomes das propriedades (por qualquer tipo de herança)
|
|
39
|
-
* Rotas para o inline
|
|
40
|
-
* inline será para composição (arquivo externo é agregação)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[metadata]
|
|
2
2
|
name = nsj_rest_lib2
|
|
3
|
-
version = 0.0.
|
|
3
|
+
version = 0.0.22
|
|
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).
|
nsj_rest_lib2-0.0.21/README.md
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# nsj_rest_lib2
|
|
2
|
-
|
|
3
|
-
Biblioteca para permitir a distribuição de rotas dinâmicas numa API, configuradas por meio de EDLs declarativos (em formato JSON).
|
|
4
|
-
|
|
5
|
-
[ESPECIFICAÇÃO DO MODELO DE ENTIDADES](docs/especificacao.md)
|
|
6
|
-
|
|
7
|
-
## TODO
|
|
8
|
-
* Valores default
|
|
9
|
-
* Usar trait_properties como valor default
|
|
10
|
-
* Não está carregando a lista de dependências de execução, para os components
|
|
11
|
-
* Implementar gravação de entidades com extensão parcial
|
|
12
|
-
* Unificar o arquivo redis_config.py
|
|
13
|
-
* Usar pydantic, ou similar, para transformar a configuração das entidades, no redis, num objeto
|
|
14
|
-
* Rever modo de usar o InjectFactory (talvez dando ciência, ao RestLib, do padrão multibanco)
|
|
15
|
-
* Implementar e documentar campos join
|
|
16
|
-
* Implementar e documentar conjuntos
|
|
17
|
-
* Dar erro ao haver conflito de nomes das propriedades (por qualquer tipo de herança)
|
|
18
|
-
* Rotas para o inline
|
|
19
|
-
* inline será para composição (arquivo externo é agregação)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/ai_entity_edl.py
RENAMED
|
File without changes
|
|
File without changes
|
{nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/column_meta_model.py
RENAMED
|
File without changes
|
{nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/entity_model.py
RENAMED
|
File without changes
|
{nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/entity_model_base.py
RENAMED
|
File without changes
|
{nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/entity_model_root.py
RENAMED
|
File without changes
|
{nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/index_model.py
RENAMED
|
File without changes
|
{nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/edl_model/repository_model.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/compiler/util/type_naming_util.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nsj_rest_lib2-0.0.21 → nsj_rest_lib2-0.0.22}/nsj_rest_lib2/controller/dynamic_controller.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|