@oondemand/oon-core-back 0.3.32 → 0.3.34

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.
package/README.md CHANGED
@@ -20,3 +20,22 @@ Compatibilidade temporária: `CENTRAL_ATIVACAO_BACKEND_URL` e `MEUS_APPS_BACKEND
20
20
  `GET /ativacao/status` informa estado sem segredos. `POST /ativacao/validar-codigo` valida sem consumir. `POST /ativacao/concluir` revalida, chama `/ativar`, criptografa imediatamente o token da instância, executa hooks declarativos, chama `/concluir` e marca a instância como `ativa`. `POST /ativacao/tentar-novamente` retoma uma ativação já registrada sem exigir novo código.
21
21
 
22
22
  Campos adicionais podem ser declarados em `activation.fields`; `password` e `secret` são sanitizados na configuração retornada ao frontend. Hooks opcionais: `validate`, `beforeComplete`, `afterComplete`.
23
+
24
+ ## Rótulos de campos relacionados
25
+
26
+ Por padrão, campos declarados com `fields.ref(...)` continuam sendo devolvidos pelo CRUD como `ObjectId`. Uma model pode optar pela população segura das referências usadas em grids e cards:
27
+
28
+ ```js
29
+ defineModel({
30
+ name: "Pedido",
31
+ schema: {
32
+ clienteId: fields.ref("Cliente", { required: true, label: "Cliente" }),
33
+ },
34
+ crud: {
35
+ enabled: true,
36
+ populateRefs: ["clienteId"],
37
+ },
38
+ });
39
+ ```
40
+
41
+ Use `populateRefs: true` para todas as referências da model ou informe uma lista explícita. O CRUD devolve somente `_id` e campos usuais de identificação, como nome, razão social, descrição, código, e-mail e campos pesquisáveis da model referenciada. Exportações mantêm os identificadores originais.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oondemand/oon-core-back",
3
- "version": "0.3.32",
3
+ "version": "0.3.34",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/oondemand/oon-platform.git",
@@ -1,4 +1,71 @@
1
1
  const GenericError = require("../errors/GenericError");
2
+ const registry = require("../registry");
3
+
4
+ const COMMON_REFERENCE_LABEL_FIELDS = [
5
+ "nome",
6
+ "razaoSocial",
7
+ "razao_social",
8
+ "descricao",
9
+ "numero",
10
+ "codigoIndividual",
11
+ "codigo_individual",
12
+ "codigo",
13
+ "label",
14
+ "email",
15
+ "sigla",
16
+ ];
17
+
18
+ /**
19
+ * Gera especificações de populate somente quando a model opta explicitamente
20
+ * por `crud.populateRefs`. O select é restrito a campos de identificação para
21
+ * evitar devolver o documento relacionado inteiro nas listagens genéricas.
22
+ */
23
+ function referencePopulateSpecs(entry) {
24
+ const setting = entry.definition?.crud?.populateRefs;
25
+ if (!setting) return [];
26
+
27
+ const allowed = Array.isArray(setting) ? new Set(setting) : null;
28
+ const metaFields = Object.values(entry.metaFields || {});
29
+
30
+ return metaFields
31
+ .filter((field) =>
32
+ field?.kind === "ref" &&
33
+ field.ref &&
34
+ (!allowed || allowed.has(field.name))
35
+ )
36
+ .map((field) => {
37
+ const referencedEntry = registry.getModel(field.ref);
38
+ const select = [
39
+ "_id",
40
+ ...COMMON_REFERENCE_LABEL_FIELDS,
41
+ ...(referencedEntry?.searchableFields || []),
42
+ ];
43
+
44
+ return {
45
+ path: field.name,
46
+ select: [...new Set(select)].join(" "),
47
+ };
48
+ });
49
+ }
50
+
51
+ function populateQuery(query, specs) {
52
+ return specs.length ? query.populate(specs) : query;
53
+ }
54
+
55
+ /**
56
+ * Aceita tanto uma Query Mongoose quanto uma Promise/Document devolvida por
57
+ * uma model que sobrescreveu métodos como `findByIdAndUpdate`.
58
+ */
59
+ async function resolvePopulated(result, specs) {
60
+ if (!specs.length) return result;
61
+ if (result && typeof result.populate === "function") {
62
+ return result.populate(specs);
63
+ }
64
+
65
+ const doc = await result;
66
+ if (doc && typeof doc.populate === "function") await doc.populate(specs);
67
+ return doc;
68
+ }
2
69
 
3
70
  /**
4
71
  * Gera um service de CRUD genérico para uma model registrada.
@@ -6,6 +73,7 @@ const GenericError = require("../errors/GenericError");
6
73
  */
7
74
  function createCrudService(entry) {
8
75
  const { mongooseModel: Model, searchableFields } = entry;
76
+ const populateSpecs = referencePopulateSpecs(entry);
9
77
 
10
78
  async function listPaginated({ pageIndex = 0, pageSize = 20, searchTerm, sort, filtros = {} } = {}) {
11
79
  const page = Math.max(0, Number(pageIndex) || 0);
@@ -18,8 +86,12 @@ function createCrudService(entry) {
18
86
  }
19
87
 
20
88
  const sortSpec = parseSort(sort);
89
+ const listQuery = populateQuery(
90
+ Model.find(query).sort(sortSpec).skip(page * limit).limit(limit),
91
+ populateSpecs
92
+ );
21
93
  const [results, totalItems] = await Promise.all([
22
- Model.find(query).sort(sortSpec).skip(page * limit).limit(limit).lean(),
94
+ listQuery.lean(),
23
95
  Model.countDocuments(query),
24
96
  ]);
25
97
 
@@ -35,20 +107,24 @@ function createCrudService(entry) {
35
107
  }
36
108
 
37
109
  async function getById(id) {
38
- const doc = await Model.findById(id);
110
+ const doc = await resolvePopulated(Model.findById(id), populateSpecs);
39
111
  if (!doc) throw new GenericError("Registro não encontrado.", { statusCode: 404 });
40
112
  return doc;
41
113
  }
42
114
 
43
115
  async function create(data) {
44
- return Model.create(data);
116
+ const doc = await Model.create(data);
117
+ return resolvePopulated(doc, populateSpecs);
45
118
  }
46
119
 
47
120
  async function update(id, data) {
48
- const doc = await Model.findByIdAndUpdate(id, data, {
49
- new: true,
50
- runValidators: true,
51
- });
121
+ const doc = await resolvePopulated(
122
+ Model.findByIdAndUpdate(id, data, {
123
+ new: true,
124
+ runValidators: true,
125
+ }),
126
+ populateSpecs
127
+ );
52
128
  if (!doc) throw new GenericError("Registro não encontrado.", { statusCode: 404 });
53
129
  return doc;
54
130
  }
@@ -93,4 +169,4 @@ function escapeRegex(str) {
93
169
  return String(str).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
94
170
  }
95
171
 
96
- module.exports = { createCrudService };
172
+ module.exports = { createCrudService, referencePopulateSpecs, resolvePopulated };