vsrepo 1.3.4 → 1.3.6
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 +181 -137
- package/README.pt-BR.md +188 -144
- package/dist/DynamicRepository.d.ts +36 -15
- package/dist/VSRepoError.d.ts +21 -1
- package/dist/VSRepository.d.ts +126 -87
- package/dist/VSRepository.js +49 -49
- package/dist/internal/constants/dynamic-methods-key.constant.js +4 -0
- package/dist/internal/decorators/dynamic-method.decorator.js +4 -4
- package/dist/internal/decorators/query-method.decorator.js +7 -3
- package/dist/internal/entities/dynamic-method-metadata.entity.js +3 -3
- package/dist/internal/resolvers/base-methods.resolve.js +2 -2
- package/dist/internal/resolvers/dbAndPrismaArgs.resolve.js +7 -4
- package/dist/internal/resolvers/dynamic-method-customization.resolve.js +57 -0
- package/dist/internal/resolvers/dynamic-method-info.resolve.js +279 -0
- package/dist/internal/resolvers/dynamic-methods-metadata.resolve.js +2 -2
- package/dist/internal/resolvers/pretty-wheres.resolve.js +8 -8
- package/dist/internal/resolvers/types/dynamic-method-where-ops.type.js +2 -0
- package/dist/internal/utils/schemas.util.js +8 -2
- package/dist/internal/validation/constructor-config.validate.js +7 -4
- package/dist/internal/validation/method-options.validate.js +10 -3
- package/package.json +11 -2
- package/scripts/configure-prisma-import.mjs +12 -8
- package/scripts/copy-types.mjs +16 -16
- package/dist/internal/constants/dinamic-methods-key.constant.js +0 -4
- package/dist/internal/resolvers/dinamic-method-customization.resolve.js +0 -57
- package/dist/internal/resolvers/dinamic-method-info.resolve.js +0 -279
- /package/dist/internal/{resolvers/types/dinamic-method-customization.type.js → errors/types/vs-repo-runtime-error-code.type.js} +0 -0
- /package/dist/internal/resolvers/types/{dinamic-method-info.type.js → dynamic-method-customization.type.js} +0 -0
- /package/dist/internal/resolvers/types/{dinamic-method-where-ops.type.js → dynamic-method-info.type.js} +0 -0
package/README.pt-BR.md
CHANGED
|
@@ -35,10 +35,11 @@ O VSRepository permite criar repositórios fortemente tipados com:
|
|
|
35
35
|
- [Merge](#merge)
|
|
36
36
|
- [Configurando os métodos base](#configurando-os-métodos-base)
|
|
37
37
|
- [Select Models](#select-models)
|
|
38
|
+
- [Select bruto (options.select)](#select-bruto-optionsselect)
|
|
38
39
|
- [Include Models](#include-models)
|
|
39
40
|
- [Include bruto (options.include)](#include-bruto-optionsinclude)
|
|
40
41
|
- [Required Where](#required-where)
|
|
41
|
-
- [Ordenação padrão (Default
|
|
42
|
+
- [Ordenação padrão (Default Ordering)](#ordenação-padrão-default-ordering)
|
|
42
43
|
- [Opção `see`](#opção-see)
|
|
43
44
|
- [Métodos dinâmicos](#métodos-dinâmicos)
|
|
44
45
|
- [Prefixos disponíveis](#prefixos-disponíveis)
|
|
@@ -95,15 +96,17 @@ npx vsrepo generate \
|
|
|
95
96
|
|
|
96
97
|
**Flags disponíveis:**
|
|
97
98
|
|
|
98
|
-
| Flag | Atalho | Padrão
|
|
99
|
+
| Flag | Atalho | Padrão |
|
|
99
100
|
| ---------- | ------ | -------------------- |
|
|
100
101
|
| `--output` | `-o` | `generated/vsrepo` |
|
|
101
102
|
| `--prisma` | `-p` | `generated/prisma` |
|
|
102
103
|
|
|
103
104
|
**Arquivos gerados:**
|
|
104
105
|
|
|
105
|
-
```
|
|
106
|
+
```text
|
|
106
107
|
generated/vsrepo/
|
|
108
|
+
├── DynamicRepository.ts
|
|
109
|
+
├── DynamicRepository.types.d.ts
|
|
107
110
|
├── VSRepoError.ts
|
|
108
111
|
├── VSRepoError.types.d.ts
|
|
109
112
|
├── VSRepository.ts
|
|
@@ -331,18 +334,18 @@ export class UserService {
|
|
|
331
334
|
|
|
332
335
|
Ao chamar `.build(prisma)`, os métodos base abaixo ficam automaticamente disponíveis:
|
|
333
336
|
|
|
334
|
-
| Método | Descrição
|
|
335
|
-
|
|
|
336
|
-
| `get(pk)` | Busca um registro pela sua chave primária
|
|
337
|
+
| Método | Descrição |
|
|
338
|
+
| ------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
339
|
+
| `get(pk)` | Busca um registro pela sua chave primária |
|
|
337
340
|
| `getOrThrow(pk)` | Busca um registro pela sua chave primária; lança `VSRepoRuntimeError` (código `"20727"`) se não for encontrado |
|
|
338
341
|
| `getList(pks)` | Busca múltiplos registros a partir de uma lista de chaves primárias |
|
|
339
342
|
| `save(obj)` | Cria ou atualiza — se o objeto tiver uma `pk`, realiza um `upsert`; caso contrário, um `create` |
|
|
340
343
|
| `saveList(objs)` | Salva um array de objetos em uma única transação automática |
|
|
341
344
|
| `patch(pk, obj)` | Atualiza parcialmente um registro pela sua chave primária |
|
|
342
|
-
| `patchList(tuples)` | Atualiza parcialmente múltiplos registros via um array de tuplas `[pk, obj]` em uma transação automática
|
|
345
|
+
| `patchList(tuples)` | Atualiza parcialmente múltiplos registros via um array de tuplas `[pk, obj]` em uma transação automática |
|
|
343
346
|
| `merge(pk, obj)` | Busca um registro e faz um deep merge em memória — **não persiste**, retorna o objeto mesclado |
|
|
344
347
|
| `remove(pk)` | Remove um registro pela sua chave primária |
|
|
345
|
-
| `removeList(pks)` | Remove vários registros a partir de uma lista de chaves primárias — retorna `{ count }`
|
|
348
|
+
| `removeList(pks)` | Remove vários registros a partir de uma lista de chaves primárias — retorna `{ count }` |
|
|
346
349
|
| `getAll()` | Retorna todos os registros (aceita `pagination` e `order` em `options`) |
|
|
347
350
|
| `total()` | Retorna o número total de registros |
|
|
348
351
|
| `has(pk)` | Verifica se um registro existe pela sua chave primária — retorna `boolean` |
|
|
@@ -353,12 +356,12 @@ Todos eles aceitam `options` como último argumento.
|
|
|
353
356
|
|
|
354
357
|
Quando `softRemovekName` está configurado no repositório, os métodos adicionais abaixo ficam disponíveis:
|
|
355
358
|
|
|
356
|
-
| Método | Descrição
|
|
357
|
-
|
|
|
358
|
-
| `softRemove(pk)` | Marca um registro como removido, preenchendo `softRemovekName` com a data atual
|
|
359
|
-
| `softRemoveList(pks)` | Marca múltiplos registros como removidos em lote — retorna `{ count }`
|
|
360
|
-
| `restore(pk)` | Restaura um registro com soft-delete, limpando o campo `softRemovekName`
|
|
361
|
-
| `restoreList(pks)` | Restaura múltiplos registros com soft-delete em lote — retorna `{ count }`
|
|
359
|
+
| Método | Descrição |
|
|
360
|
+
| --------------------------- | ---------------------------------------------------------------------------------- |
|
|
361
|
+
| `softRemove(pk)` | Marca um registro como removido, preenchendo `softRemovekName` com a data atual |
|
|
362
|
+
| `softRemoveList(pks)` | Marca múltiplos registros como removidos em lote — retorna `{ count }` |
|
|
363
|
+
| `restore(pk)` | Restaura um registro com soft-delete, limpando o campo `softRemovekName` |
|
|
364
|
+
| `restoreList(pks)` | Restaura múltiplos registros com soft-delete em lote — retorna `{ count }` |
|
|
362
365
|
|
|
363
366
|
```ts
|
|
364
367
|
const userRepository = setupVSRepo<User, "user">()(({
|
|
@@ -531,6 +534,35 @@ const user = await userRepository.get(id, { selectModel: "minimal" });
|
|
|
531
534
|
const fullUser = await userRepository.get(id, { selectModel: false });
|
|
532
535
|
```
|
|
533
536
|
|
|
537
|
+
### Select bruto (`options.select`)
|
|
538
|
+
|
|
539
|
+
Além do `selectModel` (nomeado, pré-configurado em `selectModels`), você pode passar um `select` bruto do Prisma diretamente na chamada, sem precisar registrá-lo antecipadamente no repositório.
|
|
540
|
+
|
|
541
|
+
```ts
|
|
542
|
+
const usuario = await usuarioRepository.get(id, {
|
|
543
|
+
select: { id: true, nome: true },
|
|
544
|
+
});
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
`options.select` aceita qualquer `select` válido para o modelo Prisma do repositório — é totalmente tipado e oferece o mesmo autocomplete/validação de chamar `prisma.usuario.findMany({ select: ... })` diretamente, e o tipo de retorno do método é restrito exatamente aos campos selecionados.
|
|
548
|
+
|
|
549
|
+
**Regras e comportamento:**
|
|
550
|
+
|
|
551
|
+
- **Mutuamente exclusivo com `selectModel`, `includeModel` e `include`.** Apenas um dos quatro pode ser fornecido por chamada; os tipos garantem isso — passar mais de um é um erro em tempo de compilação.
|
|
552
|
+
- **Ad hoc, não reutilizável.** Diferente do `selectModel`, não precisa ser declarado em `selectModels`. Use-o para projeções pontuais que não justificam um select model nomeado.
|
|
553
|
+
- **Nenhum `defaultSelectModel` é aplicado.** Quando `select` é fornecido, o select padrão (`defaultSelectModel`) é ignorado e apenas o `select` bruto é enviado ao Prisma.
|
|
554
|
+
|
|
555
|
+
```ts
|
|
556
|
+
// CORRETO ✅ — apenas select bruto
|
|
557
|
+
await usuarioRepository.get(id, { select: { id: true, nome: true } });
|
|
558
|
+
|
|
559
|
+
// ERRADO ❌ — combinar select com selectModel/includeModel/include não é permitido
|
|
560
|
+
await usuarioRepository.get(id, { selectModel: "public", select: { id: true } });
|
|
561
|
+
await usuarioRepository.get(id, { include: { posts: true }, select: { id: true } });
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
> **Quando usar `selectModel` vs. `select`:** prefira `selectModel` para projeções reutilizadas em várias chamadas (definidas uma vez em `selectModels`); use `select` para projeções específicas e ocasionais que não precisam de um nome.
|
|
565
|
+
|
|
534
566
|
---
|
|
535
567
|
|
|
536
568
|
## Include Models
|
|
@@ -629,15 +661,15 @@ const user = await userRepository.findByEmail("john@email.com");
|
|
|
629
661
|
|
|
630
662
|
---
|
|
631
663
|
|
|
632
|
-
## Ordenação padrão (Default
|
|
664
|
+
## Ordenação padrão (Default Ordering)
|
|
633
665
|
|
|
634
|
-
`
|
|
666
|
+
`defaultOrdering` define uma ordenação padrão que é aplicada automaticamente em toda query que aceita `orderBy`, sem precisar repetir o argumento `order` em cada chamada.
|
|
635
667
|
|
|
636
668
|
```ts
|
|
637
669
|
const userRepository = setupVSRepo<User, "user">()(({
|
|
638
670
|
tableName: "user",
|
|
639
671
|
pkName: "id",
|
|
640
|
-
|
|
672
|
+
defaultOrdering: { createdAt: "desc" },
|
|
641
673
|
}).build(prisma);
|
|
642
674
|
```
|
|
643
675
|
|
|
@@ -651,23 +683,23 @@ const users = await userRepository.getAll();
|
|
|
651
683
|
const paginated = await userRepository.getAll({ pagination: { take: 10 } });
|
|
652
684
|
```
|
|
653
685
|
|
|
654
|
-
**`
|
|
686
|
+
**`defaultOrdering` é ignorado quando:**
|
|
655
687
|
|
|
656
688
|
- O método usa o sufixo `Ordered`, `OrderedAndPaginated` ou `PaginatedAndOrdered` — nesses casos, o argumento `order` passado na chamada tem prioridade.
|
|
657
|
-
- O método dinâmico tem `
|
|
689
|
+
- O método dinâmico tem `injectOrdering` configurado — a ordenação fixa do método tem precedência.
|
|
658
690
|
|
|
659
691
|
```ts
|
|
660
692
|
methods: {
|
|
661
|
-
findManyPaginatedAndOrdered: { map: true }, // order vem do argumento →
|
|
662
|
-
findManyByActive: { map: true }, // sem Ordered →
|
|
693
|
+
findManyPaginatedAndOrdered: { map: true }, // order vem do argumento → defaultOrdering ignorado
|
|
694
|
+
findManyByActive: { map: true }, // sem Ordered → defaultOrdering aplicado
|
|
663
695
|
findManyByStatus: {
|
|
664
696
|
map: true,
|
|
665
|
-
|
|
697
|
+
injectOrdering: { name: "asc" }, // injectOrdering → defaultOrdering ignorado
|
|
666
698
|
},
|
|
667
699
|
}
|
|
668
700
|
```
|
|
669
701
|
|
|
670
|
-
> `
|
|
702
|
+
> `defaultOrdering` aceita o mesmo tipo do `orderBy` nativo do Prisma para o modelo — incluindo arrays de ordenações encadeadas.
|
|
671
703
|
|
|
672
704
|
---
|
|
673
705
|
|
|
@@ -676,10 +708,10 @@ methods: {
|
|
|
676
708
|
Quando `softRemovekName` está configurado, todo método aceita a opção `see` para controlar a visibilidade de registros com soft-delete:
|
|
677
709
|
|
|
678
710
|
| Valor | Comportamento |
|
|
679
|
-
| ----------- |
|
|
680
|
-
| `"active"` | Retorna apenas registros que **não** foram removidos (padrão)
|
|
681
|
-
| `"removed"` | Retorna apenas registros removidos
|
|
682
|
-
| `"all"` | Retorna todos os registros, independente do status
|
|
711
|
+
| ----------- | -------------------------------------------------------------- |
|
|
712
|
+
| `"active"` | Retorna apenas registros que **não** foram removidos (padrão) |
|
|
713
|
+
| `"removed"` | Retorna apenas registros removidos |
|
|
714
|
+
| `"all"` | Retorna todos os registros, independente do status |
|
|
683
715
|
|
|
684
716
|
```ts
|
|
685
717
|
// Retorna apenas usuários ativos (padrão)
|
|
@@ -715,39 +747,39 @@ methods: {
|
|
|
715
747
|
|
|
716
748
|
O prefixo do nome do método determina qual operação do Prisma será chamada e quais argumentos são esperados.
|
|
717
749
|
|
|
718
|
-
| Prefixo | Operação do Prisma | Retorno | Observações
|
|
719
|
-
| ---------------------------- |
|
|
720
|
-
| `findOneBy` | `findFirst`
|
|
721
|
-
| `findBy` | `findMany` / `findFirst`
|
|
722
|
-
| `findUniqueBy`
|
|
723
|
-
| `findUniqueOrThrowBy`
|
|
724
|
-
| `findFirstBy`
|
|
725
|
-
| `findFirstOrThrowBy`
|
|
726
|
-
| `findFirst`
|
|
727
|
-
| `findFirstOrThrow`
|
|
728
|
-
| `findManyBy`
|
|
729
|
-
| `findMany`
|
|
730
|
-
| `findOneWhere`
|
|
731
|
-
| `findListWhere`
|
|
732
|
-
| `existsBy`
|
|
733
|
-
| `existsWhere`
|
|
734
|
-
| `countBy`
|
|
735
|
-
| `countWhere`
|
|
736
|
-
| `count`
|
|
737
|
-
| `create`
|
|
738
|
-
| `createMany`
|
|
739
|
-
| `createManyAndReturn`
|
|
740
|
-
| `updateBy`
|
|
741
|
-
| `updateManyBy`
|
|
742
|
-
| `updateManyWhere`
|
|
743
|
-
| `updateManyAndReturnBy`
|
|
744
|
-
| `updateManyAndReturnWhere`
|
|
745
|
-
| `upsertBy`
|
|
746
|
-
| `deleteBy`
|
|
747
|
-
| `deleteManyBy`
|
|
748
|
-
| `deleteManyWhere`
|
|
749
|
-
| `aggregate`
|
|
750
|
-
| `groupBy`
|
|
750
|
+
| Prefixo | Operação do Prisma | Retorno | Observações |
|
|
751
|
+
| ---------------------------- | --------------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------- |
|
|
752
|
+
| `findOneBy` | `findFirst` | `T \| null` | Retorno único. |
|
|
753
|
+
| `findBy` | `findMany` / `findFirst` | `T[]` ou `T \| null` | Padrão é lista; use `fbMode: "one"` para retorno único (**deprecated**, use `findOneBy`) |
|
|
754
|
+
| `findUniqueBy` | `findUnique` | `T \| null` | |
|
|
755
|
+
| `findUniqueOrThrowBy` | `findUniqueOrThrow` | `T` | Lança um erro se não encontrado |
|
|
756
|
+
| `findFirstBy` | `findFirst` | `T \| null` | Aceita campos como filtro |
|
|
757
|
+
| `findFirstOrThrowBy` | `findFirstOrThrow` | `T` | Aceita campos como filtro; lança um erro se não encontrado |
|
|
758
|
+
| `findFirst` | `findFirst` | `T \| null` | Sem filtros de campo; aplica apenas `requiredWhere` e `pushWhere` |
|
|
759
|
+
| `findFirstOrThrow` | `findFirstOrThrow` | `T` | Sem filtros de campo; aplica apenas `requiredWhere` e `pushWhere`; lança um erro se não encontrado |
|
|
760
|
+
| `findManyBy` | `findMany` | `T[]` | Aceita campos como filtro |
|
|
761
|
+
| `findMany` | `findMany` | `T[]` | Sem filtros de campo; aplica apenas `requiredWhere` e `pushWhere` |
|
|
762
|
+
| `findOneWhere` | `findFirst` | `T \| null` | Recebe um objeto `where` explícito como argumento |
|
|
763
|
+
| `findListWhere` | `findMany` | `T[]` | Recebe um objeto `where` explícito como argumento |
|
|
764
|
+
| `existsBy` | `findFirst` | `boolean` | Retorna `true` se encontrado, `false` caso contrário |
|
|
765
|
+
| `existsWhere` | `findFirst` | `boolean` | Recebe um objeto `where` explícito e retorna se existe |
|
|
766
|
+
| `countBy` | `count` | `number` | Aceita campos como filtro |
|
|
767
|
+
| `countWhere` | `count` | `number` | Recebe um objeto `where` explícito como argumento |
|
|
768
|
+
| `count` | `count` | `number` | Sem filtros de campo; aplica apenas `requiredWhere` e `pushWhere` |
|
|
769
|
+
| `create` | `create` | `T` | Recebe `data` como argumento |
|
|
770
|
+
| `createMany` | `createMany` | `{ count: number }` | Recebe `data` como argumento; suporta `SkipDuplicates` |
|
|
771
|
+
| `createManyAndReturn` | `createManyAndReturn` | `T[]` | Recebe `data` como argumento; suporta `SkipDuplicates` |
|
|
772
|
+
| `updateBy` | `update` | `T` | Recebe `data` como argumento |
|
|
773
|
+
| `updateManyBy` | `updateMany` | `{ count: number }` | Recebe `data` como argumento |
|
|
774
|
+
| `updateManyWhere` | `updateMany` | `{ count: number }` | Recebe um objeto `where` e um objeto `data` como argumentos |
|
|
775
|
+
| `updateManyAndReturnBy` | `updateManyAndReturn` | `T[]` | Recebe `data` como argumento |
|
|
776
|
+
| `updateManyAndReturnWhere` | `updateManyAndReturn` | `T[]` | Recebe um objeto `where` e um objeto `data` como argumentos |
|
|
777
|
+
| `upsertBy` | `upsert` | `T` | Recebe `update` e `create` como argumentos |
|
|
778
|
+
| `deleteBy` | `delete` | `T` | |
|
|
779
|
+
| `deleteManyBy` | `deleteMany` | `{ count: number }` | |
|
|
780
|
+
| `deleteManyWhere` | `deleteMany` | `{ count: number }` | Recebe um objeto `where` explícito como argumento |
|
|
781
|
+
| `aggregate` | `aggregate` | `Dynamic` | O nome deve ser exato; recebe argumentos nativos do Prisma; ignora `selectModels`, `pushWhere` e `requiredWhere` |
|
|
782
|
+
| `groupBy` | `groupBy` | `Dynamic[]` | O nome deve ser exato; recebe argumentos nativos do Prisma; ignora `selectModels`, `pushWhere` e `requiredWhere` |
|
|
751
783
|
|
|
752
784
|
---
|
|
753
785
|
|
|
@@ -756,28 +788,28 @@ O prefixo do nome do método determina qual operação do Prisma será chamada e
|
|
|
756
788
|
Filtros são sufixos aplicados ao nome do campo dentro do método. O próprio campo vem capitalizado logo após o prefixo (ou após `By`).
|
|
757
789
|
|
|
758
790
|
| Sufixo | Operador Prisma | Argumento obrigatório |
|
|
759
|
-
| ---------------------- |
|
|
760
|
-
| *(sem sufixo)*
|
|
761
|
-
| `Not`
|
|
762
|
-
| `In`
|
|
763
|
-
| `NotIn`
|
|
764
|
-
| `Contains`
|
|
765
|
-
| `NotContains`
|
|
766
|
-
| `StartsWith`
|
|
767
|
-
| `NotStartsWith`
|
|
768
|
-
| `EndsWith`
|
|
769
|
-
| `NotEndsWith`
|
|
770
|
-
| `GreaterThan`
|
|
771
|
-
| `GreaterThanEqual`
|
|
772
|
-
| `LessThan`
|
|
773
|
-
| `LessThanEqual`
|
|
774
|
-
| `Between`
|
|
775
|
-
| `NotBetween`
|
|
776
|
-
| `IsNull`
|
|
777
|
-
| `IsNotNull`
|
|
778
|
-
| `IsTrue`
|
|
779
|
-
| `IsFalse`
|
|
780
|
-
| `Insensitive`
|
|
791
|
+
| --------------------- | ---------------------- | --------------------------- |
|
|
792
|
+
| *(sem sufixo)* | igualdade (`=`) | sim |
|
|
793
|
+
| `Not` | `not` | sim |
|
|
794
|
+
| `In` | `in` | sim (array) |
|
|
795
|
+
| `NotIn` | `notIn` | sim (array) |
|
|
796
|
+
| `Contains` | `contains` | sim |
|
|
797
|
+
| `NotContains` | `not.contains` | sim |
|
|
798
|
+
| `StartsWith` | `startsWith` | sim |
|
|
799
|
+
| `NotStartsWith` | `not.startsWith` | sim |
|
|
800
|
+
| `EndsWith` | `endsWith` | sim |
|
|
801
|
+
| `NotEndsWith` | `not.endsWith` | sim |
|
|
802
|
+
| `GreaterThan` | `gt` | sim |
|
|
803
|
+
| `GreaterThanEqual` | `gte` | sim |
|
|
804
|
+
| `LessThan` | `lt` | sim |
|
|
805
|
+
| `LessThanEqual` | `lte` | sim |
|
|
806
|
+
| `Between` | `gte` + `lte` | sim (tupla `[min, max]`) |
|
|
807
|
+
| `NotBetween` | `not.gte` + `not.lte` | sim (tupla `[min, max]`) |
|
|
808
|
+
| `IsNull` | `null` | não |
|
|
809
|
+
| `IsNotNull` | `not: null` | não |
|
|
810
|
+
| `IsTrue` | `true` | não |
|
|
811
|
+
| `IsFalse` | `false` | não |
|
|
812
|
+
| `Insensitive` | `mode: 'insensitive'` | combinador |
|
|
781
813
|
|
|
782
814
|
`Insensitive` é um combinador e pode ser usado junto com outro filtro de texto:
|
|
783
815
|
|
|
@@ -812,10 +844,10 @@ findByNameOptionalAndEmail // name é opcional, email é obrigatório
|
|
|
812
844
|
### Operadores lógicos
|
|
813
845
|
|
|
814
846
|
| Operador | Uso no nome | Exemplo |
|
|
815
|
-
| --------- | ---------------------------------- |
|
|
816
|
-
| `And` | entre dois campos
|
|
817
|
-
| `Or` | entre dois campos
|
|
818
|
-
| `AND` | separa um bloco final de `AND`
|
|
847
|
+
| --------- | -------------------------------- | ---------------------------------- |
|
|
848
|
+
| `And` | entre dois campos | `findOneByIdAndEmail` |
|
|
849
|
+
| `Or` | entre dois campos | `findByNameOrEmail` |
|
|
850
|
+
| `AND` | separa um bloco final de `AND` | `findByEmailOrNameANDActiveStatus` |
|
|
819
851
|
|
|
820
852
|
`AND` (em maiúsculas) tem uma regra específica:
|
|
821
853
|
|
|
@@ -895,22 +927,23 @@ Gera (`findByEmailOrNameANDActiveStatusAndAgeGreaterThan`):
|
|
|
895
927
|
Permitem filtrar por campos de modelos relacionados.
|
|
896
928
|
|
|
897
929
|
> [!IMPORTANT]
|
|
930
|
+
>
|
|
898
931
|
> - **Tipagem de relação**: Para que o TypeScript reconheça os tipos dos campos de relação nos métodos dinâmicos, o tipo genérico da entidade passado para `setupVSRepo` deve incluir as relações estruturadas (ex.: usando o `UserGetPayload<{ include: { profile: true, posts: true } }>` do Prisma).
|
|
899
932
|
> - **Compatibilidade de sufixos**:
|
|
900
933
|
> - Os sufixos `Some`, `Every` e `None` só funcionam em relações **to-many** (`many-to-many` e `one-to-many`).
|
|
901
934
|
> - Os sufixos `With` e `Without` só funcionam em relações **to-one** (`one-to-one` e `many-to-one`).
|
|
902
935
|
|
|
903
|
-
| Sufixo de relação
|
|
904
|
-
|
|
|
905
|
-
| `Some`
|
|
906
|
-
| `SomeField`
|
|
907
|
-
| `EveryField`
|
|
908
|
-
| `None`
|
|
909
|
-
| `NoneField`
|
|
910
|
-
| `With`
|
|
911
|
-
| `WithField`
|
|
912
|
-
| `Without`
|
|
913
|
-
| `WithoutField`
|
|
936
|
+
| Sufixo de relação | Operador Prisma | Observação |
|
|
937
|
+
| ---------------------- | ---------------- | ------------------------------------------------- |
|
|
938
|
+
| `Some` | `some: {}` | A relação tem *algum* registro |
|
|
939
|
+
| `SomeField` | `some.field` | Filtra dentro dos registros da relação |
|
|
940
|
+
| `EveryField` | `every.field` | Filtra dentro dos registros da relação |
|
|
941
|
+
| `None` | `none: {}` | A relação não tem *nenhum* registro |
|
|
942
|
+
| `NoneField` | `none.field` | Filtra dentro dos registros da relação |
|
|
943
|
+
| `With` | `is: {}` | A relação existe (não é nula) |
|
|
944
|
+
| `WithField` | `is.field` | Filtra um campo dentro da relação |
|
|
945
|
+
| `Without` | `isNot: {}` | A relação não existe (é nula) |
|
|
946
|
+
| `WithoutField` | `isNot.field` | Filtra um campo dentro da relação com negação |
|
|
914
947
|
|
|
915
948
|
Considerando `user` com uma relação to-one `profile` e uma relação to-many `posts`:
|
|
916
949
|
|
|
@@ -990,18 +1023,18 @@ Gera (`findByProfileWithout`):
|
|
|
990
1023
|
|
|
991
1024
|
Aplicados no **final** do nome do método, injetam automaticamente os argumentos de paginação e ordenação.
|
|
992
1025
|
|
|
993
|
-
| Sufixo | Argumentos adicionais
|
|
994
|
-
|
|
|
995
|
-
| `Paginated`
|
|
996
|
-
| `Ordered`
|
|
997
|
-
| `OrderedAndPaginated`
|
|
998
|
-
| `PaginatedAndOrdered`
|
|
1026
|
+
| Sufixo | Argumentos adicionais |
|
|
1027
|
+
| ------------------------ | ---------------------------- |
|
|
1028
|
+
| `Paginated` | `(pagination)` |
|
|
1029
|
+
| `Ordered` | `(order)` |
|
|
1030
|
+
| `OrderedAndPaginated` | `(order, pagination)` |
|
|
1031
|
+
| `PaginatedAndOrdered` | `(pagination, order)` |
|
|
999
1032
|
|
|
1000
1033
|
Para `createMany` e `createManyAndReturn`, o sufixo `SkipDuplicates` está disponível:
|
|
1001
1034
|
|
|
1002
|
-
| Sufixo | Efeito
|
|
1003
|
-
|
|
|
1004
|
-
| `SkipDuplicates`
|
|
1035
|
+
| Sufixo | Efeito |
|
|
1036
|
+
| ---------------------| ---------------------------------------------- |
|
|
1037
|
+
| `SkipDuplicates` | Ignora registros duplicados durante a inserção |
|
|
1005
1038
|
|
|
1006
1039
|
---
|
|
1007
1040
|
|
|
@@ -1045,17 +1078,17 @@ await userRepository.findManyByNameDistinctRole("John");
|
|
|
1045
1078
|
|
|
1046
1079
|
Cada entrada em `methods` aceita as seguintes opções:
|
|
1047
1080
|
|
|
1048
|
-
| Opção | Tipo
|
|
1049
|
-
|
|
|
1050
|
-
| `map`
|
|
1051
|
-
| `whereType`
|
|
1052
|
-
| `selectModel`
|
|
1053
|
-
| `fbMode`
|
|
1054
|
-
| `proxyTo`
|
|
1055
|
-
| `pushWhere`
|
|
1056
|
-
| `
|
|
1057
|
-
| `injectPagination`
|
|
1058
|
-
| `query`
|
|
1081
|
+
| Opção | Tipo | Padrão | Descrição |
|
|
1082
|
+
| --------------------- | ---------------------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
1083
|
+
| `map` | `boolean` | — | **Obrigatório.** Define se o método será exposto no repositório. |
|
|
1084
|
+
| `whereType` | `'extending'` \| `'overwrite'` | `extending` | `extending` combina com `requiredWhere`. `overwrite` ignora `requiredWhere`. |
|
|
1085
|
+
| `selectModel` | `keyof SelectModels \| false` | — | Sobrescreve o `defaultSelectModel` para este método. |
|
|
1086
|
+
| `fbMode` | `'one'` \| `'list'` | `'list'` | (**Deprecated. Use `findOneBy`**) Apenas para `findBy`. `'one'` retorna `T \| null`; `'list'` retorna `T[]`. |
|
|
1087
|
+
| `proxyTo` | `Padrão de método válido` | — | Delega a lógica para outro padrão de método válido. |
|
|
1088
|
+
| `pushWhere` | `WhereModel<M>` | — | `where` extra adicionado à query além do `requiredWhere`. |
|
|
1089
|
+
| `injectOrdering` | `OrderingModel<M>` | — | Ordenação fixa injetada automaticamente na query. |
|
|
1090
|
+
| `injectPagination` | `PaginationModel<M>` | — | Paginação fixa injetada automaticamente na query. |
|
|
1091
|
+
| `query` | `{ value: string; modifying?: boolean }` | — | Transforma o método em um **Query Method** (SQL bruto). Ignora todas as outras opções acima — veja [Query Methods](#query-methods). |
|
|
1059
1092
|
|
|
1060
1093
|
---
|
|
1061
1094
|
|
|
@@ -1137,13 +1170,13 @@ await userRepository.prisma.$transaction(async (tx) => {
|
|
|
1137
1170
|
});
|
|
1138
1171
|
```
|
|
1139
1172
|
|
|
1140
|
-
| Opção
|
|
1141
|
-
| ------------- | --------- | ------- |
|
|
1142
|
-
| `value` | `string` | — | **Obrigatório.** SQL bruto a ser executado. Use `$1`, `$2`, ... para os placeholders dos valores em `args`.
|
|
1173
|
+
| Opção | Tipo | Padrão | Descrição |
|
|
1174
|
+
| ------------- | --------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1175
|
+
| `value` | `string` | — | **Obrigatório.** SQL bruto a ser executado. Use `$1`, `$2`, ... para os placeholders dos valores em `args`. |
|
|
1143
1176
|
| `modifying` | `boolean` | `false` | Quando `true`, executa via `$executeRawUnsafe` e o método sempre resolve para `number`. Quando `false`, executa via `$queryRawUnsafe` e o método resolve para `TReturn` (`any` por padrão, inferível via generic na chamada). |
|
|
1144
1177
|
|
|
1145
1178
|
> [!NOTE]
|
|
1146
|
-
> Diferente dos demais métodos dinâmicos, Query Methods **ignoram completamente** `selectModels`, `requiredWhere`, `pushWhere`, `whereType`, `
|
|
1179
|
+
> Diferente dos demais métodos dinâmicos, Query Methods **ignoram completamente** `selectModels`, `requiredWhere`, `pushWhere`, `whereType`, `injectOrdering`, `injectPagination` e `proxyTo` — nada disso se aplica, já que não há parsing de nome nem montagem de `where`/`select` pelo VSRepository. Nomes de métodos livres (fora dos padrões de `findBy`, `updateBy`, etc.) também **não** exigem `proxyTo`.
|
|
1147
1180
|
|
|
1148
1181
|
A mesma funcionalidade está disponível na abordagem baseada em classes através do decorator `@QueryMethod` — veja o [README-DynamicRepo.pt-BR.md](./README-DynamicRepo.pt-BR.md#o-decorator-querymethod).
|
|
1149
1182
|
|
|
@@ -1181,29 +1214,29 @@ const userRepository = setupVSRepo<User, "user">()(({
|
|
|
1181
1214
|
|
|
1182
1215
|
**Modos de relação:**
|
|
1183
1216
|
|
|
1184
|
-
| Modo | Relação
|
|
1217
|
+
| Modo | Relação |
|
|
1185
1218
|
| ----- | ------------------ |
|
|
1186
|
-
| `oto` | um-para-um
|
|
1187
|
-
| `otm` | um-para-muitos
|
|
1188
|
-
| `mto` | muitos-para-um
|
|
1189
|
-
| `mtm` | muitos-para-muitos
|
|
1219
|
+
| `oto` | um-para-um |
|
|
1220
|
+
| `otm` | um-para-muitos |
|
|
1221
|
+
| `mto` | muitos-para-um |
|
|
1222
|
+
| `mtm` | muitos-para-muitos |
|
|
1190
1223
|
|
|
1191
1224
|
**Restrições:**
|
|
1192
1225
|
|
|
1193
|
-
| Restrição | Comportamento na atualização
|
|
1194
|
-
|
|
|
1195
|
-
| `set`
|
|
1196
|
-
| `add`
|
|
1226
|
+
| Restrição | Comportamento na atualização |
|
|
1227
|
+
| ----------- | ----------------------------------------------------------- |
|
|
1228
|
+
| `set` | Substitui totalmente (remove os que não foram enviados) |
|
|
1229
|
+
| `add` | Adiciona/atualiza sem remover os existentes |
|
|
1197
1230
|
|
|
1198
1231
|
> [!WARNING]
|
|
1199
1232
|
> **`set` significa coisas diferentes dependendo do `mode` da relação — e isso pode causar perda de dados se você não tomar cuidado.**
|
|
1200
1233
|
>
|
|
1201
1234
|
> Em relações onde o registro relacionado **pertence** ao registro pai (`oto` e `otm`), "remover os que não foram enviados" significa **apagar o registro do banco de dados** (`delete`/`deleteMany`). Em relações onde o registro relacionado é **independente** (`mto` e `mtm`), "remover" significa apenas **desvincular** (`disconnect`/`set: []`) — o registro relacionado continua existindo no banco, apenas deixa de apontar para o pai (ou de estar na tabela de junção).
|
|
1202
1235
|
>
|
|
1203
|
-
> | Modo
|
|
1204
|
-
> | ----- | ------------------------------------------------ |
|
|
1236
|
+
> | Modo | `restriction: "set"` quando um item é omitido | O item continua existindo no banco de dados? |
|
|
1237
|
+
> | ----- | ------------------------------------------------ | ----------------------------------------------------- |
|
|
1205
1238
|
> | `oto` | Passar `null` no campo → **apaga** o registro relacionado (`delete: true`) | Não |
|
|
1206
|
-
> | `otm` | Itens fora da lista enviada → **apagados** (`deleteMany` com `notIn`)
|
|
1239
|
+
> | `otm` | Itens fora da lista enviada → **apagados** (`deleteMany` com `notIn`) | Não |
|
|
1207
1240
|
> | `mto` | Passar `null` no campo (com `nullable: true`) → **desvincula** (`disconnect: true`) | Sim |
|
|
1208
1241
|
> | `mtm` | Itens fora da lista enviada → **desvinculados** da tabela de junção (`set: []`) | Sim |
|
|
1209
1242
|
>
|
|
@@ -1306,14 +1339,23 @@ try {
|
|
|
1306
1339
|
|
|
1307
1340
|
**Subclasses disponíveis:**
|
|
1308
1341
|
|
|
1309
|
-
| Classe
|
|
1310
|
-
|
|
|
1311
|
-
| `VSRepoConfigError` | Configuração inválida em `setupVSRepo`
|
|
1312
|
-
| `VSRepoBuildError` | Nome de método, tipo de campo ou configuração inválida em `build`
|
|
1313
|
-
| `VSRepoExtendError` | Argumento inválido em `extend`
|
|
1314
|
-
| `
|
|
1342
|
+
| Classe | Quando é lançada |
|
|
1343
|
+
| ------------------------- | -------------------------------------------------------------------- |
|
|
1344
|
+
| `VSRepoConfigError` | Configuração inválida em `setupVSRepo` |
|
|
1345
|
+
| `VSRepoBuildError` | Nome de método, tipo de campo ou configuração inválida em `build` |
|
|
1346
|
+
| `VSRepoExtendError` | Argumento inválido em `extend` |
|
|
1347
|
+
| `VSRepoDecoratorError` | Argumento inválido passado para `@DynamicMethod` ou `@QueryMethod` |
|
|
1348
|
+
| `VSRepoRuntimeError` | Erro em tempo de execução durante uma operação |
|
|
1349
|
+
|
|
1350
|
+
`VSRepoRuntimeError` tem uma propriedade `code: VSRepoRuntimeErrorCode` para identificação programática, sem precisar fazer parsing da mensagem (legível por humanos, e possivelmente localizada):
|
|
1315
1351
|
|
|
1316
|
-
|
|
1352
|
+
| Código | Significado |
|
|
1353
|
+
| ------ | ----------- |
|
|
1354
|
+
| `"65706"` | Um argumento obrigatório está ausente ou tem formato inválido — ex.: `pk` ausente, `pks`/`objs`/`tuples` que não são um array, ou `options`/`obj` que não são um objeto válido. |
|
|
1355
|
+
| `"20727"` | Nenhum registro foi encontrado para a primary key informada (`getOrThrow` ao buscar o registro base). |
|
|
1356
|
+
| `"67542"` | A validação (zod) de `options` de um método, ou de um argumento de `@QueryMethod`, falhou. |
|
|
1357
|
+
| `"91868"` | Uma relação passada em `save`/`patch`/`merge` tem formato inválido para o `mode`/`restriction` configurados (ex.: `null` numa relação `mtm`/`otm`, ou um array numa relação `oto`/`mto`). |
|
|
1358
|
+
| `"48670"` | Um método dinâmico (`config.methods`) foi chamado com menos argumentos posicionais do que os campos do `where` exigem. |
|
|
1317
1359
|
|
|
1318
1360
|
---
|
|
1319
1361
|
|
|
@@ -1346,7 +1388,7 @@ import type {
|
|
|
1346
1388
|
IncludeModel,
|
|
1347
1389
|
IncludeModels,
|
|
1348
1390
|
WhereModel,
|
|
1349
|
-
|
|
1391
|
+
OrderingModel,
|
|
1350
1392
|
PaginationModel,
|
|
1351
1393
|
ModelUpsertInput,
|
|
1352
1394
|
PrismaModelInputs,
|
|
@@ -1367,6 +1409,8 @@ type OptsModel = MethodOptionsModel<typeof userVSRepo>;
|
|
|
1367
1409
|
```
|
|
1368
1410
|
|
|
1369
1411
|
> O segundo parâmetro de `MethodOptions` (`IM`) representa as chaves válidas de `includeModels`. Quando informado, `selectModel` e `includeModel` se tornam mutuamente exclusivos no tipo — não é possível passar os dois na mesma chamada.
|
|
1412
|
+
>
|
|
1413
|
+
> `MethodOptions` também aceita mais dois parâmetros genéricos, `RI` e `RS`, para tipar `include` e `select` brutos respectivamente (ambos com padrão `never`, ou seja, não são aceitos a menos que tipados explicitamente): `MethodOptions<"public", "withPosts", "usuario", IncludeModel<"usuario">, SelectModel<"usuario">>`. O `MethodOptionsModel`, derivado diretamente de um repositório configurado, não expõe `RI`/`RS` — use `MethodOptions` diretamente se precisar tipar as opções de `include`/`select` brutos.
|
|
1370
1414
|
|
|
1371
1415
|
### Tipos de configuração
|
|
1372
1416
|
|
|
@@ -1427,7 +1471,7 @@ setupVSRepo<TPayload, TTableName>()({
|
|
|
1427
1471
|
defaultSelectModel?: keyof SM; // Select aplicado por padrão
|
|
1428
1472
|
includeModels?: IncludeModels<M>; // Projeções de dados nomeadas (include) — sem padrão, apenas na chamada
|
|
1429
1473
|
requiredWhere?: WhereModel<M>; // Filtros sempre aplicados
|
|
1430
|
-
|
|
1474
|
+
defaultOrdering?: OrderingModel<M>; // Ordenação padrão para queries sem Ordered/injectOrdering
|
|
1431
1475
|
relations?: RepositoryRelations<T>; // Configuração de relações
|
|
1432
1476
|
methods?: Record<string, MethodConfig<M, SM>>; // Métodos dinâmicos
|
|
1433
1477
|
});
|
|
@@ -1478,7 +1522,7 @@ repo.extend((repo) => ({
|
|
|
1478
1522
|
|
|
1479
1523
|
Além deste README, o repositório tem uma pasta **[`examples/`](https://github.com/jaobrabo123/VSRepository/tree/main/examples)** com exemplos práticos, comentados e prontos para executar — é o melhor lugar para ver o VSRepository sendo usado em cenários reais.
|
|
1480
1524
|
|
|
1481
|
-
```
|
|
1525
|
+
```text
|
|
1482
1526
|
examples/
|
|
1483
1527
|
├── prisma.ts # Instância do PrismaClient usada pelos exemplos
|
|
1484
1528
|
├── repositories.ts # Configuração dos repositórios (User, Address, Product) com setupVSRepo
|
|
@@ -1549,7 +1593,7 @@ Para reportar problemas ou sugerir novas funcionalidades, abra uma **Issue**.
|
|
|
1549
1593
|
|
|
1550
1594
|
**`softRemovekName` lança um erro no build** — O campo informado deve ser do tipo `DateTime` no schema do Prisma. Tipos como `Boolean` ou `String` não são aceitos.
|
|
1551
1595
|
|
|
1552
|
-
**`
|
|
1596
|
+
**`defaultOrdering` não está sendo aplicado** — Verifique se o método usa o sufixo `Ordered`, `OrderedAndPaginated` ou `PaginatedAndOrdered`, e se tem `injectOrdering` configurado. Ambos têm prioridade sobre a ordenação padrão.
|
|
1553
1597
|
|
|
1554
1598
|
**Sufixo `Distinct` não é reconhecido** — `Distinct` só é resolvido em prefixos de leitura (`findMany`, `findFirst`, `findBy`, `existsBy`, etc). Em métodos como `count`, `createMany`, `updateMany` ou `deleteMany` o sufixo é ignorado.
|
|
1555
1599
|
|