vsrepo 1.1.5 → 1.1.7
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 +44 -10
- package/VSRepository/VSRepository.d.ts +127 -18
- package/VSRepository/VSRepository.js +256 -107
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# VSRepository
|
|
2
2
|
|
|
3
3
|

|
|
4
|
-

|
|
4
|
+

|
|
5
5
|

|
|
6
6
|
|
|
7
7
|
Biblioteca de repository pattern para projetos que usam **Prisma**, com suporte completo a **TypeScript** e **type inference** automático.
|
|
@@ -35,7 +35,7 @@ O VSRepository permite criar repositories fortemente tipados com:
|
|
|
35
35
|
- [Configuração de métodos](#configuração-de-métodos)
|
|
36
36
|
- [Relações no save](#relações-no-save)
|
|
37
37
|
- [Transações](#transações)
|
|
38
|
-
- [
|
|
38
|
+
- [Estendendo um repository](#estendendo-um-repository)
|
|
39
39
|
- [Tratamento de erros](#tratamento-de-erros)
|
|
40
40
|
- [Tipos utilitários](#tipos-utilitários)
|
|
41
41
|
- [API Reference](#api-reference)
|
|
@@ -334,6 +334,7 @@ Ao chamar `.build(prisma)` os métodos base abaixo são automaticamente disponib
|
|
|
334
334
|
| `get(pk)` | Busca um registro pela primary key |
|
|
335
335
|
| `getOrThrow(pk)` | Busca um registro pela primary key e lança erro se não encontrar |
|
|
336
336
|
| `save(obj)` | Cria ou atualiza (se o objeto passado tiver a `pk` faz `upsert`, se não faz `create`) |
|
|
337
|
+
| `patch(pk, obj)` | Atualiza parcialmente um registro pela primary key (equivalente ao `update` com payload parcial) |
|
|
337
338
|
| `remove(pk)` | Remove um registro pela primary key |
|
|
338
339
|
| `removeList(pks)` | Remove vários registros pela lista de primary keys — retorna `{ count }` |
|
|
339
340
|
| `getAll()` | Retorna todos os registros (aceita `pagination` e `order` no `options`) |
|
|
@@ -357,9 +358,13 @@ usuarioVSRepo.build(prisma, {
|
|
|
357
358
|
remove: {
|
|
358
359
|
active: true,
|
|
359
360
|
defaultSelect: "minimal",
|
|
361
|
+
ignoreRequiredWhere: false, // Aplica o requiredWhere no remove (padrão = false)
|
|
360
362
|
},
|
|
361
363
|
save: {
|
|
362
|
-
ignoreRequiredWhere: true,
|
|
364
|
+
ignoreRequiredWhere: true, // Não aplica requiredWhere no save
|
|
365
|
+
},
|
|
366
|
+
patch: {
|
|
367
|
+
defaultSelect: "minimal",
|
|
363
368
|
},
|
|
364
369
|
has: {
|
|
365
370
|
active: false, // Desativa o 'has' (padrão = true)
|
|
@@ -721,7 +726,7 @@ methods: {
|
|
|
721
726
|
|
|
722
727
|
## Relações no save
|
|
723
728
|
|
|
724
|
-
Configure relações para que o `save` as gerencie automaticamente. Para que as relações apareçam no autocomplete, o tipo genérico deve incluir as relações usando `GetPayload`:
|
|
729
|
+
Configure relações para que o `save` as gerencie automaticamente. Essas mesmas relações também são usadas no `patch`. Para que as relações apareçam no autocomplete, o tipo genérico deve incluir as relações usando `GetPayload`:
|
|
725
730
|
|
|
726
731
|
```ts
|
|
727
732
|
import type { Prisma } from "../../generated/prisma/client";
|
|
@@ -743,12 +748,39 @@ const usuarioRepository = setupVSRepo<Usuario, "usuario">()({
|
|
|
743
748
|
postagens: {
|
|
744
749
|
pk: "id",
|
|
745
750
|
mode: "otm",
|
|
746
|
-
restriction: "
|
|
751
|
+
restriction: "add",
|
|
747
752
|
},
|
|
748
753
|
},
|
|
749
754
|
}).build(prisma);
|
|
750
755
|
```
|
|
751
756
|
|
|
757
|
+
Exemplos de uso com relações:
|
|
758
|
+
|
|
759
|
+
```ts
|
|
760
|
+
await usuarioRepository.save({
|
|
761
|
+
nome: "Maria",
|
|
762
|
+
email: "maria@email.com",
|
|
763
|
+
senha: "password",
|
|
764
|
+
perfil: {
|
|
765
|
+
id: 1,
|
|
766
|
+
bio: "Bio da Maria",
|
|
767
|
+
},
|
|
768
|
+
postagens: [
|
|
769
|
+
{ titulo: "Primeiro post", conteudo: "Olá!" },
|
|
770
|
+
],
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
await usuarioRepository.patch(1, {
|
|
774
|
+
perfil: {
|
|
775
|
+
id: 1,
|
|
776
|
+
bio: "Bio atualizada",
|
|
777
|
+
},
|
|
778
|
+
postagens: [
|
|
779
|
+
{ id: 10, titulo: "Post revisado", conteudo: "Conteúdo ajustado" },
|
|
780
|
+
],
|
|
781
|
+
});
|
|
782
|
+
```
|
|
783
|
+
|
|
752
784
|
> **Dica:** Se o tipo genérico não incluir `include: { relação: true }`, o VSRepository ainda funcionará, mas o autocomplete não sugerirá as relações no `save`. O tipo recomendado é sempre `GetPayload<{ include: { /* suas relações */ } }>` para melhor experiência de desenvolvimento.
|
|
753
785
|
|
|
754
786
|
**Modos de relação:**
|
|
@@ -774,23 +806,24 @@ const usuarioRepository = setupVSRepo<Usuario, "usuario">()({
|
|
|
774
806
|
Todos os métodos aceitam `options.db` para participar de uma transação:
|
|
775
807
|
|
|
776
808
|
```ts
|
|
777
|
-
await prisma.$transaction(async (tx) => {
|
|
809
|
+
await usuarioRepository.prisma.$transaction(async (tx) => {
|
|
778
810
|
const usuario = await usuarioRepository.save(
|
|
779
811
|
{ nome: "Maria", email: "maria@email.com", senha: "password" },
|
|
780
812
|
{ db: tx }
|
|
781
813
|
);
|
|
782
814
|
|
|
783
|
-
await
|
|
784
|
-
usuario.id,
|
|
785
|
-
{ ativo: true },
|
|
815
|
+
await usuarioLogsRepository.save(
|
|
816
|
+
{ acao: "Cadastro de usuário", data: { usuarioCadastrado: usuario.id } },
|
|
786
817
|
{ db: tx }
|
|
787
818
|
);
|
|
788
819
|
});
|
|
789
820
|
```
|
|
790
821
|
|
|
822
|
+
Observe que é possível diferentes repositories participarem da mesma transação.
|
|
823
|
+
|
|
791
824
|
---
|
|
792
825
|
|
|
793
|
-
##
|
|
826
|
+
## Estendendo um repository
|
|
794
827
|
|
|
795
828
|
```ts
|
|
796
829
|
const usuarioRepository = setupVSRepo<Usuario, "usuario">()({
|
|
@@ -1011,6 +1044,7 @@ vsRepo.build(prisma, {
|
|
|
1011
1044
|
getOrThrow?:{ active?: boolean; defaultSelect?: string; ignoreRequiredWhere?: boolean };
|
|
1012
1045
|
remove?: { active?: boolean; defaultSelect?: string; ignoreRequiredWhere?: boolean };
|
|
1013
1046
|
save?: { active?: boolean; defaultSelect?: string; ignoreRequiredWhere?: boolean };
|
|
1047
|
+
patch?: { active?: boolean; defaultSelect?: string; ignoreRequiredWhere?: boolean };
|
|
1014
1048
|
getAll?: { active?: boolean; defaultSelect?: string; ignoreRequiredWhere?: boolean };
|
|
1015
1049
|
|
|
1016
1050
|
// Métodos que NÃO aceitam `defaultSelect`
|
|
@@ -197,7 +197,7 @@ export type MethodOptions<S> = {
|
|
|
197
197
|
/**
|
|
198
198
|
* Select model a ser aplicado na operação.
|
|
199
199
|
*
|
|
200
|
-
* Use `false` para retornar o payload completo do Prisma, sem select.
|
|
200
|
+
* @note Use `false` para retornar o payload completo do Prisma, sem select.
|
|
201
201
|
*/
|
|
202
202
|
selectModel?: S | false;
|
|
203
203
|
/**
|
|
@@ -329,7 +329,7 @@ export type MethodConfig<M extends Prisma.ModelName, SelectModels = any> = {
|
|
|
329
329
|
readonly map: boolean;
|
|
330
330
|
/** Sobrescreve o `defaultSelectModel` apenas para este método. */
|
|
331
331
|
readonly selectModel?: keyof SelectModels | false;
|
|
332
|
-
/** Controla se o método combina ou sobrescreve o `requiredWhere`. */
|
|
332
|
+
/** Controla se o método combina (`extending`) ou sobrescreve (`overwrite`) o `requiredWhere`. */
|
|
333
333
|
readonly whereType?: 'overwrite' | 'extending';
|
|
334
334
|
/** Redireciona a lógica para outro padrão de método válido. */
|
|
335
335
|
readonly proxyTo?: ValidMethodPatterns;
|
|
@@ -372,6 +372,8 @@ export type BuildConfig<TSelectKeys extends PropertyKey = string> = {
|
|
|
372
372
|
remove?: BaseMethodConfig<TSelectKeys>;
|
|
373
373
|
/** Configuração do método `save`. */
|
|
374
374
|
save?: BaseMethodConfig<TSelectKeys>;
|
|
375
|
+
/** Configuração do método `patch`. */
|
|
376
|
+
patch?: BaseMethodConfig<TSelectKeys>;
|
|
375
377
|
/** Configuração do método `removeList` (exclusão em lote). Não aceita select. */
|
|
376
378
|
removeList?: Omit<BaseMethodConfig<TSelectKeys>, 'defaultSelect'>;
|
|
377
379
|
/** Configuração do método `getAll` (listagem total). */
|
|
@@ -383,7 +385,7 @@ export type BuildConfig<TSelectKeys extends PropertyKey = string> = {
|
|
|
383
385
|
};
|
|
384
386
|
};
|
|
385
387
|
|
|
386
|
-
type ResolveMethodDefaultSelect<Config, C, Method extends 'get' | 'getOrThrow' | 'remove' | 'save' | 'getAll', TSelects = ExtractSelectModels<Config>> =
|
|
388
|
+
type ResolveMethodDefaultSelect<Config, C, Method extends 'get' | 'getOrThrow' | 'remove' | 'save' | 'getAll' | 'patch', TSelects = ExtractSelectModels<Config>> =
|
|
387
389
|
C extends { baseMethods?: { [_ in Method]?: { defaultSelect?: infer D } } }
|
|
388
390
|
? D extends keyof TSelects
|
|
389
391
|
? D
|
|
@@ -413,6 +415,12 @@ type InjectedGet<
|
|
|
413
415
|
TDefault = ExtractDefaultSelect<Config>,
|
|
414
416
|
TPk = ExtractPkName<T, Config>
|
|
415
417
|
> = C extends { baseMethods: { get: { active: false } } } ? {} : {
|
|
418
|
+
/**
|
|
419
|
+
* Busca um registro pela chave primária (PK).
|
|
420
|
+
* @param pk Chave primária do registro.
|
|
421
|
+
* @param options Opções adicionais (por exemplo `selectModel` ou `db`).
|
|
422
|
+
* @returns O registro selecionado ou `null` se não encontrado.
|
|
423
|
+
*/
|
|
416
424
|
get<S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'get', TSelects>>(
|
|
417
425
|
pk: T[TPk extends keyof T ? TPk : never], options?: MethodOptions<S>
|
|
418
426
|
): Promise<ResolveCurrentReturn<M, TSelects, S, TDefault> | null>;
|
|
@@ -424,6 +432,12 @@ type InjectedGetOrThrow<
|
|
|
424
432
|
TDefault = ExtractDefaultSelect<Config>,
|
|
425
433
|
TPk = ExtractPkName<T, Config>
|
|
426
434
|
> = C extends { baseMethods: { getOrThrow: { active: false } } } ? {} : {
|
|
435
|
+
/**
|
|
436
|
+
* Busca um registro pela chave primária (PK) e lança erro se não encontrado.
|
|
437
|
+
* @param pk Chave primária do registro.
|
|
438
|
+
* @param options Opções adicionais (por exemplo `selectModel` ou `db`).
|
|
439
|
+
* @returns O registro selecionado.
|
|
440
|
+
*/
|
|
427
441
|
getOrThrow<S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'getOrThrow', TSelects>>(
|
|
428
442
|
pk: T[TPk extends keyof T ? TPk : never], options?: MethodOptions<S>
|
|
429
443
|
): Promise<ResolveCurrentReturn<M, TSelects, S, TDefault>>;
|
|
@@ -435,6 +449,12 @@ type InjectedRemove<
|
|
|
435
449
|
TDefault = ExtractDefaultSelect<Config>,
|
|
436
450
|
TPk = ExtractPkName<T, Config>
|
|
437
451
|
> = C extends { baseMethods: { remove: { active: false } } } ? {} : {
|
|
452
|
+
/**
|
|
453
|
+
* Remove um registro identificado pela chave primária (PK).
|
|
454
|
+
* @param pk Chave primária do registro a ser removido.
|
|
455
|
+
* @param options Opções adicionais (por exemplo `selectModel` ou `db`).
|
|
456
|
+
* @returns O registro removido.
|
|
457
|
+
*/
|
|
438
458
|
remove<S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'remove', TSelects>>(
|
|
439
459
|
pk: T[TPk extends keyof T ? TPk : never], options?: MethodOptions<S>
|
|
440
460
|
): Promise<ResolveCurrentReturn<M, TSelects, S, TDefault>>;
|
|
@@ -474,6 +494,12 @@ type InjectedSave<
|
|
|
474
494
|
TDefault = ExtractDefaultSelect<Config>,
|
|
475
495
|
TRelations = ExtractRelations<Config>
|
|
476
496
|
> = C extends { baseMethods: { save: { active: false } } } ? {} : {
|
|
497
|
+
/**
|
|
498
|
+
* Insere ou atualiza (save/upsert) um registro, aceita os campos de relações definidas nas `relations`.
|
|
499
|
+
* @param obj Payload para criação/atualização.
|
|
500
|
+
* @param options Opções adicionais (por exemplo `selectModel` ou `db`).
|
|
501
|
+
* @returns O registro salvo com tipos refinados conforme a entrada.
|
|
502
|
+
*/
|
|
477
503
|
save<
|
|
478
504
|
O extends UpsertWithRelations<T, M, TRelations>,
|
|
479
505
|
S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'save', TSelects>
|
|
@@ -483,11 +509,40 @@ type InjectedSave<
|
|
|
483
509
|
): Promise<RefineSaveResult<ResolveCurrentReturn<M, TSelects, S, TDefault>, O>>;
|
|
484
510
|
};
|
|
485
511
|
|
|
512
|
+
type InjectedPatch<
|
|
513
|
+
T, M extends Prisma.ModelName, Config, C extends BuildConfig<any> | undefined,
|
|
514
|
+
TSelects = ExtractSelectModels<Config>,
|
|
515
|
+
TDefault = ExtractDefaultSelect<Config>,
|
|
516
|
+
TPk = ExtractPkName<T, Config>,
|
|
517
|
+
I = PrismaModelInputs<M>
|
|
518
|
+
> = C extends { baseMethods: { patch: { active: false } } } ? {} : {
|
|
519
|
+
/**
|
|
520
|
+
* Atualiza parcialmente (patch) um registro existente pela chave primária (PK), aceita os campos de relações definidas nas `relations`.
|
|
521
|
+
* @param pk Chave primária do registro.
|
|
522
|
+
* @param obj Objeto parcial com os campos a atualizar.
|
|
523
|
+
* @param options Opções adicionais (por exemplo `selectModel` ou `db`).
|
|
524
|
+
* @returns O registro atualizado refinado conforme a entrada.
|
|
525
|
+
*/
|
|
526
|
+
patch<
|
|
527
|
+
O extends (I extends { updateInput: infer U } ? U : Record<string, any>),
|
|
528
|
+
S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'patch', TSelects>
|
|
529
|
+
>(
|
|
530
|
+
pk: T[TPk extends keyof T ? TPk : never],
|
|
531
|
+
obj: O & (I extends { updateInput: infer U } ? U : Record<string, any>),
|
|
532
|
+
options?: MethodOptions<S>
|
|
533
|
+
): Promise<RefineSaveResult<ResolveCurrentReturn<M, TSelects, S, TDefault>, O>>;
|
|
534
|
+
};
|
|
535
|
+
|
|
486
536
|
type InjectedRemoveList<
|
|
487
537
|
T, M extends Prisma.ModelName, Config, C extends BuildConfig<any> | undefined,
|
|
488
538
|
TPk = ExtractPkName<T, Config>
|
|
489
539
|
> = C extends { baseMethods: { removeList: { active: false } } } ? {} : {
|
|
490
|
-
/**
|
|
540
|
+
/**
|
|
541
|
+
* Remove múltiplos registros pelas suas chaves primárias.
|
|
542
|
+
* @param pks Lista de chaves primárias a remover.
|
|
543
|
+
* @param options Opções adicionais (por exemplo `db`).
|
|
544
|
+
* @returns Objeto com a contagem de registros removidos.
|
|
545
|
+
*/
|
|
491
546
|
removeList(
|
|
492
547
|
pks: T[TPk extends keyof T ? TPk : never][],
|
|
493
548
|
options?: { db?: ClientOrTransaction }
|
|
@@ -500,7 +555,11 @@ type InjectedGetAll<
|
|
|
500
555
|
TDefault = ExtractDefaultSelect<Config>,
|
|
501
556
|
I = PrismaModelInputs<M>
|
|
502
557
|
> = C extends { baseMethods: { getAll: { active: false } } } ? {} : {
|
|
503
|
-
/**
|
|
558
|
+
/**
|
|
559
|
+
* Busca todos os registros (respeita `requiredWhere` quando aplicado).
|
|
560
|
+
* @param options Opções adicionais, incluindo paginação, ordenação e `db`/`selectModel`.
|
|
561
|
+
* @returns Lista dos registros encontrados`.
|
|
562
|
+
*/
|
|
504
563
|
getAll<S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'getAll', TSelects>>(
|
|
505
564
|
options?: MethodOptions<S> & {
|
|
506
565
|
pagination?: PaginationOptions<I extends { cursorInput: infer Curs } ? Curs : unknown>;
|
|
@@ -512,7 +571,11 @@ type InjectedGetAll<
|
|
|
512
571
|
type InjectedTotal<
|
|
513
572
|
T, M extends Prisma.ModelName, Config, C extends BuildConfig<any> | undefined
|
|
514
573
|
> = C extends { baseMethods: { total: { active: false } } } ? {} : {
|
|
515
|
-
/**
|
|
574
|
+
/**
|
|
575
|
+
* Retorna a quantidade total de registros, respeitando `requiredWhere` quando aplicado.
|
|
576
|
+
* @param options Opções adicionais (por exemplo `db`).
|
|
577
|
+
* @returns Número total de registros.
|
|
578
|
+
*/
|
|
516
579
|
total(options?: { db?: ClientOrTransaction }): Promise<number>;
|
|
517
580
|
};
|
|
518
581
|
|
|
@@ -520,7 +583,12 @@ type InjectedHas<
|
|
|
520
583
|
T, M extends Prisma.ModelName, Config, C extends BuildConfig<any> | undefined,
|
|
521
584
|
TPk = ExtractPkName<T, Config>
|
|
522
585
|
> = C extends { baseMethods: { has: { active: false } } } ? {} : {
|
|
523
|
-
/**
|
|
586
|
+
/**
|
|
587
|
+
* Verifica se um registro existe pela chave primária (PK).
|
|
588
|
+
* @param pk Chave primária a verificar.
|
|
589
|
+
* @param options Opções adicionais (por exemplo `db`).
|
|
590
|
+
* @returns `true` se existir, caso contrário `false`.
|
|
591
|
+
*/
|
|
524
592
|
has(
|
|
525
593
|
pk: T[TPk extends keyof T ? TPk : never],
|
|
526
594
|
options?: { db?: ClientOrTransaction }
|
|
@@ -532,18 +600,63 @@ type InjectedBaseMethods<T, M extends Prisma.ModelName, Config, C extends BuildC
|
|
|
532
600
|
InjectedGetOrThrow<T, M, Config, C> &
|
|
533
601
|
InjectedRemove<T, M, Config, C> &
|
|
534
602
|
InjectedSave<T, M, Config, C> &
|
|
603
|
+
InjectedPatch<T, M, Config, C> &
|
|
535
604
|
InjectedRemoveList<T, M, Config, C> &
|
|
536
605
|
InjectedGetAll<T, M, Config, C> &
|
|
537
606
|
InjectedTotal<T, M, Config, C> &
|
|
538
607
|
InjectedHas<T, M, Config, C>;
|
|
539
608
|
|
|
609
|
+
/**
|
|
610
|
+
* Configuração de relação para One-to-Many ou Many-to-Many.
|
|
611
|
+
*
|
|
612
|
+
* @template TItem O tipo da entidade relacionada.
|
|
613
|
+
*/
|
|
614
|
+
export type ManyRelationConfig<TItem> = {
|
|
615
|
+
/** A chave primária (Primary Key) do entidade relacionada. */
|
|
616
|
+
pk: keyof TItem;
|
|
617
|
+
/** Tipo de relação: `otm` (One-to-Many) ou `mtm` (Many-to-Many). */
|
|
618
|
+
mode: 'otm' | 'mtm';
|
|
619
|
+
/** Comportamento de mutação: `set` (substitui tudo) ou `add` (adiciona aos existentes). */
|
|
620
|
+
restriction: 'set' | 'add';
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Configuração de relação One-to-One.
|
|
625
|
+
*
|
|
626
|
+
* @template TItem O tipo da entidade relacionada.
|
|
627
|
+
*/
|
|
628
|
+
export type OneToOneRelationConfig<TItem> = {
|
|
629
|
+
/** A chave primária (Primary Key) do entidade relacionada. */
|
|
630
|
+
pk: keyof TItem;
|
|
631
|
+
/** Tipo de relação: `oto` (One-to-One). */
|
|
632
|
+
mode: 'oto';
|
|
633
|
+
/** Comportamento de mutação permitido para salvar. */
|
|
634
|
+
restriction: 'set' | 'add';
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Configuração de relação Many-to-One.
|
|
639
|
+
*
|
|
640
|
+
* @template TItem O tipo da entidade relacionada.
|
|
641
|
+
*/
|
|
642
|
+
export type ManyToOneRelationConfig<TItem> = {
|
|
643
|
+
/** A chave primária (Primary Key) da entidade relacionada. */
|
|
644
|
+
pk: keyof TItem;
|
|
645
|
+
/** Tipo de relação: `mto` (Many-to-One). */
|
|
646
|
+
mode: 'mto';
|
|
647
|
+
/** Comportamento de mutação permitido para salvar. */
|
|
648
|
+
restriction: 'set' | 'add';
|
|
649
|
+
/** Habilita a possibilidade de desvincular a relação, tornando a chave estrangeira nula. */
|
|
650
|
+
nullAble?: boolean;
|
|
651
|
+
};
|
|
652
|
+
|
|
540
653
|
/**
|
|
541
654
|
* Infere automaticamente a configuração de relação possível a partir de um campo.
|
|
542
655
|
*/
|
|
543
656
|
export type ExtractRelationConfig<TField> = NonNullable<TField> extends infer NonNull
|
|
544
657
|
? NonNull extends Date | Buffer | Uint8Array ? never
|
|
545
|
-
: NonNull extends any[] ? (NonNull[number] extends object ?
|
|
546
|
-
: NonNull extends object ? (
|
|
658
|
+
: NonNull extends any[] ? (NonNull[number] extends object ? ManyRelationConfig<NonNull[number]> : never)
|
|
659
|
+
: NonNull extends object ? (OneToOneRelationConfig<NonNull> | ManyToOneRelationConfig<NonNull>)
|
|
547
660
|
: never
|
|
548
661
|
: never;
|
|
549
662
|
|
|
@@ -634,11 +747,11 @@ export type ValidateRepoConfig<T extends object, M extends Prisma.ModelName, Con
|
|
|
634
747
|
pkName: keyof T;
|
|
635
748
|
/** Mapa de select models disponíveis. */
|
|
636
749
|
selectModels?: SelectModels<M>;
|
|
637
|
-
/**
|
|
750
|
+
/** Select model padrão. */
|
|
638
751
|
defaultSelectModel?: Config extends { selectModels: infer SM } ? (keyof SM extends never ? string : Extract<keyof SM, string>) : string;
|
|
639
752
|
/** Filtros globais aplicados às queries do repository. */
|
|
640
753
|
requiredWhere?: WhereModel<M>;
|
|
641
|
-
/** Relações gerenciadas automaticamente pelo `save`. */
|
|
754
|
+
/** Relações gerenciadas automaticamente pelo `save` e pelo `patch`. */
|
|
642
755
|
relations?: RepositoryRelations<T>;
|
|
643
756
|
/** Mapa dos métodos dinâmicos e suas regras de validação. */
|
|
644
757
|
methods?: {
|
|
@@ -651,16 +764,12 @@ export type ValidateRepoConfig<T extends object, M extends Prisma.ModelName, Con
|
|
|
651
764
|
};
|
|
652
765
|
|
|
653
766
|
/**
|
|
654
|
-
*
|
|
655
|
-
*
|
|
656
|
-
* Use esta função para declarar `tableName`, `pkName`, `selectModels`,
|
|
657
|
-
* `requiredWhere`, `relations` e `methods` do seu repository.
|
|
767
|
+
* Função para inicializar e configurar o `repository`.
|
|
768
|
+
* As configurações passadas nele são as que serão lidas ao executar o `.build()`.
|
|
658
769
|
*/
|
|
659
770
|
export declare function setupVSRepo<T extends object, M extends Prisma.ModelName>(): <
|
|
660
771
|
const SM extends Record<string, SelectModel<M>>,
|
|
661
772
|
const Config extends RepoConfig<T, M, SM>
|
|
662
773
|
>(
|
|
663
|
-
config: Config
|
|
664
|
-
? Config
|
|
665
|
-
: ValidateRepoConfig<T, M, Config>
|
|
774
|
+
config: Config & ValidateRepoConfig<T, M, Config>
|
|
666
775
|
) => VSRepository<T, M, Config>;
|
|
@@ -1055,138 +1055,287 @@ export class VSRepository {
|
|
|
1055
1055
|
console.log(`[VSRepository] (runtime) Fatal error when trying to save on ${buildInstance.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
|
|
1056
1056
|
throw err;
|
|
1057
1057
|
}
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
if(config.baseMethods?.removeList?.active !== false) {
|
|
1061
|
+
buildInstance.removeList = async (pks, options = {}) => {
|
|
1062
|
+
let db = options?.db ?? prisma;
|
|
1063
|
+
const prismaArgs = {};
|
|
1064
|
+
|
|
1065
|
+
const where = { [buildInstance.pkName]: { in: pks } };
|
|
1066
|
+
if(buildInstance.requiredWhere && !config.baseMethods?.removeList?.ignoreRequiredWhere) {
|
|
1067
|
+
Object.assign(where, buildInstance.requiredWhere);
|
|
1068
|
+
}
|
|
1069
|
+
prismaArgs.where = where;
|
|
1069
1070
|
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
}
|
|
1082
|
-
return result;
|
|
1083
|
-
} catch (err) {
|
|
1084
|
-
console.log(`[VSRepository] (runtime) Fatal error when trying to removeList on ${buildInstance.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
|
|
1085
|
-
throw err;
|
|
1071
|
+
let start;
|
|
1072
|
+
if(showWorking){
|
|
1073
|
+
console.log(`[VSRepository] (runtime) Executing removeList on ${buildInstance.tableName}.`);
|
|
1074
|
+
console.log(`[VSRepository] (runtime) Built arguments to removeList on ${buildInstance.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
|
|
1075
|
+
start = performance.now();
|
|
1076
|
+
}
|
|
1077
|
+
try {
|
|
1078
|
+
const result = await db[buildInstance.tableName].deleteMany(prismaArgs);
|
|
1079
|
+
if(showWorking) {
|
|
1080
|
+
const end = performance.now();
|
|
1081
|
+
console.log(`[VSRepository] (runtime) Executed removeList on ${buildInstance.tableName} (took: ${(end - start).toFixed(2)}ms).`);
|
|
1086
1082
|
}
|
|
1083
|
+
return result;
|
|
1084
|
+
} catch (err) {
|
|
1085
|
+
console.log(`[VSRepository] (runtime) Fatal error when trying to removeList on ${buildInstance.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
|
|
1086
|
+
throw err;
|
|
1087
1087
|
}
|
|
1088
1088
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1089
|
+
}
|
|
1090
|
+
if(config.baseMethods?.getAll?.active !== false) {
|
|
1091
|
+
buildInstance.getAll = async (options = {}) => {
|
|
1092
|
+
let db = options?.db ?? prisma;
|
|
1093
|
+
const prismaArgs = {};
|
|
1093
1094
|
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1095
|
+
if(buildInstance.requiredWhere && !config.baseMethods?.getAll?.ignoreRequiredWhere) {
|
|
1096
|
+
prismaArgs.where = { ...buildInstance.requiredWhere };
|
|
1097
|
+
}
|
|
1097
1098
|
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1099
|
+
let selectModelKey = options?.selectModel ?? config.baseMethods?.getAll?.defaultSelect ?? buildInstance.defaultSelectModel;
|
|
1100
|
+
if(selectModelKey){
|
|
1101
|
+
prismaArgs.select = buildInstance.selectModels[selectModelKey];
|
|
1102
|
+
}
|
|
1102
1103
|
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1104
|
+
if(options.pagination) {
|
|
1105
|
+
prismaArgs.skip = options.pagination.skip;
|
|
1106
|
+
prismaArgs.take = options.pagination.take;
|
|
1107
|
+
prismaArgs.cursor = options.pagination.cursor;
|
|
1108
|
+
}
|
|
1109
|
+
if(options.order) {
|
|
1110
|
+
prismaArgs.orderBy = options.order;
|
|
1111
|
+
}
|
|
1111
1112
|
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
}
|
|
1124
|
-
return result;
|
|
1125
|
-
} catch (err) {
|
|
1126
|
-
console.log(`[VSRepository] (runtime) Fatal error when trying to getAll on ${buildInstance.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
|
|
1127
|
-
throw err;
|
|
1113
|
+
let start;
|
|
1114
|
+
if(showWorking){
|
|
1115
|
+
console.log(`[VSRepository] (runtime) Executing getAll on ${buildInstance.tableName}.`);
|
|
1116
|
+
console.log(`[VSRepository] (runtime) Built arguments to getAll on ${buildInstance.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
|
|
1117
|
+
start = performance.now();
|
|
1118
|
+
}
|
|
1119
|
+
try {
|
|
1120
|
+
const result = await db[buildInstance.tableName].findMany(prismaArgs);
|
|
1121
|
+
if(showWorking) {
|
|
1122
|
+
const end = performance.now();
|
|
1123
|
+
console.log(`[VSRepository] (runtime) Executed getAll on ${buildInstance.tableName} (took: ${(end - start).toFixed(2)}ms).`);
|
|
1128
1124
|
}
|
|
1125
|
+
return result;
|
|
1126
|
+
} catch (err) {
|
|
1127
|
+
console.log(`[VSRepository] (runtime) Fatal error when trying to getAll on ${buildInstance.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
|
|
1128
|
+
throw err;
|
|
1129
1129
|
}
|
|
1130
1130
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1131
|
+
}
|
|
1132
|
+
if(config.baseMethods?.total?.active !== false) {
|
|
1133
|
+
buildInstance.total = async (options = {}) => {
|
|
1134
|
+
let db = options?.db ?? prisma;
|
|
1135
|
+
const prismaArgs = {};
|
|
1135
1136
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1137
|
+
if(buildInstance.requiredWhere && !config.baseMethods?.total?.ignoreRequiredWhere) {
|
|
1138
|
+
prismaArgs.where = { ...buildInstance.requiredWhere };
|
|
1139
|
+
}
|
|
1139
1140
|
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1141
|
+
let start;
|
|
1142
|
+
if(showWorking){
|
|
1143
|
+
console.log(`[VSRepository] (runtime) Executing total on ${buildInstance.tableName}.`);
|
|
1144
|
+
console.log(`[VSRepository] (runtime) Built arguments to total on ${buildInstance.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
|
|
1145
|
+
start = performance.now();
|
|
1146
|
+
}
|
|
1147
|
+
try {
|
|
1148
|
+
const result = await db[buildInstance.tableName].count(prismaArgs);
|
|
1149
|
+
if(showWorking) {
|
|
1150
|
+
const end = performance.now();
|
|
1151
|
+
console.log(`[VSRepository] (runtime) Executed total on ${buildInstance.tableName} (took: ${(end - start).toFixed(2)}ms).`);
|
|
1145
1152
|
}
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1153
|
+
return result;
|
|
1154
|
+
} catch (err) {
|
|
1155
|
+
console.log(`[VSRepository] (runtime) Fatal error when trying to total on ${buildInstance.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
|
|
1156
|
+
throw err;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
if(config.baseMethods?.has?.active !== false) {
|
|
1161
|
+
buildInstance.has = async (pk, options = {}) => {
|
|
1162
|
+
let db = options?.db ?? prisma;
|
|
1163
|
+
const prismaArgs = {};
|
|
1164
|
+
|
|
1165
|
+
const where = { [buildInstance.pkName]: pk };
|
|
1166
|
+
if(buildInstance.requiredWhere && !config.baseMethods?.has?.ignoreRequiredWhere) {
|
|
1167
|
+
Object.assign(where, buildInstance.requiredWhere);
|
|
1168
|
+
}
|
|
1169
|
+
prismaArgs.where = where;
|
|
1170
|
+
prismaArgs.select = { [buildInstance.pkName]: true };
|
|
1171
|
+
|
|
1172
|
+
let start;
|
|
1173
|
+
if(showWorking){
|
|
1174
|
+
console.log(`[VSRepository] (runtime) Executing has on ${buildInstance.tableName}.`);
|
|
1175
|
+
console.log(`[VSRepository] (runtime) Built arguments to has on ${buildInstance.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
|
|
1176
|
+
start = performance.now();
|
|
1177
|
+
}
|
|
1178
|
+
try {
|
|
1179
|
+
const result = await db[buildInstance.tableName].findUnique(prismaArgs);
|
|
1180
|
+
if(showWorking) {
|
|
1181
|
+
const end = performance.now();
|
|
1182
|
+
console.log(`[VSRepository] (runtime) Executed has on ${buildInstance.tableName} (took: ${(end - start).toFixed(2)}ms).`);
|
|
1156
1183
|
}
|
|
1184
|
+
return !!result;
|
|
1185
|
+
} catch (err) {
|
|
1186
|
+
console.log(`[VSRepository] (runtime) Fatal error when trying to has on ${buildInstance.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
|
|
1187
|
+
throw err;
|
|
1157
1188
|
}
|
|
1158
1189
|
}
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1190
|
+
}
|
|
1191
|
+
if(config.baseMethods?.patch?.active !== false) {
|
|
1192
|
+
buildInstance.patch = async (pk, obj, options = {}) => {
|
|
1193
|
+
let db = options?.db ?? prisma;
|
|
1194
|
+
const prismaArgs = {};
|
|
1195
|
+
|
|
1196
|
+
let selectModelKey = options?.selectModel ?? config.baseMethods?.patch?.defaultSelect ?? buildInstance.defaultSelectModel;
|
|
1197
|
+
if(selectModelKey){
|
|
1198
|
+
prismaArgs.select = buildInstance.selectModels[selectModelKey];
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
let start;
|
|
1202
|
+
if(showWorking){
|
|
1203
|
+
console.log(`[VSRepository] (runtime) Executing patch on ${buildInstance.tableName}.`);
|
|
1204
|
+
start = performance.now();
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
try {
|
|
1208
|
+
let result;
|
|
1209
|
+
prismaArgs.data = {};
|
|
1210
|
+
|
|
1211
|
+
const keys = Object.keys(obj);
|
|
1212
|
+
for (let i = 0; i < keys.length; i++) {
|
|
1213
|
+
const key = keys[i];
|
|
1214
|
+
const field = obj[key];
|
|
1215
|
+
|
|
1216
|
+
if(field === undefined) continue;
|
|
1217
|
+
|
|
1218
|
+
if(relationsKeys.includes(key)){
|
|
1219
|
+
const relation = buildInstance.relations[key];
|
|
1220
|
+
const relationMode = relation.mode;
|
|
1221
|
+
const relationRestriction = relation.restriction;
|
|
1222
|
+
const relationPk = relation.pk;
|
|
1223
|
+
|
|
1224
|
+
if(relationMode === 'oto' || relationMode === 'mto') {
|
|
1225
|
+
if(field === null) {
|
|
1226
|
+
if(relationMode === 'oto' && relationRestriction === 'set') {
|
|
1227
|
+
prismaArgs.data[key] = { delete: true };
|
|
1228
|
+
} else if(relationMode === 'mto' && relation.nullAble) {
|
|
1229
|
+
prismaArgs.data[key] = { disconnect: true };
|
|
1230
|
+
}
|
|
1231
|
+
} else if (field !== undefined) {
|
|
1232
|
+
const relationFieldPk = field[relationPk];
|
|
1233
|
+
if(relationFieldPk){
|
|
1234
|
+
const connectOrCreate = {
|
|
1235
|
+
where: { [relationPk]: relationFieldPk },
|
|
1236
|
+
create: field
|
|
1237
|
+
};
|
|
1238
|
+
|
|
1239
|
+
if(relationRestriction === 'add') {
|
|
1240
|
+
prismaArgs.data[key] = { connectOrCreate };
|
|
1241
|
+
} else {
|
|
1242
|
+
const update = {...field};
|
|
1243
|
+
delete update[relationPk];
|
|
1244
|
+
|
|
1245
|
+
prismaArgs.data[key] = {
|
|
1246
|
+
upsert: {
|
|
1247
|
+
where: { [relationPk]: relationFieldPk },
|
|
1248
|
+
create: field,
|
|
1249
|
+
update: update
|
|
1250
|
+
}
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
} else {
|
|
1254
|
+
prismaArgs.data[key] = { create: field };
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
} else if(Array.isArray(field)) {
|
|
1258
|
+
const dataWithPk = field.filter(data=>data[relationPk]!==undefined);
|
|
1259
|
+
const dataWithoutPk = field.filter(data=>data[relationPk]===undefined);
|
|
1260
|
+
|
|
1261
|
+
const connectOrCreate = dataWithPk.map(data=>({
|
|
1262
|
+
where: { [relationPk]: data[relationPk] },
|
|
1263
|
+
create: data
|
|
1264
|
+
}));
|
|
1265
|
+
|
|
1266
|
+
if(relationRestriction === 'add') {
|
|
1267
|
+
if(relationMode === 'mtm') {
|
|
1268
|
+
prismaArgs.data[key] = {
|
|
1269
|
+
create: dataWithoutPk,
|
|
1270
|
+
connectOrCreate
|
|
1271
|
+
}
|
|
1272
|
+
} else {
|
|
1273
|
+
prismaArgs.data[key] = {
|
|
1274
|
+
create: dataWithoutPk,
|
|
1275
|
+
upsert: dataWithPk.map(data=>{
|
|
1276
|
+
const update = { ...data };
|
|
1277
|
+
delete update[relationPk];
|
|
1278
|
+
return {
|
|
1279
|
+
where: { [relationPk]: data[relationPk] },
|
|
1280
|
+
create: data, update
|
|
1281
|
+
}
|
|
1282
|
+
})
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
} else {
|
|
1286
|
+
if(relationMode === 'mtm') {
|
|
1287
|
+
prismaArgs.data[key] = {
|
|
1288
|
+
set: [],
|
|
1289
|
+
create: dataWithoutPk,
|
|
1290
|
+
connectOrCreate
|
|
1291
|
+
}
|
|
1292
|
+
} else {
|
|
1293
|
+
prismaArgs.data[key] = {
|
|
1294
|
+
deleteMany: { [relationPk]: { notIn: dataWithPk.map(data=>data[relationPk]) } },
|
|
1295
|
+
create: dataWithoutPk,
|
|
1296
|
+
upsert: dataWithPk.map(data=>{
|
|
1297
|
+
const update = { ...data };
|
|
1298
|
+
delete update[relationPk];
|
|
1299
|
+
return {
|
|
1300
|
+
where: { [relationPk]: data[relationPk] },
|
|
1301
|
+
create: data, update
|
|
1302
|
+
}
|
|
1303
|
+
})
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
} else {
|
|
1309
|
+
if (key !== buildInstance.pkName) {
|
|
1310
|
+
prismaArgs.data[key] = field;
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1164
1315
|
const where = { [buildInstance.pkName]: pk };
|
|
1165
|
-
if(buildInstance.requiredWhere && !config.baseMethods?.
|
|
1316
|
+
if(buildInstance.requiredWhere && !config.baseMethods?.patch?.ignoreRequiredWhere) {
|
|
1166
1317
|
Object.assign(where, buildInstance.requiredWhere);
|
|
1167
1318
|
}
|
|
1168
1319
|
prismaArgs.where = where;
|
|
1169
|
-
prismaArgs.select = { [buildInstance.pkName]: true };
|
|
1170
1320
|
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
console.log(`[VSRepository] (runtime) Executing has on ${buildInstance.tableName}.`);
|
|
1174
|
-
console.log(`[VSRepository] (runtime) Built arguments to has on ${buildInstance.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
|
|
1175
|
-
start = performance.now();
|
|
1321
|
+
if(showWorking) {
|
|
1322
|
+
console.log(`[VSRepository] (runtime) Built arguments to patch on ${buildInstance.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
|
|
1176
1323
|
}
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
} catch (err) {
|
|
1185
|
-
console.log(`[VSRepository] (runtime) Fatal error when trying to has on ${buildInstance.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
|
|
1186
|
-
throw err;
|
|
1324
|
+
|
|
1325
|
+
result = await db[buildInstance.tableName].update(prismaArgs);
|
|
1326
|
+
|
|
1327
|
+
if(showWorking) {
|
|
1328
|
+
const end = performance.now();
|
|
1329
|
+
const duration = (end - start).toFixed(2);
|
|
1330
|
+
console.log(`[VSRepository] (runtime) Executed patch on ${buildInstance.tableName} (took: ${duration}ms).`);
|
|
1187
1331
|
}
|
|
1332
|
+
|
|
1333
|
+
return result;
|
|
1334
|
+
} catch (err) {
|
|
1335
|
+
console.log(`[VSRepository] (runtime) Fatal error when trying to patch on ${buildInstance.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
|
|
1336
|
+
throw err;
|
|
1188
1337
|
}
|
|
1189
|
-
}
|
|
1338
|
+
}
|
|
1190
1339
|
}
|
|
1191
1340
|
|
|
1192
1341
|
buildInstance.prisma = prisma;
|