pwi-plata-type 0.1.0 → 0.1.3

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,4 +1,5 @@
1
1
  import { tools } from "./plata-create-tools.js";
2
+ import { PlataDirs } from "../../libs/tools.js"
2
3
  import * as path from 'node:path'
3
4
 
4
5
  export async function h() {
@@ -50,6 +51,17 @@ export async function h() {
50
51
  )))
51
52
 
52
53
  break;
54
+ case 'model':
55
+ const modelName = args.shift()
56
+ const plataName = PlataDirs.ProjectJson.plata_name
57
+
58
+ promises.push(tools.files.deployFileToProject(
59
+ 'models',
60
+ 'model',
61
+ `${modelName.toLowerCase()}.ts`,
62
+ { Name: `${modelName}`, PlataName: `${plataName}` }
63
+ ).finally(() => console.log(`Model ${modelName} criada`)))
64
+ break;
53
65
  }
54
66
 
55
67
  await Promise.all(promises)
package/index.ts CHANGED
@@ -2,10 +2,12 @@ import * as PlataCluster from './libs/cluster.js'
2
2
  import * as PlataEnv from './libs/env.js'
3
3
  import * as PlataRoutes from './libs/routes.js'
4
4
  import * as PlataTools from './libs/tools.js'
5
+ import * as PlataModels from './libs/model.js'
5
6
 
6
7
  export {
7
8
  PlataCluster,
8
9
  PlataEnv,
9
10
  PlataRoutes,
10
11
  PlataTools,
12
+ PlataModels,
11
13
  }
package/libs/model.ts ADDED
@@ -0,0 +1,474 @@
1
+ export interface ErroValidacao {
2
+ errorID: string
3
+ error?: any
4
+ msg: string
5
+ }
6
+
7
+ export interface RetornoValidacaoPrimitivo {
8
+ error?: ErroValidacao
9
+ continua: boolean
10
+ }
11
+
12
+ export interface RetornoValicadaoModel {
13
+ value: any,
14
+ errors: ErroValidacao[]
15
+ }
16
+
17
+ export type ModelValicacao = (value: any) => Promise<ErroValidacao | null>
18
+
19
+ export type ModelValicacaoPrimitivo = (nome: string, valor: any) => Promise<RetornoValidacaoPrimitivo>
20
+
21
+ export interface ModelType {
22
+ [name: string]: ModelValicacaoPrimitivo[] | ModelType[] | ModelType
23
+ }
24
+
25
+ export class Model {
26
+ public readonly template: ModelType
27
+ public readonly validacoes: Map<string, ModelValicacao>
28
+
29
+ constructor(template: ModelType) {
30
+ this.template = template
31
+ this.validacoes = new Map()
32
+ }
33
+
34
+ public addValidacao(nome: string, callback: ModelValicacao) {
35
+ this.validacoes.set(nome, callback)
36
+ }
37
+ }
38
+
39
+ export async function _validaCampo(value: any, pipeline: ModelValicacaoPrimitivo[], name: string): Promise<ErroValidacao | null> {
40
+ for (let i = 0; i < pipeline.length; i++) {
41
+ const result = await pipeline[i](name, value)
42
+
43
+ if (result.error !== undefined) {
44
+ return result.error
45
+ }
46
+
47
+ if (!result.continua) {
48
+ break
49
+ }
50
+ }
51
+
52
+ return null
53
+ }
54
+
55
+ export function _filtraModel(value: any, model: Model): any {
56
+ for (const campo in model.template) {
57
+ const t = model.template[campo]
58
+
59
+ if (t.length === undefined) {
60
+ if (value[campo] === undefined) {
61
+ value[campo] = {}
62
+ }
63
+
64
+ const m = new Model(t as ModelType)
65
+ value[campo] = _filtraModel(value[campo], m)
66
+ continue
67
+ }
68
+
69
+ if (typeof t[0] === 'function') {
70
+ if (value[campo] === undefined) {
71
+ value[campo] = null
72
+ }
73
+
74
+ continue
75
+ }
76
+
77
+ if (value[campo] === undefined) {
78
+ value[campo] = []
79
+
80
+ continue
81
+ }
82
+
83
+ const m = new Model(t[0] as ModelType)
84
+
85
+ for (let i = 0; i < value[campo].length; i++) {
86
+ value[campo][i] = _filtraModel(value[campo][i], m)
87
+ }
88
+ }
89
+
90
+ return value
91
+ }
92
+
93
+ export async function _validaModel(value: any, model: Model, name?: string): Promise<ErroValidacao[]> {
94
+ let promises: any[] = []
95
+ let errors: ErroValidacao[] = []
96
+
97
+ for(const campo in model.template) {
98
+ const t = model.template[campo]
99
+
100
+ if (t.length === undefined) {
101
+ const m = new Model(t as ModelType)
102
+
103
+ promises.push(_validaModel(value[campo], m, `${campo}.`))
104
+ continue
105
+ }
106
+
107
+ if (typeof t[0] === 'function') {
108
+ promises.push(
109
+ _validaCampo(
110
+ value[campo],
111
+ t as ModelValicacaoPrimitivo[],
112
+ `${name ?? ''}${campo}`
113
+ )
114
+ )
115
+ continue
116
+ }
117
+
118
+ const m = new Model(t[0])
119
+
120
+ for (let i = 0; i < value[campo].length; i++) {
121
+ promises.push(
122
+ _validaModel(
123
+ value[campo][i],
124
+ m,
125
+ `${name ?? ''}${campo}[${i}].`
126
+ )
127
+ )
128
+ }
129
+ }
130
+
131
+ let Erros = await Promise.all(promises).then(
132
+ result => [].concat(...result).filter(v => v !== null),
133
+ err => {
134
+ return {
135
+ errorID: 'BPLM0002',
136
+ error: err,
137
+ msg: 'Erro ao validar o body',
138
+ }
139
+ }
140
+ )
141
+
142
+ if ((Erros as any).errorID !== undefined) {
143
+ errors.push(Erros as ErroValidacao)
144
+
145
+ return errors
146
+ }
147
+
148
+ errors = errors.concat(Erros)
149
+
150
+ if (errors.length !== 0) {
151
+ return errors
152
+ }
153
+
154
+ promises = []
155
+
156
+ for (const [ _, callback ] of model.validacoes) {
157
+ promises.push(callback(value))
158
+ }
159
+
160
+ Erros = await Promise.all(promises).then(
161
+ result => [].concat(...result),
162
+ err => {
163
+ return {
164
+ errorID: 'BPLM0003',
165
+ error: err,
166
+ msg: 'Erro ao validar o body',
167
+ }
168
+ }
169
+ )
170
+
171
+ if ((Erros as any).errorID !== undefined) {
172
+ errors.push(Erros as ErroValidacao)
173
+
174
+ return errors
175
+ }
176
+
177
+ return errors.concat(Erros)
178
+ }
179
+
180
+ export async function valida(value: any, model: Model): Promise<RetornoValicadaoModel> {
181
+ value = _filtraModel(value, model)
182
+
183
+ return {
184
+ value,
185
+ errors: await _validaModel(value, model),
186
+ }
187
+ }
188
+
189
+ export function DateTime(): ModelValicacaoPrimitivo {
190
+ return async (nome: string, valor: any) => {
191
+ const regex = /(\d{4})-([01]\d)-([0-3]\d)T([0-2]\d):([0-5]\d):([0-5]\d)/
192
+
193
+ if (!regex.test(valor)) {
194
+ return {
195
+ error: {
196
+ errorID: "BPMVDT001",
197
+ msg: `A data no campo ${nome} tem que está no formato yyyy-mm-ddTHH:MM:SS`,
198
+ },
199
+ continua: false
200
+ }
201
+ }
202
+
203
+ const [ _, ano, mes, dia, hora, minutos, segundos ] = valor.match(regex)
204
+
205
+ if (isNaN(+ano) || isNaN(+mes) || isNaN(+dia) || isNaN(+hora) || isNaN(+minutos) || isNaN(+segundos) ){
206
+ return {
207
+ error: {
208
+ errorID: "BPMVDT002",
209
+ msg: `A data no campo ${nome} tem que está no formato yyyy-mm-ddTHH:MM:SS`
210
+ },
211
+ continua: false
212
+ }
213
+ }
214
+
215
+ if ((+dia) > 31 || (+mes) > 12 || (+hora) > 24){
216
+ return {
217
+ error: {
218
+ errorID: "BCVDT003",
219
+ msg: `A data no campo ${nome} tem que está no formato yyyy-mm-ddTHH:MM:SS`,
220
+ },
221
+ continua: false
222
+ }
223
+ }
224
+
225
+ return { continua: true }
226
+ }
227
+ }
228
+
229
+ export function Decimal(tamanhoInteiro: number, casasDecimais: number): ModelValicacaoPrimitivo {
230
+ return async (nome: string, valor: any) => {
231
+ if (isNaN(+valor)) {
232
+ return {
233
+ error: {
234
+ errorID: "BPMVDEC001",
235
+ msg: `O campo ${nome} tem que ser um decimal`
236
+ },
237
+ continua: false,
238
+ }
239
+ }
240
+
241
+ const v = `${valor}`
242
+
243
+ if (v.length > (tamanhoInteiro + casasDecimais + 1)) {
244
+ return {
245
+ error: {
246
+ errorID: "BPMVDEC002",
247
+ msg: `O campo ${nome} não pode ser maior que ${(tamanhoInteiro + casasDecimais + 1)}`
248
+ },
249
+ continua: false,
250
+ }
251
+ }
252
+
253
+ const n = v.split('.')
254
+
255
+ if (n[0].length > tamanhoInteiro) {
256
+ return {
257
+ error: {
258
+ errorID: "BPMVDEC003",
259
+ msg: `A parte inteira do ${nome} não pode ter mais de ${tamanhoInteiro} digitos`
260
+ },
261
+ continua: false,
262
+ }
263
+ }
264
+
265
+ if (n[1] !== undefined) {
266
+ if (n[1].length > casasDecimais) {
267
+ return {
268
+ error: {
269
+ errorID: "BPMVDEC004",
270
+ msg: `A parte decimal do ${nome} não pode ter mais de ${casasDecimais} digitos`
271
+ },
272
+ continua: false,
273
+ }
274
+ }
275
+ }
276
+
277
+ return { continua: true }
278
+ }
279
+ }
280
+
281
+ export function Int(): ModelValicacaoPrimitivo {
282
+ return async (nome: string, valor: any) => {
283
+ if (isNaN(+valor)) {
284
+ return {
285
+ error: {
286
+ errorID: "BPMVINT001",
287
+ msg: `O campo ${nome} tem que ser um número inteiro`
288
+ },
289
+ continua: false,
290
+ }
291
+ }
292
+
293
+ if (Math.round(valor) !== valor) {
294
+ return {
295
+ error: {
296
+ errorID: "BPMVINT002",
297
+ msg: `O campo ${nome} tem que ser um número inteiro`
298
+ },
299
+ continua: false,
300
+ }
301
+ }
302
+
303
+ return { continua: true }
304
+ }
305
+ }
306
+
307
+ export function isArray(tamanhoMaximo?: number): ModelValicacaoPrimitivo {
308
+ return async (nome: string, valor: any) => {
309
+ if (valor === undefined) {
310
+ return {
311
+ error: {
312
+ errorID: "BPCVARR001",
313
+ msg: `O campo ${nome} tem ser um array`
314
+ },
315
+ continua: false
316
+ }
317
+ }
318
+
319
+ if (valor.length === undefined) {
320
+ return {
321
+ error: {
322
+ errorID: "BPCVARR002",
323
+ msg: `O campo ${nome} tem ser um array`
324
+ },
325
+ continua: false
326
+ }
327
+ }
328
+
329
+ if (tamanhoMaximo !== undefined && tamanhoMaximo !== Infinity) {
330
+ if (valor.length > tamanhoMaximo) {
331
+ return {
332
+ error: {
333
+ errorID: "BPCVARR003",
334
+ msg: `O campo ${nome} não pode ter mais de ${tamanhoMaximo} itens`
335
+ },
336
+ continua: false
337
+ }
338
+ }
339
+ }
340
+
341
+ return { continua: true }
342
+ }
343
+ }
344
+
345
+ export function Optional(): ModelValicacaoPrimitivo {
346
+ return async (nome: string, valor: any) => {
347
+ if (!valor) {
348
+ return { continua: false }
349
+ }
350
+
351
+ return { continua: true }
352
+ }
353
+ }
354
+
355
+ export function Required(): ModelValicacaoPrimitivo {
356
+ return async (nome: string, valor: any) => {
357
+ if (valor === undefined) {
358
+ return {
359
+ error: {
360
+ errorID: "BPCVREQ001",
361
+ msg: `O campo ${nome} é obrigatório`
362
+ },
363
+ continua: false
364
+ }
365
+ }
366
+
367
+ return { continua: true }
368
+ }
369
+ }
370
+
371
+ export function SmallDateTime(): ModelValicacaoPrimitivo {
372
+ return async (nome: string, valor: any) => {
373
+ const regex = /(\d{4})-([01]\d)-([0-3]\d)/
374
+
375
+ if (!regex.test(valor)) {
376
+ return {
377
+ error: {
378
+ errorID: "BPCVDT001",
379
+ msg: `A data no campo ${nome} tem que está no formato yyyy-mm-dd`
380
+ },
381
+ continua: false
382
+ }
383
+ }
384
+
385
+ const [ _, ano, mes, dia ] = valor.match(regex)
386
+
387
+ if (isNaN(+ano) || isNaN(+mes) || isNaN(+dia)){
388
+ return {
389
+ error: {
390
+ errorID: "BPCVDT002",
391
+ msg: `A data no campo ${nome} tem que está no formato yyyy-mm-dd`
392
+ },
393
+ continua: false
394
+ }
395
+ }
396
+
397
+ if ((+dia) > 31 || (+mes) > 12 ){
398
+ return {
399
+ error: {
400
+ errorID: "BPCVDT003",
401
+ msg: `A data no campo ${nome} tem que está no formato yyyy-mm-dd`
402
+ },
403
+ continua: false
404
+ }
405
+ }
406
+
407
+ //https://sqltutorialtips.blogspot.com/2016/11/smalldatetime-vs-datetime.html
408
+ if (new Date(+ano, mes - 1, +dia) >= new Date(2079, 11, 31)) {
409
+ return {
410
+ error: {
411
+ errorID: "BPCVDT004",
412
+ msg: `A data no campo ${nome} não pode ser maior que 2079-12-31`
413
+ },
414
+ continua: false
415
+ }
416
+ }
417
+
418
+ return { continua: true }
419
+ }
420
+ }
421
+
422
+ export function Telefone(): ModelValicacaoPrimitivo {
423
+ return async (nome: string, valor: any) => {
424
+ const v = `${valor}`.split('-')
425
+
426
+ if (v.length !== 2) {
427
+ return {
428
+ error: {
429
+ errorID: "BPVTEL001",
430
+ msg: `O campo ${nome} tem que ser um telefone em no formato 99-999999999`
431
+ },
432
+ continua: false
433
+ }
434
+ }
435
+
436
+ if (v[0].length !== 2 || v[1].length > 9) {
437
+ return {
438
+ error: {
439
+ errorID: "BPVTEL002",
440
+ msg: `O campo ${nome} tem que ser um telefone em no formato 99-999999999`
441
+ },
442
+ continua: false
443
+ }
444
+ }
445
+
446
+ if (!+v[0] || !+v[1]) {
447
+ return {
448
+ error: {
449
+ errorID: "BPVTEL003",
450
+ msg: `O campo ${nome} tem que ser um telefone em no formato 99-999999999`
451
+ },
452
+ continua: false
453
+ }
454
+ }
455
+
456
+ return { continua: true }
457
+ }
458
+ }
459
+
460
+ export function VarChar(size: number): ModelValicacaoPrimitivo {
461
+ return async (nome: string, valor: any) => {
462
+ if (valor.length > size) {
463
+ return {
464
+ error: {
465
+ errorID: "BPVVARC001",
466
+ msg: `O campo ${nome} tem que menos de ${nome} caracteres`
467
+ },
468
+ continua: false
469
+ }
470
+ }
471
+
472
+ return { continua: true }
473
+ }
474
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pwi-plata-type",
3
- "version": "0.1.0",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
6
  "bin": {
@@ -0,0 +1,26 @@
1
+ //@ts-nocheck
2
+ import { PlataModels } from "ç__PlataName__ç";
3
+
4
+ const ç__Name__ç = new PlataModels.Model({
5
+ campo: [ PlataModels.Required(), PlataModels.Int() ],
6
+ objeto: {
7
+ campo: [ PlataModels.Optional(), PlataModels.DateTime() ]
8
+ },
9
+ arrayItens: [{
10
+ campo: [ PlataModels.Required(), PlataModels.Telefone() ]
11
+ }]
12
+ })
13
+
14
+ ç__Name__ç.addValidacao('Validação Customizada', async (objeto) => {
15
+ if (objeto.campo > 30) {
16
+ return {
17
+ errorID: 'BM0001',
18
+ msg: 'O campo não pode ser maior que 30',
19
+ error: `valor do campo: ${objeto.campo}`
20
+ }
21
+ }
22
+
23
+ return null
24
+ })
25
+
26
+ export const ç__Name__çModel = ç__Name__ç
@@ -7,6 +7,7 @@ export async function install({ dirs, projectPackageJson }) {
7
7
  promises.push(t.createFolderProject('clusters'))
8
8
  promises.push(t.createFolderProject('routes'))
9
9
  promises.push(t.createFolderProject('libs'))
10
+ promises.push(t.createFolderProject('models'))
10
11
 
11
12
  promises.push(t.copyFolderToProject('configs'))
12
13
  promises.push(t.copyFolderToProject('envs'))