vsrepo 1.0.3 → 1.0.4
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 +299 -72
- package/VSRepository/VSRepository.d.ts +21 -15
- package/VSRepository/index.d.ts +2 -2
- package/package.json +19 -2
- package/scripts/configure-prisma-import.mjs +155 -0
package/README.md
CHANGED
|
@@ -1,22 +1,95 @@
|
|
|
1
1
|
# VSRepo
|
|
2
2
|
|
|
3
|
-
Biblioteca de repository para projetos que usam Prisma.
|
|
3
|
+
Biblioteca de repository para projetos que usam Prisma.
|
|
4
|
+
O VSRepo permite criar repositories tipados com métodos base (`get`, `save` e `remove`) e métodos dinâmicos inferidos pelo nome, como:
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
- `findByEmail`
|
|
7
|
+
- `findManyPaginated`
|
|
8
|
+
- `updateById`
|
|
9
|
+
- `deleteManyByIdIn`
|
|
10
|
+
|
|
11
|
+
Tudo com inferência automática baseada no Prisma Client do próprio projeto.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Instalação
|
|
16
|
+
|
|
17
|
+
Instale o VSRepo e o Prisma Client:
|
|
6
18
|
|
|
7
19
|
```bash
|
|
8
20
|
pnpm add vsrepo @prisma/client
|
|
9
21
|
```
|
|
10
22
|
|
|
11
|
-
|
|
23
|
+
Gere o Prisma Client:
|
|
12
24
|
|
|
13
25
|
```bash
|
|
14
26
|
pnpm prisma generate
|
|
15
27
|
```
|
|
16
28
|
|
|
17
|
-
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
# Gerando os tipos do VSRepo
|
|
32
|
+
|
|
33
|
+
O VSRepo precisa conhecer o caminho real do seu Prisma Client para gerar as tipagens corretamente.
|
|
34
|
+
|
|
35
|
+
Execute:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pnpm vsrepo generate --output src/generated/vsrepo --prisma src/generated/prisma/client
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
ou:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pnpm vsrepo generate -o src/generated/vsrepo -p src/generated/prisma/client
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## O que esse comando faz
|
|
48
|
+
|
|
49
|
+
O script:
|
|
50
|
+
|
|
51
|
+
1. Lê os arquivos de tipagem internos do VSRepo
|
|
52
|
+
2. Substitui o import do Prisma pelo caminho informado em `--prisma`
|
|
53
|
+
3. Gera uma façade tipada dentro da pasta definida em `--output`
|
|
54
|
+
|
|
55
|
+
Arquivos gerados:
|
|
56
|
+
|
|
57
|
+
```txt
|
|
58
|
+
src/generated/vsrepo/
|
|
59
|
+
├── VSRepoError.ts
|
|
60
|
+
├── VSRepoError.types.d.ts
|
|
61
|
+
├── VSRepository.ts
|
|
62
|
+
├── VSRepository.types.d.ts
|
|
63
|
+
└── index.ts
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
# Como importar depois
|
|
69
|
+
|
|
70
|
+
Após gerar os arquivos:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { setupVSRepo } from "../generated/vsrepo";
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
ou:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import {
|
|
80
|
+
setupVSRepo,
|
|
81
|
+
type SelectModels,
|
|
82
|
+
type WhereModel,
|
|
83
|
+
} from "../generated/vsrepo";
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Você NÃO deve mais importar diretamente de `vsrepo`.
|
|
18
87
|
|
|
19
|
-
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
# Uso básico
|
|
91
|
+
|
|
92
|
+
## Criando o Prisma Client
|
|
20
93
|
|
|
21
94
|
```ts
|
|
22
95
|
// src/db.ts
|
|
@@ -27,12 +100,21 @@ const prisma = new PrismaClient();
|
|
|
27
100
|
export default prisma;
|
|
28
101
|
```
|
|
29
102
|
|
|
30
|
-
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
# Criando um repository
|
|
31
106
|
|
|
32
107
|
```ts
|
|
33
108
|
// src/repositories/usuarioRepository.ts
|
|
109
|
+
|
|
34
110
|
import prisma from "../db";
|
|
35
|
-
|
|
111
|
+
|
|
112
|
+
import {
|
|
113
|
+
setupVSRepo,
|
|
114
|
+
type SelectModels,
|
|
115
|
+
type WhereModel,
|
|
116
|
+
} from "../generated/vsrepo";
|
|
117
|
+
|
|
36
118
|
import type { Prisma } from "@prisma/client";
|
|
37
119
|
|
|
38
120
|
type Usuario = Prisma.usuarioGetPayload<{
|
|
@@ -48,6 +130,7 @@ const usuarioSelectModels = {
|
|
|
48
130
|
nome: true,
|
|
49
131
|
email: true,
|
|
50
132
|
},
|
|
133
|
+
|
|
51
134
|
minimal: {
|
|
52
135
|
id: true,
|
|
53
136
|
},
|
|
@@ -60,15 +143,34 @@ const usuarioRequiredWhere = {
|
|
|
60
143
|
const usuarioVSRepo = setupVSRepo<Usuario, "usuario">()({
|
|
61
144
|
tableName: "usuario",
|
|
62
145
|
pkName: "id",
|
|
146
|
+
|
|
63
147
|
selectModels: usuarioSelectModels,
|
|
64
148
|
defaultSelectModel: "public",
|
|
149
|
+
|
|
65
150
|
requiredWhere: usuarioRequiredWhere,
|
|
151
|
+
|
|
66
152
|
methods: {
|
|
67
|
-
findByEmail: {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
153
|
+
findByEmail: {
|
|
154
|
+
map: true,
|
|
155
|
+
fbMode: "one",
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
findManyPaginated: {
|
|
159
|
+
map: true,
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
updateById: {
|
|
163
|
+
map: true,
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
deleteManyByIdIn: {
|
|
167
|
+
map: true,
|
|
168
|
+
whereType: "overwrite",
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
count: {
|
|
172
|
+
map: true,
|
|
173
|
+
},
|
|
72
174
|
},
|
|
73
175
|
});
|
|
74
176
|
|
|
@@ -77,7 +179,9 @@ const usuarioRepository = usuarioVSRepo.build(prisma);
|
|
|
77
179
|
export default usuarioRepository;
|
|
78
180
|
```
|
|
79
181
|
|
|
80
|
-
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
# Usando o repository
|
|
81
185
|
|
|
82
186
|
```ts
|
|
83
187
|
import usuarioRepository from "./repositories/usuarioRepository";
|
|
@@ -99,30 +203,44 @@ await usuarioRepository.updateById(usuario.id, {
|
|
|
99
203
|
await usuarioRepository.remove(usuario.id);
|
|
100
204
|
```
|
|
101
205
|
|
|
102
|
-
|
|
206
|
+
---
|
|
103
207
|
|
|
104
|
-
|
|
208
|
+
# Métodos base
|
|
209
|
+
|
|
210
|
+
Ao executar:
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
.build(prisma)
|
|
214
|
+
```
|
|
105
215
|
|
|
106
|
-
|
|
107
|
-
| --- | --- |
|
|
108
|
-
| `get(pk, options?)` | Busca um registro pela primary key definida em `pkName`. |
|
|
109
|
-
| `save(obj, options?)` | Cria ou atualiza um registro. Se `obj` tiver a primary key, usa `upsert`; se não tiver, usa `create`. |
|
|
110
|
-
| `remove(pk, options?)` | Remove um registro pela primary key. |
|
|
216
|
+
o VSRepo cria automaticamente:
|
|
111
217
|
|
|
112
|
-
|
|
218
|
+
| Método | Descrição |
|
|
219
|
+
| ------------ | ----------------------- |
|
|
220
|
+
| `get(pk)` | Busca pela primary key |
|
|
221
|
+
| `save(obj)` | Cria ou atualiza |
|
|
222
|
+
| `remove(pk)` | Remove pela primary key |
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
# Configurando métodos base
|
|
113
227
|
|
|
114
228
|
```ts
|
|
115
229
|
const usuarioRepository = usuarioVSRepo.build(prisma, {
|
|
116
230
|
freeze: true,
|
|
231
|
+
|
|
117
232
|
showWorking: false,
|
|
233
|
+
|
|
118
234
|
baseMethods: {
|
|
119
235
|
get: {
|
|
120
236
|
active: true,
|
|
121
237
|
defaultSelect: "public",
|
|
122
238
|
},
|
|
239
|
+
|
|
123
240
|
remove: {
|
|
124
241
|
defaultSelect: "minimal",
|
|
125
242
|
},
|
|
243
|
+
|
|
126
244
|
save: {
|
|
127
245
|
active: true,
|
|
128
246
|
},
|
|
@@ -130,43 +248,82 @@ const usuarioRepository = usuarioVSRepo.build(prisma, {
|
|
|
130
248
|
});
|
|
131
249
|
```
|
|
132
250
|
|
|
133
|
-
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
# Select models
|
|
134
254
|
|
|
135
|
-
`selectModels`
|
|
255
|
+
`selectModels` cria selects reutilizáveis.
|
|
136
256
|
|
|
137
257
|
```ts
|
|
138
258
|
const usuario = await usuarioRepository.get(id, {
|
|
139
259
|
selectModel: "minimal",
|
|
140
260
|
});
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Para retornar o payload padrão do Prisma:
|
|
141
264
|
|
|
265
|
+
```ts
|
|
142
266
|
const usuarioCompleto = await usuarioRepository.get(id, {
|
|
143
267
|
selectModel: false,
|
|
144
268
|
});
|
|
145
269
|
```
|
|
146
270
|
|
|
147
|
-
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
# Métodos dinâmicos
|
|
148
274
|
|
|
149
|
-
|
|
275
|
+
Métodos dinâmicos são definidos em:
|
|
150
276
|
|
|
151
|
-
|
|
277
|
+
```ts
|
|
278
|
+
methods: {
|
|
279
|
+
}
|
|
280
|
+
```
|
|
152
281
|
|
|
153
|
-
|
|
282
|
+
Exemplo:
|
|
154
283
|
|
|
155
284
|
```ts
|
|
156
285
|
methods: {
|
|
157
286
|
findUniqueByIdAndEmail: { map: true },
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
287
|
+
|
|
288
|
+
findByNomeContainsInsensitive: {
|
|
289
|
+
map: true,
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
findManyPaginated: {
|
|
293
|
+
map: true,
|
|
294
|
+
},
|
|
295
|
+
|
|
296
|
+
findListWhereOrderedAndPaginated: {
|
|
297
|
+
map: true,
|
|
298
|
+
whereType: 'overwrite',
|
|
299
|
+
},
|
|
300
|
+
|
|
301
|
+
createManyAndReturn: {
|
|
302
|
+
map: true,
|
|
303
|
+
},
|
|
304
|
+
|
|
305
|
+
updateById: {
|
|
306
|
+
map: true,
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
deleteManyByIdIn: {
|
|
310
|
+
map: true,
|
|
311
|
+
whereType: 'overwrite',
|
|
312
|
+
},
|
|
313
|
+
|
|
314
|
+
existsByEmail: {
|
|
315
|
+
map: true,
|
|
316
|
+
},
|
|
317
|
+
|
|
318
|
+
countByPerfil: {
|
|
319
|
+
map: true,
|
|
320
|
+
},
|
|
166
321
|
}
|
|
167
322
|
```
|
|
168
323
|
|
|
169
|
-
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
# Exemplos de uso
|
|
170
327
|
|
|
171
328
|
```ts
|
|
172
329
|
const usuario = await usuarioRepository.findUniqueByIdAndEmail(id, email);
|
|
@@ -179,43 +336,58 @@ const pagina = await usuarioRepository.findManyPaginated({
|
|
|
179
336
|
});
|
|
180
337
|
|
|
181
338
|
const ordenado = await usuarioRepository.findListWhereOrderedAndPaginated(
|
|
182
|
-
{
|
|
183
|
-
|
|
184
|
-
|
|
339
|
+
{
|
|
340
|
+
nome: {
|
|
341
|
+
startsWith: "A",
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
|
|
345
|
+
{
|
|
346
|
+
dataCriacao: "desc",
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
{
|
|
350
|
+
take: 10,
|
|
351
|
+
},
|
|
185
352
|
);
|
|
186
353
|
```
|
|
187
354
|
|
|
188
|
-
|
|
355
|
+
---
|
|
189
356
|
|
|
190
|
-
|
|
357
|
+
# Filtros suportados
|
|
191
358
|
|
|
192
|
-
| Padrão
|
|
193
|
-
|
|
|
194
|
-
| `And` / `Or`
|
|
195
|
-
| `In` / `NotIn`
|
|
196
|
-
| `Contains`
|
|
197
|
-
| `
|
|
198
|
-
| `
|
|
199
|
-
| `
|
|
200
|
-
| `
|
|
201
|
-
| `
|
|
202
|
-
| `
|
|
203
|
-
| `
|
|
359
|
+
| Padrão | Exemplo |
|
|
360
|
+
| ------------------ | ----------------------------------- |
|
|
361
|
+
| `And` / `Or` | `findByIdAndEmail` |
|
|
362
|
+
| `In` / `NotIn` | `deleteManyByIdIn` |
|
|
363
|
+
| `Contains` | `findByNomeContains` |
|
|
364
|
+
| `StartsWith` | `findByNomeStartsWith` |
|
|
365
|
+
| `EndsWith` | `findByEmailEndsWith` |
|
|
366
|
+
| `Insensitive` | `findByNomeContainsInsensitive` |
|
|
367
|
+
| `GreaterThan` | `findByIdadeGreaterThan` |
|
|
368
|
+
| `LessThanEqual` | `findByIdadeLessThanEqual` |
|
|
369
|
+
| `IsNull` | `findByPerfilIsNull` |
|
|
370
|
+
| `IsTrue` | `findByAtivoIsTrue` |
|
|
371
|
+
| `Some` | `findByPostagensSomeTituloContains` |
|
|
372
|
+
| `With` / `Without` | `findByPerfilWith` |
|
|
204
373
|
|
|
205
|
-
|
|
374
|
+
---
|
|
206
375
|
|
|
207
|
-
|
|
376
|
+
# Relações no save
|
|
208
377
|
|
|
209
378
|
```ts
|
|
210
379
|
const usuarioVSRepo = setupVSRepo<Usuario, "usuario">()({
|
|
211
380
|
tableName: "usuario",
|
|
381
|
+
|
|
212
382
|
pkName: "id",
|
|
383
|
+
|
|
213
384
|
relations: {
|
|
214
385
|
perfil: {
|
|
215
386
|
pk: "id",
|
|
216
387
|
mode: "oto",
|
|
217
388
|
restriction: "set",
|
|
218
389
|
},
|
|
390
|
+
|
|
219
391
|
postagens: {
|
|
220
392
|
pk: "id",
|
|
221
393
|
mode: "otm",
|
|
@@ -225,20 +397,26 @@ const usuarioVSRepo = setupVSRepo<Usuario, "usuario">()({
|
|
|
225
397
|
});
|
|
226
398
|
```
|
|
227
399
|
|
|
228
|
-
Modos disponíveis
|
|
400
|
+
## Modos disponíveis
|
|
229
401
|
|
|
230
|
-
| Modo
|
|
231
|
-
|
|
|
232
|
-
| `oto` | one-to-one
|
|
233
|
-
| `otm` | one-to-many
|
|
234
|
-
| `mto` | many-to-one
|
|
402
|
+
| Modo | Relação |
|
|
403
|
+
| ----- | ------------ |
|
|
404
|
+
| `oto` | one-to-one |
|
|
405
|
+
| `otm` | one-to-many |
|
|
406
|
+
| `mto` | many-to-one |
|
|
235
407
|
| `mtm` | many-to-many |
|
|
236
408
|
|
|
237
|
-
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
# Transações
|
|
238
412
|
|
|
239
|
-
|
|
413
|
+
Todos os métodos aceitam:
|
|
240
414
|
|
|
241
|
-
|
|
415
|
+
```ts
|
|
416
|
+
options.db;
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
Exemplo:
|
|
242
420
|
|
|
243
421
|
```ts
|
|
244
422
|
await prisma.$transaction(async (tx) => {
|
|
@@ -248,24 +426,34 @@ await prisma.$transaction(async (tx) => {
|
|
|
248
426
|
email: "maria@email.com",
|
|
249
427
|
senha: "password",
|
|
250
428
|
},
|
|
251
|
-
|
|
429
|
+
|
|
430
|
+
{
|
|
431
|
+
db: tx,
|
|
432
|
+
},
|
|
252
433
|
);
|
|
253
434
|
|
|
254
435
|
await usuarioRepository.updateById(
|
|
255
436
|
usuario.id,
|
|
256
|
-
|
|
257
|
-
{
|
|
437
|
+
|
|
438
|
+
{
|
|
439
|
+
ativo: true,
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
{
|
|
443
|
+
db: tx,
|
|
444
|
+
},
|
|
258
445
|
);
|
|
259
446
|
});
|
|
260
447
|
```
|
|
261
448
|
|
|
262
|
-
|
|
449
|
+
---
|
|
263
450
|
|
|
264
|
-
|
|
451
|
+
# Extendendo um repository
|
|
265
452
|
|
|
266
453
|
```ts
|
|
267
454
|
const repository = usuarioVSRepo
|
|
268
455
|
.build(prisma)
|
|
456
|
+
|
|
269
457
|
.extend((repo) => ({
|
|
270
458
|
async buscarAtivosPorDominio(dominio: string) {
|
|
271
459
|
return repo.findByEmailEndsWith(`@${dominio}`);
|
|
@@ -273,9 +461,48 @@ const repository = usuarioVSRepo
|
|
|
273
461
|
}));
|
|
274
462
|
```
|
|
275
463
|
|
|
276
|
-
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
# Estrutura recomendada
|
|
467
|
+
|
|
468
|
+
```txt
|
|
469
|
+
src/
|
|
470
|
+
├── db.ts
|
|
471
|
+
├── generated/
|
|
472
|
+
│ ├── prisma/
|
|
473
|
+
│ └── vsrepo/
|
|
474
|
+
├── repositories/
|
|
475
|
+
└── services/
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
# Scripts úteis
|
|
277
481
|
|
|
278
482
|
```bash
|
|
279
|
-
pnpm
|
|
280
|
-
|
|
483
|
+
pnpm prisma generate
|
|
484
|
+
|
|
485
|
+
pnpm vsrepo generate \
|
|
486
|
+
--output src/generated/vsrepo \
|
|
487
|
+
--prisma src/generated/prisma/client
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
# Requisitos
|
|
493
|
+
|
|
494
|
+
- TypeScript
|
|
495
|
+
- Prisma
|
|
496
|
+
- Node.js ESM
|
|
497
|
+
- `"moduleResolution": "bundler"` ou `"nodenext"`
|
|
498
|
+
|
|
499
|
+
Exemplo:
|
|
500
|
+
|
|
501
|
+
```json
|
|
502
|
+
{
|
|
503
|
+
"compilerOptions": {
|
|
504
|
+
"module": "NodeNext",
|
|
505
|
+
"moduleResolution": "NodeNext"
|
|
506
|
+
}
|
|
507
|
+
}
|
|
281
508
|
```
|
|
@@ -4,7 +4,7 @@ export type DbClient = PrismaClient;
|
|
|
4
4
|
export type DbTransaction = Prisma.TransactionClient;
|
|
5
5
|
export type ClientOrTransaction = DbClient | DbTransaction;
|
|
6
6
|
|
|
7
|
-
export * from './VSRepoError';
|
|
7
|
+
export * from './VSRepoError.js';
|
|
8
8
|
|
|
9
9
|
type OrderPattern = {
|
|
10
10
|
[key: string]: 'asc' | 'desc' | { _count: 'asc' | 'desc' } | OrderPattern;
|
|
@@ -241,10 +241,16 @@ export type BuildConfig<TSelectKeys extends PropertyKey = string> = {
|
|
|
241
241
|
};
|
|
242
242
|
};
|
|
243
243
|
|
|
244
|
-
type ResolveMethodDefaultSelect<Config, C, Method extends 'get' | 'remove' | 'save'
|
|
245
|
-
C extends { baseMethods
|
|
246
|
-
? D extends keyof
|
|
247
|
-
|
|
244
|
+
type ResolveMethodDefaultSelect<Config, C, Method extends 'get' | 'remove' | 'save', TSelects = ExtractSelectModels<Config>> =
|
|
245
|
+
C extends { baseMethods?: { [_ in Method]?: { defaultSelect?: infer D } } }
|
|
246
|
+
? D extends keyof TSelects
|
|
247
|
+
? D
|
|
248
|
+
: ExtractDefaultSelect<Config> extends keyof TSelects
|
|
249
|
+
? ExtractDefaultSelect<Config>
|
|
250
|
+
: false
|
|
251
|
+
: ExtractDefaultSelect<Config> extends keyof TSelects
|
|
252
|
+
? ExtractDefaultSelect<Config>
|
|
253
|
+
: false;
|
|
248
254
|
|
|
249
255
|
type ResolveCurrentReturn<M extends Prisma.ModelName, Models, S, D> =
|
|
250
256
|
[S] extends [false]
|
|
@@ -261,7 +267,7 @@ type InjectedGet<
|
|
|
261
267
|
TDefault = ExtractDefaultSelect<Config>,
|
|
262
268
|
TPk = ExtractPkName<T, Config>
|
|
263
269
|
> = C extends { baseMethods: { get: { active: false } } } ? {} : {
|
|
264
|
-
get<S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'get'>>(
|
|
270
|
+
get<S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'get', TSelects>>(
|
|
265
271
|
pk: T[TPk extends keyof T ? TPk : never], options?: MethodOptions<S>
|
|
266
272
|
): Promise<ResolveCurrentReturn<M, TSelects, S, TDefault> | null>;
|
|
267
273
|
};
|
|
@@ -272,7 +278,7 @@ type InjectedRemove<
|
|
|
272
278
|
TDefault = ExtractDefaultSelect<Config>,
|
|
273
279
|
TPk = ExtractPkName<T, Config>
|
|
274
280
|
> = C extends { baseMethods: { remove: { active: false } } } ? {} : {
|
|
275
|
-
remove<S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'remove'>>(
|
|
281
|
+
remove<S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'remove', TSelects>>(
|
|
276
282
|
pk: T[TPk extends keyof T ? TPk : never], options?: MethodOptions<S>
|
|
277
283
|
): Promise<ResolveCurrentReturn<M, TSelects, S, TDefault>>;
|
|
278
284
|
};
|
|
@@ -304,14 +310,14 @@ type InjectedSave<
|
|
|
304
310
|
> = C extends { baseMethods: { save: { active: false } } } ? {} : {
|
|
305
311
|
save<
|
|
306
312
|
O extends UpsertWithRelations<T, M, TRelations>,
|
|
307
|
-
S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'save'>
|
|
313
|
+
S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'save', TSelects>
|
|
308
314
|
>(
|
|
309
315
|
obj: O & UpsertWithRelations<T, M, TRelations>,
|
|
310
316
|
options?: MethodOptions<S>
|
|
311
317
|
): Promise<RefineSaveResult<ResolveCurrentReturn<M, TSelects, S, TDefault>, O>>;
|
|
312
318
|
};
|
|
313
319
|
|
|
314
|
-
type InjectedBaseMethods<T, M extends Prisma.ModelName, Config, C extends BuildConfig | undefined> =
|
|
320
|
+
type InjectedBaseMethods<T, M extends Prisma.ModelName, Config, C extends BuildConfig<any> | undefined> =
|
|
315
321
|
InjectedGet<T, M, Config, C> &
|
|
316
322
|
InjectedRemove<T, M, Config, C> &
|
|
317
323
|
InjectedSave<T, M, Config, C>;
|
|
@@ -333,24 +339,24 @@ export type RepoConfig<T, M extends Prisma.ModelName, SM extends Record<string,
|
|
|
333
339
|
tableName: Uncapitalize<M>;
|
|
334
340
|
pkName: keyof T;
|
|
335
341
|
selectModels?: SM;
|
|
336
|
-
defaultSelectModel?: keyof SM
|
|
342
|
+
defaultSelectModel?: Extract<keyof SM, string>;
|
|
337
343
|
requiredWhere?: WhereModel<M>;
|
|
338
344
|
relations?: RepositoryRelations<T>;
|
|
339
345
|
methods?: Record<string, MethodConfig<M, SM>>;
|
|
340
346
|
};
|
|
341
347
|
|
|
342
|
-
export type BuiltRepository<T extends object, M extends Prisma.ModelName, Config extends RepoConfig<T, M>, C extends BuildConfig<
|
|
348
|
+
export type BuiltRepository<T extends object, M extends Prisma.ModelName, Config extends RepoConfig<T, M, any>, C extends BuildConfig<any> | undefined> = {
|
|
343
349
|
extend<E>(extensionFunc: (repo: BuiltRepository<T, M, Config, C>) => E): BuiltRepository<T, M, Config, C> & E;
|
|
344
350
|
} & DynamicMethods<T, M, Config, PrismaModelInputs<M>> & InjectedBaseMethods<T, M, Config, C>;
|
|
345
351
|
|
|
346
|
-
export declare class VSRepository<T extends object, M extends Prisma.ModelName, const Config extends RepoConfig<T, M> = RepoConfig<T, M>> {
|
|
352
|
+
export declare class VSRepository<T extends object, M extends Prisma.ModelName, const Config extends RepoConfig<T, M, any> = RepoConfig<T, M, any>> {
|
|
347
353
|
readonly config: Config;
|
|
348
354
|
constructor(config: Config);
|
|
349
|
-
build<C extends BuildConfig<
|
|
355
|
+
build<C extends BuildConfig<any>>(prisma: DbClient, config?: C): BuiltRepository<T, M, Config, C>;
|
|
350
356
|
vsrepocache: never;
|
|
351
357
|
}
|
|
352
358
|
|
|
353
|
-
export type RepositoryOf<TRepo, C = undefined, E = unknown> =
|
|
359
|
+
export type RepositoryOf<TRepo, C extends BuildConfig<any> | undefined = undefined, E = unknown> =
|
|
354
360
|
TRepo extends VSRepository<infer T, infer M, infer Config>
|
|
355
361
|
? BuiltRepository<T, M, Config, C> & E
|
|
356
362
|
: never;
|
|
@@ -359,7 +365,7 @@ export type ValidateRepoConfig<T extends object, M extends Prisma.ModelName, Con
|
|
|
359
365
|
tableName: Uncapitalize<M>;
|
|
360
366
|
pkName: keyof T;
|
|
361
367
|
selectModels?: SelectModels<M>;
|
|
362
|
-
defaultSelectModel?: Config extends { selectModels: infer SM } ? (keyof SM extends never ? string : keyof SM) : string;
|
|
368
|
+
defaultSelectModel?: Config extends { selectModels: infer SM } ? (keyof SM extends never ? string : Extract<keyof SM, string>) : string;
|
|
363
369
|
requiredWhere?: WhereModel<M>;
|
|
364
370
|
relations?: RepositoryRelations<T>;
|
|
365
371
|
methods?: {
|
package/VSRepository/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './VSRepoError';
|
|
2
|
-
export * from './VSRepository';
|
|
1
|
+
export * from './VSRepoError.js';
|
|
2
|
+
export * from './VSRepository.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vsrepo",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Uma biblioteca de repositório virtual para Prisma",
|
|
5
5
|
"main": "./VSRepository/index.js",
|
|
6
6
|
"types": "./VSRepository/index.d.ts",
|
|
@@ -8,12 +8,29 @@
|
|
|
8
8
|
".": {
|
|
9
9
|
"types": "./VSRepository/index.d.ts",
|
|
10
10
|
"default": "./VSRepository/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./VSRepository": {
|
|
13
|
+
"types": "./VSRepository/VSRepository.d.ts",
|
|
14
|
+
"import": "./VSRepository/VSRepository.js"
|
|
15
|
+
},
|
|
16
|
+
"./VSRepoError": {
|
|
17
|
+
"types": "./VSRepository/VSRepoError.d.ts",
|
|
18
|
+
"import": "./VSRepository/VSRepoError.js"
|
|
11
19
|
}
|
|
12
20
|
},
|
|
13
21
|
"type": "module",
|
|
14
22
|
"files": [
|
|
15
|
-
"VSRepository"
|
|
23
|
+
"VSRepository",
|
|
24
|
+
"scripts"
|
|
16
25
|
],
|
|
26
|
+
"bin": {
|
|
27
|
+
"vsrepo": "./scripts/configure-prisma-import.mjs",
|
|
28
|
+
"vsrepo-configure-prisma-import": "./scripts/configure-prisma-import.mjs"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"vsrepo": "node ./scripts/configure-prisma-import.mjs",
|
|
32
|
+
"configure:prisma-import": "node ./scripts/configure-prisma-import.mjs"
|
|
33
|
+
},
|
|
17
34
|
"keywords": [
|
|
18
35
|
"prisma",
|
|
19
36
|
"repository",
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const workspaceRoot = process.cwd();
|
|
6
|
+
const args = process.argv.slice(2);
|
|
7
|
+
const scriptDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
|
|
9
|
+
const command = args[0]?.startsWith('-') ? 'generate' : args[0] ?? 'generate';
|
|
10
|
+
const commandArgs = command === 'generate' && args[0] !== command ? args : args.slice(1);
|
|
11
|
+
|
|
12
|
+
if (command !== 'generate') {
|
|
13
|
+
console.error(`Comando desconhecido: ${command}`);
|
|
14
|
+
console.error('Uso: vsrepo generate --output <dir-output> --prisma <path-prisma-client>');
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const outputFlagIndex = commandArgs.findIndex((arg) => arg === '--output' || arg === '-o');
|
|
19
|
+
const prismaFlagIndex = commandArgs.findIndex((arg) => arg === '--prisma' || arg === '-p');
|
|
20
|
+
|
|
21
|
+
const outputArg = outputFlagIndex >= 0 ? commandArgs[outputFlagIndex + 1] : commandArgs[0];
|
|
22
|
+
const prismaArg = prismaFlagIndex >= 0 ? commandArgs[prismaFlagIndex + 1] : null;
|
|
23
|
+
|
|
24
|
+
if (!outputArg || outputArg.startsWith('-')) {
|
|
25
|
+
console.error('Uso: vsrepo generate --output <dir-output> --prisma <path-prisma-client>');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!prismaArg || prismaArg.startsWith('-')) {
|
|
30
|
+
console.error('Uso: vsrepo generate --output <dir-output> --prisma <path-prisma-client>');
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const outputDir = path.resolve(workspaceRoot, outputArg);
|
|
35
|
+
const prismaTargetPath = stripKnownExtension(path.resolve(workspaceRoot, prismaArg));
|
|
36
|
+
|
|
37
|
+
const installedNodeModulesPath = path.join(workspaceRoot, 'node_modules/vsrepo');
|
|
38
|
+
const installedPackageExists = fs.existsSync(installedNodeModulesPath);
|
|
39
|
+
const packageRoot = installedPackageExists
|
|
40
|
+
? installedNodeModulesPath
|
|
41
|
+
: path.resolve(scriptDirectory, '..');
|
|
42
|
+
|
|
43
|
+
const sourceDir = path.join(packageRoot, 'VSRepository');
|
|
44
|
+
|
|
45
|
+
if (!fs.existsSync(sourceDir)) {
|
|
46
|
+
console.error(`Nao foi possivel localizar a pasta VSRepository em: ${sourceDir}`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
51
|
+
|
|
52
|
+
const typeFiles = [
|
|
53
|
+
'VSRepoError.d.ts',
|
|
54
|
+
'VSRepository.d.ts',
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
for (const fileName of typeFiles) {
|
|
58
|
+
const sourceFile = path.join(sourceDir, fileName);
|
|
59
|
+
|
|
60
|
+
if (!fs.existsSync(sourceFile)) {
|
|
61
|
+
console.warn(`Arquivo ignorado (nao encontrado): ${fileName}`);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const targetFile = path.join(outputDir, fileName.replace('.d.ts', '.types.d.ts'));
|
|
66
|
+
let contents = fs.readFileSync(sourceFile, 'utf8');
|
|
67
|
+
|
|
68
|
+
contents = contents.replace(
|
|
69
|
+
/from\s+(['"])@vsrepo\/prisma\/types\1/g,
|
|
70
|
+
`from '${relativeImportPath(path.dirname(targetFile), prismaTargetPath)}'`
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
fs.writeFileSync(targetFile, contents, 'utf8');
|
|
74
|
+
console.log(`Gerado: ${path.relative(workspaceRoot, targetFile)}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const tsFiles = [
|
|
78
|
+
{
|
|
79
|
+
fileName: 'VSRepoError.ts',
|
|
80
|
+
content: `import {
|
|
81
|
+
VSRepoError as VSRepoErrorRuntime,
|
|
82
|
+
VSRepoConfigError as VSRepoConfigErrorRuntime,
|
|
83
|
+
VSRepoBuildError as VSRepoBuildErrorRuntime,
|
|
84
|
+
VSRepoExtendError as VSRepoExtendErrorRuntime,
|
|
85
|
+
VSRepoRuntimeError as VSRepoRuntimeErrorRuntime
|
|
86
|
+
} from 'vsrepo/VSRepoError';
|
|
87
|
+
|
|
88
|
+
import type {
|
|
89
|
+
VSRepoError as VSRepoErrorType,
|
|
90
|
+
VSRepoConfigError as VSRepoConfigErrorType,
|
|
91
|
+
VSRepoBuildError as VSRepoBuildErrorType,
|
|
92
|
+
VSRepoExtendError as VSRepoExtendErrorType,
|
|
93
|
+
VSRepoRuntimeError as VSRepoRuntimeErrorType
|
|
94
|
+
} from './VSRepoError.types';
|
|
95
|
+
|
|
96
|
+
export const VSRepoError: typeof VSRepoErrorType = VSRepoErrorRuntime;
|
|
97
|
+
export const VSRepoConfigError: typeof VSRepoConfigErrorType = VSRepoConfigErrorRuntime;
|
|
98
|
+
export const VSRepoBuildError: typeof VSRepoBuildErrorType = VSRepoBuildErrorRuntime;
|
|
99
|
+
export const VSRepoExtendError: typeof VSRepoExtendErrorType = VSRepoExtendErrorRuntime;
|
|
100
|
+
export const VSRepoRuntimeError: typeof VSRepoRuntimeErrorType = VSRepoRuntimeErrorRuntime;
|
|
101
|
+
|
|
102
|
+
export type * from './VSRepoError.types';
|
|
103
|
+
`,
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
fileName: 'VSRepository.ts',
|
|
107
|
+
content: `import {
|
|
108
|
+
VSRepository as VSRepositoryRuntime,
|
|
109
|
+
setupVSRepo as setupVSRepoRuntime
|
|
110
|
+
} from 'vsrepo/VSRepository';
|
|
111
|
+
|
|
112
|
+
import type {
|
|
113
|
+
VSRepository as VSRepositoryType,
|
|
114
|
+
setupVSRepo as setupVSRepoType
|
|
115
|
+
} from './VSRepository.types';
|
|
116
|
+
|
|
117
|
+
export const VSRepository: typeof VSRepositoryType = VSRepositoryRuntime;
|
|
118
|
+
export const setupVSRepo: typeof setupVSRepoType = setupVSRepoRuntime;
|
|
119
|
+
|
|
120
|
+
export type * from './VSRepository.types';
|
|
121
|
+
`,
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
fileName: 'index.ts',
|
|
125
|
+
content: `export { VSRepoError, VSRepoConfigError, VSRepoBuildError, VSRepoExtendError, VSRepoRuntimeError } from './VSRepoError.js';
|
|
126
|
+
export { VSRepository, setupVSRepo } from './VSRepository.js';
|
|
127
|
+
|
|
128
|
+
export type * from './VSRepoError.types';
|
|
129
|
+
export type * from './VSRepository.types';
|
|
130
|
+
`,
|
|
131
|
+
},
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
for (const file of tsFiles) {
|
|
135
|
+
const targetFile = path.join(outputDir, file.fileName);
|
|
136
|
+
fs.writeFileSync(targetFile, file.content, 'utf8');
|
|
137
|
+
console.log(`Gerado: ${path.relative(workspaceRoot, targetFile)}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
console.log('\nVSRepository gerado com tipagem do Prisma.');
|
|
141
|
+
console.log(`Prisma usado em: ${prismaTargetPath}`);
|
|
142
|
+
|
|
143
|
+
function stripKnownExtension(inputPath) {
|
|
144
|
+
return inputPath.replace(/\.(?:d\.ts|ts|js|mjs|cjs)$/i, '');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function relativeImportPath(fromDirectory, toPath) {
|
|
148
|
+
const relativePath = path.relative(fromDirectory, toPath);
|
|
149
|
+
const normalized = relativePath.startsWith('.') ? relativePath : `./${relativePath}`;
|
|
150
|
+
return toPosix(normalized);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function toPosix(inputPath) {
|
|
154
|
+
return inputPath.split(path.sep).join('/');
|
|
155
|
+
}
|