vsrepo 1.3.5 → 1.3.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 +147 -137
- package/README.pt-BR.md +154 -144
- package/dist/DynamicRepository.d.ts +24 -7
- package/dist/VSRepoError.d.ts +21 -1
- package/dist/VSRepository.d.ts +36 -12
- 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 +3 -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 +4 -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/package.json +1 -1
- package/scripts/configure-prisma-import.mjs +23 -10
- 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
|
@@ -39,7 +39,7 @@ O VSRepository permite criar repositórios fortemente tipados com:
|
|
|
39
39
|
- [Include Models](#include-models)
|
|
40
40
|
- [Include bruto (options.include)](#include-bruto-optionsinclude)
|
|
41
41
|
- [Required Where](#required-where)
|
|
42
|
-
- [Ordenação padrão (Default
|
|
42
|
+
- [Ordenação padrão (Default Ordering)](#ordenação-padrão-default-ordering)
|
|
43
43
|
- [Opção `see`](#opção-see)
|
|
44
44
|
- [Métodos dinâmicos](#métodos-dinâmicos)
|
|
45
45
|
- [Prefixos disponíveis](#prefixos-disponíveis)
|
|
@@ -96,14 +96,14 @@ npx vsrepo generate \
|
|
|
96
96
|
|
|
97
97
|
**Flags disponíveis:**
|
|
98
98
|
|
|
99
|
-
| Flag | Atalho | Padrão
|
|
99
|
+
| Flag | Atalho | Padrão |
|
|
100
100
|
| ---------- | ------ | -------------------- |
|
|
101
101
|
| `--output` | `-o` | `generated/vsrepo` |
|
|
102
102
|
| `--prisma` | `-p` | `generated/prisma` |
|
|
103
103
|
|
|
104
104
|
**Arquivos gerados:**
|
|
105
105
|
|
|
106
|
-
```
|
|
106
|
+
```text
|
|
107
107
|
generated/vsrepo/
|
|
108
108
|
├── DynamicRepository.ts
|
|
109
109
|
├── DynamicRepository.types.d.ts
|
|
@@ -334,18 +334,18 @@ export class UserService {
|
|
|
334
334
|
|
|
335
335
|
Ao chamar `.build(prisma)`, os métodos base abaixo ficam automaticamente disponíveis:
|
|
336
336
|
|
|
337
|
-
| Método | Descrição
|
|
338
|
-
|
|
|
339
|
-
| `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 |
|
|
340
340
|
| `getOrThrow(pk)` | Busca um registro pela sua chave primária; lança `VSRepoRuntimeError` (código `"20727"`) se não for encontrado |
|
|
341
341
|
| `getList(pks)` | Busca múltiplos registros a partir de uma lista de chaves primárias |
|
|
342
342
|
| `save(obj)` | Cria ou atualiza — se o objeto tiver uma `pk`, realiza um `upsert`; caso contrário, um `create` |
|
|
343
343
|
| `saveList(objs)` | Salva um array de objetos em uma única transação automática |
|
|
344
344
|
| `patch(pk, obj)` | Atualiza parcialmente um registro pela sua chave primária |
|
|
345
|
-
| `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 |
|
|
346
346
|
| `merge(pk, obj)` | Busca um registro e faz um deep merge em memória — **não persiste**, retorna o objeto mesclado |
|
|
347
347
|
| `remove(pk)` | Remove um registro pela sua chave primária |
|
|
348
|
-
| `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 }` |
|
|
349
349
|
| `getAll()` | Retorna todos os registros (aceita `pagination` e `order` em `options`) |
|
|
350
350
|
| `total()` | Retorna o número total de registros |
|
|
351
351
|
| `has(pk)` | Verifica se um registro existe pela sua chave primária — retorna `boolean` |
|
|
@@ -356,12 +356,12 @@ Todos eles aceitam `options` como último argumento.
|
|
|
356
356
|
|
|
357
357
|
Quando `softRemovekName` está configurado no repositório, os métodos adicionais abaixo ficam disponíveis:
|
|
358
358
|
|
|
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 }`
|
|
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 }` |
|
|
365
365
|
|
|
366
366
|
```ts
|
|
367
367
|
const userRepository = setupVSRepo<User, "user">()(({
|
|
@@ -661,15 +661,15 @@ const user = await userRepository.findByEmail("john@email.com");
|
|
|
661
661
|
|
|
662
662
|
---
|
|
663
663
|
|
|
664
|
-
## Ordenação padrão (Default
|
|
664
|
+
## Ordenação padrão (Default Ordering)
|
|
665
665
|
|
|
666
|
-
`
|
|
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.
|
|
667
667
|
|
|
668
668
|
```ts
|
|
669
669
|
const userRepository = setupVSRepo<User, "user">()(({
|
|
670
670
|
tableName: "user",
|
|
671
671
|
pkName: "id",
|
|
672
|
-
|
|
672
|
+
defaultOrdering: { createdAt: "desc" },
|
|
673
673
|
}).build(prisma);
|
|
674
674
|
```
|
|
675
675
|
|
|
@@ -683,23 +683,23 @@ const users = await userRepository.getAll();
|
|
|
683
683
|
const paginated = await userRepository.getAll({ pagination: { take: 10 } });
|
|
684
684
|
```
|
|
685
685
|
|
|
686
|
-
**`
|
|
686
|
+
**`defaultOrdering` é ignorado quando:**
|
|
687
687
|
|
|
688
688
|
- O método usa o sufixo `Ordered`, `OrderedAndPaginated` ou `PaginatedAndOrdered` — nesses casos, o argumento `order` passado na chamada tem prioridade.
|
|
689
|
-
- 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.
|
|
690
690
|
|
|
691
691
|
```ts
|
|
692
692
|
methods: {
|
|
693
|
-
findManyPaginatedAndOrdered: { map: true }, // order vem do argumento →
|
|
694
|
-
findManyByActive: { map: true }, // sem Ordered →
|
|
693
|
+
findManyPaginatedAndOrdered: { map: true }, // order vem do argumento → defaultOrdering ignorado
|
|
694
|
+
findManyByActive: { map: true }, // sem Ordered → defaultOrdering aplicado
|
|
695
695
|
findManyByStatus: {
|
|
696
696
|
map: true,
|
|
697
|
-
|
|
697
|
+
injectOrdering: { name: "asc" }, // injectOrdering → defaultOrdering ignorado
|
|
698
698
|
},
|
|
699
699
|
}
|
|
700
700
|
```
|
|
701
701
|
|
|
702
|
-
> `
|
|
702
|
+
> `defaultOrdering` aceita o mesmo tipo do `orderBy` nativo do Prisma para o modelo — incluindo arrays de ordenações encadeadas.
|
|
703
703
|
|
|
704
704
|
---
|
|
705
705
|
|
|
@@ -708,10 +708,10 @@ methods: {
|
|
|
708
708
|
Quando `softRemovekName` está configurado, todo método aceita a opção `see` para controlar a visibilidade de registros com soft-delete:
|
|
709
709
|
|
|
710
710
|
| Valor | Comportamento |
|
|
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
|
|
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 |
|
|
715
715
|
|
|
716
716
|
```ts
|
|
717
717
|
// Retorna apenas usuários ativos (padrão)
|
|
@@ -747,39 +747,39 @@ methods: {
|
|
|
747
747
|
|
|
748
748
|
O prefixo do nome do método determina qual operação do Prisma será chamada e quais argumentos são esperados.
|
|
749
749
|
|
|
750
|
-
| Prefixo | Operação do Prisma | Retorno | Observações
|
|
751
|
-
| ---------------------------- |
|
|
752
|
-
| `findOneBy` | `findFirst`
|
|
753
|
-
| `findBy` | `findMany` / `findFirst`
|
|
754
|
-
| `findUniqueBy`
|
|
755
|
-
| `findUniqueOrThrowBy`
|
|
756
|
-
| `findFirstBy`
|
|
757
|
-
| `findFirstOrThrowBy`
|
|
758
|
-
| `findFirst`
|
|
759
|
-
| `findFirstOrThrow`
|
|
760
|
-
| `findManyBy`
|
|
761
|
-
| `findMany`
|
|
762
|
-
| `findOneWhere`
|
|
763
|
-
| `findListWhere`
|
|
764
|
-
| `existsBy`
|
|
765
|
-
| `existsWhere`
|
|
766
|
-
| `countBy`
|
|
767
|
-
| `countWhere`
|
|
768
|
-
| `count`
|
|
769
|
-
| `create`
|
|
770
|
-
| `createMany`
|
|
771
|
-
| `createManyAndReturn`
|
|
772
|
-
| `updateBy`
|
|
773
|
-
| `updateManyBy`
|
|
774
|
-
| `updateManyWhere`
|
|
775
|
-
| `updateManyAndReturnBy`
|
|
776
|
-
| `updateManyAndReturnWhere`
|
|
777
|
-
| `upsertBy`
|
|
778
|
-
| `deleteBy`
|
|
779
|
-
| `deleteManyBy`
|
|
780
|
-
| `deleteManyWhere`
|
|
781
|
-
| `aggregate`
|
|
782
|
-
| `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` |
|
|
783
783
|
|
|
784
784
|
---
|
|
785
785
|
|
|
@@ -788,28 +788,28 @@ O prefixo do nome do método determina qual operação do Prisma será chamada e
|
|
|
788
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`).
|
|
789
789
|
|
|
790
790
|
| Sufixo | Operador Prisma | Argumento obrigatório |
|
|
791
|
-
| ---------------------- |
|
|
792
|
-
| *(sem sufixo)*
|
|
793
|
-
| `Not`
|
|
794
|
-
| `In`
|
|
795
|
-
| `NotIn`
|
|
796
|
-
| `Contains`
|
|
797
|
-
| `NotContains`
|
|
798
|
-
| `StartsWith`
|
|
799
|
-
| `NotStartsWith`
|
|
800
|
-
| `EndsWith`
|
|
801
|
-
| `NotEndsWith`
|
|
802
|
-
| `GreaterThan`
|
|
803
|
-
| `GreaterThanEqual`
|
|
804
|
-
| `LessThan`
|
|
805
|
-
| `LessThanEqual`
|
|
806
|
-
| `Between`
|
|
807
|
-
| `NotBetween`
|
|
808
|
-
| `IsNull`
|
|
809
|
-
| `IsNotNull`
|
|
810
|
-
| `IsTrue`
|
|
811
|
-
| `IsFalse`
|
|
812
|
-
| `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 |
|
|
813
813
|
|
|
814
814
|
`Insensitive` é um combinador e pode ser usado junto com outro filtro de texto:
|
|
815
815
|
|
|
@@ -844,10 +844,10 @@ findByNameOptionalAndEmail // name é opcional, email é obrigatório
|
|
|
844
844
|
### Operadores lógicos
|
|
845
845
|
|
|
846
846
|
| Operador | Uso no nome | Exemplo |
|
|
847
|
-
| --------- | ---------------------------------- |
|
|
848
|
-
| `And` | entre dois campos
|
|
849
|
-
| `Or` | entre dois campos
|
|
850
|
-
| `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` |
|
|
851
851
|
|
|
852
852
|
`AND` (em maiúsculas) tem uma regra específica:
|
|
853
853
|
|
|
@@ -927,22 +927,23 @@ Gera (`findByEmailOrNameANDActiveStatusAndAgeGreaterThan`):
|
|
|
927
927
|
Permitem filtrar por campos de modelos relacionados.
|
|
928
928
|
|
|
929
929
|
> [!IMPORTANT]
|
|
930
|
+
>
|
|
930
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).
|
|
931
932
|
> - **Compatibilidade de sufixos**:
|
|
932
933
|
> - Os sufixos `Some`, `Every` e `None` só funcionam em relações **to-many** (`many-to-many` e `one-to-many`).
|
|
933
934
|
> - Os sufixos `With` e `Without` só funcionam em relações **to-one** (`one-to-one` e `many-to-one`).
|
|
934
935
|
|
|
935
|
-
| Sufixo de relação
|
|
936
|
-
|
|
|
937
|
-
| `Some`
|
|
938
|
-
| `SomeField`
|
|
939
|
-
| `EveryField`
|
|
940
|
-
| `None`
|
|
941
|
-
| `NoneField`
|
|
942
|
-
| `With`
|
|
943
|
-
| `WithField`
|
|
944
|
-
| `Without`
|
|
945
|
-
| `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 |
|
|
946
947
|
|
|
947
948
|
Considerando `user` com uma relação to-one `profile` e uma relação to-many `posts`:
|
|
948
949
|
|
|
@@ -1022,18 +1023,18 @@ Gera (`findByProfileWithout`):
|
|
|
1022
1023
|
|
|
1023
1024
|
Aplicados no **final** do nome do método, injetam automaticamente os argumentos de paginação e ordenação.
|
|
1024
1025
|
|
|
1025
|
-
| Sufixo | Argumentos adicionais
|
|
1026
|
-
|
|
|
1027
|
-
| `Paginated`
|
|
1028
|
-
| `Ordered`
|
|
1029
|
-
| `OrderedAndPaginated`
|
|
1030
|
-
| `PaginatedAndOrdered`
|
|
1026
|
+
| Sufixo | Argumentos adicionais |
|
|
1027
|
+
| ------------------------ | ---------------------------- |
|
|
1028
|
+
| `Paginated` | `(pagination)` |
|
|
1029
|
+
| `Ordered` | `(order)` |
|
|
1030
|
+
| `OrderedAndPaginated` | `(order, pagination)` |
|
|
1031
|
+
| `PaginatedAndOrdered` | `(pagination, order)` |
|
|
1031
1032
|
|
|
1032
1033
|
Para `createMany` e `createManyAndReturn`, o sufixo `SkipDuplicates` está disponível:
|
|
1033
1034
|
|
|
1034
|
-
| Sufixo | Efeito
|
|
1035
|
-
|
|
|
1036
|
-
| `SkipDuplicates`
|
|
1035
|
+
| Sufixo | Efeito |
|
|
1036
|
+
| ---------------------| ---------------------------------------------- |
|
|
1037
|
+
| `SkipDuplicates` | Ignora registros duplicados durante a inserção |
|
|
1037
1038
|
|
|
1038
1039
|
---
|
|
1039
1040
|
|
|
@@ -1077,17 +1078,17 @@ await userRepository.findManyByNameDistinctRole("John");
|
|
|
1077
1078
|
|
|
1078
1079
|
Cada entrada em `methods` aceita as seguintes opções:
|
|
1079
1080
|
|
|
1080
|
-
| Opção | Tipo
|
|
1081
|
-
|
|
|
1082
|
-
| `map`
|
|
1083
|
-
| `whereType`
|
|
1084
|
-
| `selectModel`
|
|
1085
|
-
| `fbMode`
|
|
1086
|
-
| `proxyTo`
|
|
1087
|
-
| `pushWhere`
|
|
1088
|
-
| `
|
|
1089
|
-
| `injectPagination`
|
|
1090
|
-
| `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). |
|
|
1091
1092
|
|
|
1092
1093
|
---
|
|
1093
1094
|
|
|
@@ -1169,13 +1170,13 @@ await userRepository.prisma.$transaction(async (tx) => {
|
|
|
1169
1170
|
});
|
|
1170
1171
|
```
|
|
1171
1172
|
|
|
1172
|
-
| Opção
|
|
1173
|
-
| ------------- | --------- | ------- |
|
|
1174
|
-
| `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`. |
|
|
1175
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). |
|
|
1176
1177
|
|
|
1177
1178
|
> [!NOTE]
|
|
1178
|
-
> 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`.
|
|
1179
1180
|
|
|
1180
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).
|
|
1181
1182
|
|
|
@@ -1213,29 +1214,29 @@ const userRepository = setupVSRepo<User, "user">()(({
|
|
|
1213
1214
|
|
|
1214
1215
|
**Modos de relação:**
|
|
1215
1216
|
|
|
1216
|
-
| Modo | Relação
|
|
1217
|
+
| Modo | Relação |
|
|
1217
1218
|
| ----- | ------------------ |
|
|
1218
|
-
| `oto` | um-para-um
|
|
1219
|
-
| `otm` | um-para-muitos
|
|
1220
|
-
| `mto` | muitos-para-um
|
|
1221
|
-
| `mtm` | muitos-para-muitos
|
|
1219
|
+
| `oto` | um-para-um |
|
|
1220
|
+
| `otm` | um-para-muitos |
|
|
1221
|
+
| `mto` | muitos-para-um |
|
|
1222
|
+
| `mtm` | muitos-para-muitos |
|
|
1222
1223
|
|
|
1223
1224
|
**Restrições:**
|
|
1224
1225
|
|
|
1225
|
-
| Restrição | Comportamento na atualização
|
|
1226
|
-
|
|
|
1227
|
-
| `set`
|
|
1228
|
-
| `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 |
|
|
1229
1230
|
|
|
1230
1231
|
> [!WARNING]
|
|
1231
1232
|
> **`set` significa coisas diferentes dependendo do `mode` da relação — e isso pode causar perda de dados se você não tomar cuidado.**
|
|
1232
1233
|
>
|
|
1233
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).
|
|
1234
1235
|
>
|
|
1235
|
-
> | Modo
|
|
1236
|
-
> | ----- | ------------------------------------------------ |
|
|
1236
|
+
> | Modo | `restriction: "set"` quando um item é omitido | O item continua existindo no banco de dados? |
|
|
1237
|
+
> | ----- | ------------------------------------------------ | ----------------------------------------------------- |
|
|
1237
1238
|
> | `oto` | Passar `null` no campo → **apaga** o registro relacionado (`delete: true`) | Não |
|
|
1238
|
-
> | `otm` | Itens fora da lista enviada → **apagados** (`deleteMany` com `notIn`)
|
|
1239
|
+
> | `otm` | Itens fora da lista enviada → **apagados** (`deleteMany` com `notIn`) | Não |
|
|
1239
1240
|
> | `mto` | Passar `null` no campo (com `nullable: true`) → **desvincula** (`disconnect: true`) | Sim |
|
|
1240
1241
|
> | `mtm` | Itens fora da lista enviada → **desvinculados** da tabela de junção (`set: []`) | Sim |
|
|
1241
1242
|
>
|
|
@@ -1338,14 +1339,23 @@ try {
|
|
|
1338
1339
|
|
|
1339
1340
|
**Subclasses disponíveis:**
|
|
1340
1341
|
|
|
1341
|
-
| Classe
|
|
1342
|
-
|
|
|
1343
|
-
| `VSRepoConfigError` | Configuração inválida em `setupVSRepo`
|
|
1344
|
-
| `VSRepoBuildError` | Nome de método, tipo de campo ou configuração inválida em `build`
|
|
1345
|
-
| `VSRepoExtendError` | Argumento inválido em `extend`
|
|
1346
|
-
| `
|
|
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 |
|
|
1347
1349
|
|
|
1348
|
-
`VSRepoRuntimeError` tem uma propriedade `code` para identificação programática
|
|
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):
|
|
1351
|
+
|
|
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. |
|
|
1349
1359
|
|
|
1350
1360
|
---
|
|
1351
1361
|
|
|
@@ -1378,7 +1388,7 @@ import type {
|
|
|
1378
1388
|
IncludeModel,
|
|
1379
1389
|
IncludeModels,
|
|
1380
1390
|
WhereModel,
|
|
1381
|
-
|
|
1391
|
+
OrderingModel,
|
|
1382
1392
|
PaginationModel,
|
|
1383
1393
|
ModelUpsertInput,
|
|
1384
1394
|
PrismaModelInputs,
|
|
@@ -1461,7 +1471,7 @@ setupVSRepo<TPayload, TTableName>()({
|
|
|
1461
1471
|
defaultSelectModel?: keyof SM; // Select aplicado por padrão
|
|
1462
1472
|
includeModels?: IncludeModels<M>; // Projeções de dados nomeadas (include) — sem padrão, apenas na chamada
|
|
1463
1473
|
requiredWhere?: WhereModel<M>; // Filtros sempre aplicados
|
|
1464
|
-
|
|
1474
|
+
defaultOrdering?: OrderingModel<M>; // Ordenação padrão para queries sem Ordered/injectOrdering
|
|
1465
1475
|
relations?: RepositoryRelations<T>; // Configuração de relações
|
|
1466
1476
|
methods?: Record<string, MethodConfig<M, SM>>; // Métodos dinâmicos
|
|
1467
1477
|
});
|
|
@@ -1512,7 +1522,7 @@ repo.extend((repo) => ({
|
|
|
1512
1522
|
|
|
1513
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.
|
|
1514
1524
|
|
|
1515
|
-
```
|
|
1525
|
+
```text
|
|
1516
1526
|
examples/
|
|
1517
1527
|
├── prisma.ts # Instância do PrismaClient usada pelos exemplos
|
|
1518
1528
|
├── repositories.ts # Configuração dos repositórios (User, Address, Product) com setupVSRepo
|
|
@@ -1583,7 +1593,7 @@ Para reportar problemas ou sugerir novas funcionalidades, abra uma **Issue**.
|
|
|
1583
1593
|
|
|
1584
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.
|
|
1585
1595
|
|
|
1586
|
-
**`
|
|
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.
|
|
1587
1597
|
|
|
1588
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.
|
|
1589
1599
|
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
ExtractNestedUpdateInput,
|
|
9
9
|
IncludeModel,
|
|
10
10
|
ModelUpsertInput,
|
|
11
|
-
|
|
11
|
+
OrderingModel,
|
|
12
12
|
PaginationModel,
|
|
13
13
|
PaginationOptions,
|
|
14
14
|
PrismaModelInputs,
|
|
@@ -224,12 +224,23 @@ export interface DynamicRepositoryConstructorConfig<T, U extends PrismaModelName
|
|
|
224
224
|
|
|
225
225
|
/**
|
|
226
226
|
* Default ordering automatically injected into all queries that accept `orderBy`,
|
|
227
|
-
* unless the method already has `
|
|
227
|
+
* unless the method already has `injectOrdering` configured or uses the `Ordered` suffix.
|
|
228
228
|
*
|
|
229
229
|
* Useful for ensuring a consistent sort order across the repository without repeating
|
|
230
230
|
* the `order` argument on every call.
|
|
231
231
|
*/
|
|
232
|
-
|
|
232
|
+
defaultOrdering?: OrderingModel<U>;
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Default ordering automatically injected into all queries that accept `orderBy`,
|
|
236
|
+
* unless the method already has `injectOrdering` configured or uses the `Ordered` suffix.
|
|
237
|
+
*
|
|
238
|
+
* Useful for ensuring a consistent sort order across the repository without repeating
|
|
239
|
+
* the `order` argument on every call.
|
|
240
|
+
*
|
|
241
|
+
* @deprecated Use `defaultOrdering` instead.
|
|
242
|
+
*/
|
|
243
|
+
defaultOrdenation?: OrderingModel<U>;
|
|
233
244
|
|
|
234
245
|
/**
|
|
235
246
|
* Configures automatic relation management.
|
|
@@ -336,10 +347,10 @@ export declare abstract class DynamicRepository<
|
|
|
336
347
|
pagination?: PaginationOptions;
|
|
337
348
|
/**
|
|
338
349
|
* Ordering to apply to the query.
|
|
339
|
-
* When omitted and `
|
|
350
|
+
* When omitted and `defaultOrdering` is configured on the repository,
|
|
340
351
|
* the default ordering is applied automatically.
|
|
341
352
|
*/
|
|
342
|
-
order?:
|
|
353
|
+
order?: OrderingModel<UName>;
|
|
343
354
|
},
|
|
344
355
|
): Promise<TEntity[]>;
|
|
345
356
|
|
|
@@ -385,7 +396,13 @@ export type DynamicMethodConfig<M extends PrismaModelName = PrismaModelName> = {
|
|
|
385
396
|
fbMode?: "one" | "list";
|
|
386
397
|
|
|
387
398
|
/** Injects a fixed ordering automatically into the query. */
|
|
388
|
-
|
|
399
|
+
injectOrdering?: OrderingModel<M>;
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Injects a fixed ordering automatically into the query.
|
|
403
|
+
* @deprecated Use `injectOrdering` instead.
|
|
404
|
+
*/
|
|
405
|
+
injectOrdenation?: OrderingModel<M>;
|
|
389
406
|
|
|
390
407
|
/** Injects a fixed pagination automatically into the query. */
|
|
391
408
|
injectPagination?: PaginationModel<M>;
|
|
@@ -406,7 +423,7 @@ export type DynamicMethodConfig<M extends PrismaModelName = PrismaModelName> = {
|
|
|
406
423
|
* `@DynamicMethod()`
|
|
407
424
|
* declare findOneByEmail: (email: string) => Promise<User | null>;
|
|
408
425
|
*
|
|
409
|
-
* @DynamicMethod<"User">({
|
|
426
|
+
* @DynamicMethod<"User">({ injectOrdering: { createdAt: "desc" } })
|
|
410
427
|
* declare findByAge: (email: number) => Promise<User[]>;
|
|
411
428
|
* }
|
|
412
429
|
* ```
|