vsrepo 1.2.0 → 1.2.2
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 +103 -14
- package/VSRepository/VSRepository.d.ts +109 -39
- package/VSRepository/VSRepository.js +30 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -33,6 +33,7 @@ O VSRepository permite criar repositories fortemente tipados com:
|
|
|
33
33
|
- [Filtros de relação](#filtros-de-relação)
|
|
34
34
|
- [Sufixos de paginação e ordenação](#sufixos-de-paginação-e-ordenação)
|
|
35
35
|
- [Configuração de métodos](#configuração-de-métodos)
|
|
36
|
+
- [Aggregate e GroupBy](#aggregate-e-groupby)
|
|
36
37
|
- [Relações no save](#relações-no-save)
|
|
37
38
|
- [Transações](#transações)
|
|
38
39
|
- [Estendendo um repository](#estendendo-um-repository)
|
|
@@ -460,6 +461,7 @@ O prefixo do nome do método determina qual operação Prisma será chamada e qu
|
|
|
460
461
|
| `findListWhere` | `findMany` | `T[]` | Recebe um objeto `where` explícito como argumento |
|
|
461
462
|
| `existsBy` | `findFirst` | `boolean` | Retorna `true` se encontrar, `false` caso contrário |
|
|
462
463
|
| `countBy` | `count` | `number` | Aceita campos como filtro |
|
|
464
|
+
| `countWhere` | `count` | `number` | Recebe um objeto `where` explícito como argumento |
|
|
463
465
|
| `count` | `count` | `number` | Sem filtros de campo; aplica só `requiredWhere` e `pushWhere` |
|
|
464
466
|
| `create` | `create` | `T` | Recebe `data` como argumento |
|
|
465
467
|
| `createMany` | `createMany` | `{ count: number }` | Recebe `data` como argumento; suporta `SkipDuplicates` |
|
|
@@ -470,6 +472,8 @@ O prefixo do nome do método determina qual operação Prisma será chamada e qu
|
|
|
470
472
|
| `upsertBy` | `upsert` | `T` | Recebe `update` e `create` como argumentos |
|
|
471
473
|
| `deleteBy` | `delete` | `T` | |
|
|
472
474
|
| `deleteManyBy` | `deleteMany` | `{ count: number }` | |
|
|
475
|
+
| `aggregate` | `aggregate` | `Dinâmico` | Nome deve ser exato; recebe args nativos do Prisma; ignora `selectModels`, `pushWhere` e `requiredWhere` |
|
|
476
|
+
| `groupBy` | `groupBy` | `Dinâmico[]` | Nome deve ser exato; recebe args nativos do Prisma; ignora `selectModels`, `pushWhere` e `requiredWhere` |
|
|
473
477
|
|
|
474
478
|
---
|
|
475
479
|
|
|
@@ -724,6 +728,81 @@ methods: {
|
|
|
724
728
|
|
|
725
729
|
---
|
|
726
730
|
|
|
731
|
+
### Aggregate e GroupBy
|
|
732
|
+
|
|
733
|
+
Para utilizar operações de agrupamento e agregação do Prisma (`aggregate` e `groupBy`), você deve expô-las explicitamente na configuração dos métodos dinâmicos (`methods`):
|
|
734
|
+
|
|
735
|
+
```ts
|
|
736
|
+
const usuarioRepository = setupVSRepo<Usuario, "usuario">()({
|
|
737
|
+
tableName: "usuario",
|
|
738
|
+
pkName: "id",
|
|
739
|
+
methods: {
|
|
740
|
+
aggregate: { map: true },
|
|
741
|
+
groupBy: { map: true },
|
|
742
|
+
},
|
|
743
|
+
}).build(prisma);
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
> [!NOTE]
|
|
747
|
+
> Estes métodos devem ter exatamente esses nomes (`aggregate` e `groupBy`).
|
|
748
|
+
> Ao contrário dos outros métodos dinâmicos, eles recebem argumentos nativos do Prisma e **ignoram** as configurações de `selectModels`, `pushWhere` e `requiredWhere`.
|
|
749
|
+
|
|
750
|
+
#### Exemplo de uso do `aggregate`
|
|
751
|
+
|
|
752
|
+
O método `aggregate` permite calcular valores agregados (como média, soma, mínimo, máximo, contagem) sobre os registros:
|
|
753
|
+
|
|
754
|
+
```ts
|
|
755
|
+
const resultado = await usuarioRepository.aggregate({
|
|
756
|
+
_count: {
|
|
757
|
+
_all: true,
|
|
758
|
+
},
|
|
759
|
+
_avg: {
|
|
760
|
+
idade: true,
|
|
761
|
+
},
|
|
762
|
+
_sum: {
|
|
763
|
+
saldo: true,
|
|
764
|
+
},
|
|
765
|
+
where: {
|
|
766
|
+
ativo: true,
|
|
767
|
+
},
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
console.log(resultado._count._all); // Total de usuários ativos
|
|
771
|
+
console.log(resultado._avg.idade); // Média de idade dos usuários ativos
|
|
772
|
+
console.log(resultado._sum.saldo); // Soma dos saldos dos usuários ativos
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
#### Exemplo de uso do `groupBy`
|
|
776
|
+
|
|
777
|
+
O método `groupBy` permite agrupar registros por um ou mais campos para realizar operações de agregação em cada grupo:
|
|
778
|
+
|
|
779
|
+
```ts
|
|
780
|
+
const grupos = await usuarioRepository.groupBy({
|
|
781
|
+
by: ["status"],
|
|
782
|
+
_count: {
|
|
783
|
+
status: true,
|
|
784
|
+
},
|
|
785
|
+
_avg: {
|
|
786
|
+
idade: true,
|
|
787
|
+
},
|
|
788
|
+
having: {
|
|
789
|
+
idade: {
|
|
790
|
+
_avg: {
|
|
791
|
+
gt: 18,
|
|
792
|
+
},
|
|
793
|
+
},
|
|
794
|
+
},
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
for (const grupo of grupos) {
|
|
798
|
+
console.log(`Status: ${grupo.status}`);
|
|
799
|
+
console.log(`Quantidade: ${grupo._count.status}`);
|
|
800
|
+
console.log(`Média de Idade: ${grupo._avg.idade}`);
|
|
801
|
+
}
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
---
|
|
805
|
+
|
|
727
806
|
## Relações no save
|
|
728
807
|
|
|
729
808
|
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`:
|
|
@@ -939,8 +1018,9 @@ import type { MethodOptions, MethodOptionsModel } from "../../generated/vsrepo";
|
|
|
939
1018
|
// S = chave do select model ou false
|
|
940
1019
|
type Opts = MethodOptions<"public" | "minimal">;
|
|
941
1020
|
|
|
942
|
-
// MethodOptionsModel<
|
|
943
|
-
|
|
1021
|
+
// MethodOptionsModel<TRepo> — derivado diretamente de uma instância VSRepository configurada
|
|
1022
|
+
const usuarioVSRepo = setupVSRepo<Usuario, "usuario">()(config);
|
|
1023
|
+
type OptsModel = MethodOptionsModel<typeof usuarioVSRepo>;
|
|
944
1024
|
```
|
|
945
1025
|
|
|
946
1026
|
### Tipos de configuração
|
|
@@ -952,7 +1032,6 @@ import type {
|
|
|
952
1032
|
BuildConfig,
|
|
953
1033
|
RepositoryRelations,
|
|
954
1034
|
ExtractRelationConfig,
|
|
955
|
-
UpsertWithRelations,
|
|
956
1035
|
} from "../../generated/vsrepo";
|
|
957
1036
|
|
|
958
1037
|
// Configuração de um método dinâmico
|
|
@@ -969,18 +1048,12 @@ type UsuarioRelations = RepositoryRelations<Usuario>;
|
|
|
969
1048
|
|
|
970
1049
|
// Configuração de relação inferida a partir de um campo
|
|
971
1050
|
type PerfilRelationConfig = ExtractRelationConfig<Usuario["perfil"]>;
|
|
972
|
-
|
|
973
|
-
// Payload do save com relações
|
|
974
|
-
type UsuarioComRelacoes = UpsertWithRelations<Usuario, "usuario", typeof relations>;
|
|
975
1051
|
```
|
|
976
1052
|
|
|
977
1053
|
### Tipo do repository construído
|
|
978
1054
|
|
|
979
1055
|
```ts
|
|
980
|
-
import type {
|
|
981
|
-
|
|
982
|
-
// Tipo completo de um repository construído
|
|
983
|
-
type MeuRepo = BuiltRepository<Usuario, "usuario", typeof config, typeof buildConfig>;
|
|
1056
|
+
import type { RepositoryOf } from "../../generated/vsrepo";
|
|
984
1057
|
|
|
985
1058
|
// Inferência a partir de uma instância VSRepository (útil para injeção de dependência)
|
|
986
1059
|
const usuarioVSRepo = setupVSRepo<Usuario, "usuario">()({ ... });
|
|
@@ -1001,15 +1074,31 @@ const extension = { buscarPorDominio: (dominio: string) => Promise<Usuario[]> };
|
|
|
1001
1074
|
type UsuarioRepositoryExtended = RepositoryOf<typeof usuarioVSRepo, undefined, typeof extension>;
|
|
1002
1075
|
```
|
|
1003
1076
|
|
|
1004
|
-
###
|
|
1077
|
+
### Tipos do payload dos métodos `save` e `patch`
|
|
1078
|
+
|
|
1079
|
+
Use `SaveObject` e `PatchObject` para extrair o tipo do payload esperado pelos métodos `save` e `patch` diretamente a partir de uma instância `VSRepository` configurada. Esses tipos já levam em conta as relações configuradas.
|
|
1005
1080
|
|
|
1006
1081
|
```ts
|
|
1007
|
-
import type {
|
|
1082
|
+
import type { SaveObject, PacthObject } from "../../generated/vsrepo";
|
|
1083
|
+
|
|
1084
|
+
const usuarioVSRepo = setupVSRepo<Usuario, "usuario">()({
|
|
1085
|
+
tableName: "usuario",
|
|
1086
|
+
pkName: "id",
|
|
1087
|
+
relations: {
|
|
1088
|
+
perfil: { pk: "id", mode: "oto", restriction: "set" },
|
|
1089
|
+
postagens: { pk: "id", mode: "otm", restriction: "add" },
|
|
1090
|
+
},
|
|
1091
|
+
});
|
|
1092
|
+
|
|
1093
|
+
// Tipo do objeto aceito pelo .save()
|
|
1094
|
+
type UsuarioSavePayload = SaveObject<typeof usuarioVSRepo>;
|
|
1008
1095
|
|
|
1009
|
-
//
|
|
1010
|
-
type
|
|
1096
|
+
// Tipo do objeto aceito pelo .patch()
|
|
1097
|
+
type UsuarioPatchPayload = PacthObject<typeof usuarioVSRepo>;
|
|
1011
1098
|
```
|
|
1012
1099
|
|
|
1100
|
+
> Útil para tipar DTOs, funções auxiliares ou serviços que chamam `save`/`patch` e precisam do tipo correto do payload sem referenciar diretamente os tipos internos do Prisma.
|
|
1101
|
+
|
|
1013
1102
|
---
|
|
1014
1103
|
|
|
1015
1104
|
## API Reference
|
|
@@ -51,15 +51,22 @@ type ValidMethodPatterns =
|
|
|
51
51
|
| `createManyAndReturn${string}` | `createMany${string}`
|
|
52
52
|
| `create${string}` | `updateManyAndReturnBy${string}` | `updateManyBy${string}`
|
|
53
53
|
| `updateBy${string}` | `upsertBy${string}` | `deleteManyBy${string}`
|
|
54
|
-
| `deleteBy${string}` | `countBy${string}` | `count${string}`
|
|
55
|
-
| `findWhere${string}` | `findListWhere${string}
|
|
56
|
-
|
|
57
|
-
type StringModifiers =
|
|
58
|
-
| 'NotStartsWith' | 'StartsWith' | 'NotEndsWith' | 'EndsWith'
|
|
59
|
-
| 'NotContains' | 'Contains' | 'NotIn' | 'In' | 'Not';
|
|
54
|
+
| `deleteBy${string}` | `countBy${string}` | `count${string}` | `countWhere${string}`
|
|
55
|
+
| `findWhere${string}` | `findListWhere${string}`
|
|
56
|
+
| 'aggregate' | 'groupBy';
|
|
60
57
|
|
|
61
58
|
type StripModifier<S extends string> =
|
|
62
|
-
|
|
59
|
+
// Expansão explícita para resolver o problema do 'Insensitive'
|
|
60
|
+
S extends `${infer Base}NotStartsWithInsensitive` ? Base :
|
|
61
|
+
S extends `${infer Base}StartsWithInsensitive` ? Base :
|
|
62
|
+
S extends `${infer Base}NotEndsWithInsensitive` ? Base :
|
|
63
|
+
S extends `${infer Base}EndsWithInsensitive` ? Base :
|
|
64
|
+
S extends `${infer Base}NotContainsInsensitive` ? Base :
|
|
65
|
+
S extends `${infer Base}ContainsInsensitive` ? Base :
|
|
66
|
+
S extends `${infer Base}NotInInsensitive` ? Base :
|
|
67
|
+
S extends `${infer Base}InInsensitive` ? Base :
|
|
68
|
+
S extends `${infer Base}NotInsensitive` ? Base :
|
|
69
|
+
// Modificadores normais
|
|
63
70
|
S extends `${infer Base}NotStartsWith` ? Base :
|
|
64
71
|
S extends `${infer Base}StartsWith` ? Base :
|
|
65
72
|
S extends `${infer Base}NotEndsWith` ? Base :
|
|
@@ -93,7 +100,7 @@ type GetFieldType<T, S extends string, I> = ExtractFieldName<S> extends infer Fi
|
|
|
93
100
|
? T[FieldName][]
|
|
94
101
|
: NonNullable<T[FieldName]> extends object | any[]
|
|
95
102
|
? I extends { whereInput: infer W }
|
|
96
|
-
? FieldName extends keyof NonNullable<W> ? NonNullable<W>[FieldName] : T[FieldName]
|
|
103
|
+
? FieldName extends keyof NonNullable<W> ? Exclude<NonNullable<W>[FieldName], undefined> : T[FieldName]
|
|
97
104
|
: T[FieldName]
|
|
98
105
|
: T[FieldName]
|
|
99
106
|
: ParseRelation<S> extends [infer Rel extends keyof T, any, infer Rest extends string]
|
|
@@ -124,8 +131,6 @@ type MapToContractTypes<T, Arr extends string[], I> =
|
|
|
124
131
|
: never
|
|
125
132
|
: [];
|
|
126
133
|
|
|
127
|
-
type HasMultipleANDs<S extends string> = S extends `${string}AND${string}AND${string}` ? true : false;
|
|
128
|
-
|
|
129
134
|
type SplitAllTokens<S extends string> =
|
|
130
135
|
S extends `${infer L}AND${infer R}` ? [...SplitAllTokens<L>, ...SplitAllTokens<R>] :
|
|
131
136
|
S extends `${infer L}And${infer R}` ? [...SplitAllTokens<L>, ...SplitAllTokens<R>] :
|
|
@@ -150,20 +155,28 @@ type ResolveReturnType<M extends string, TSelected> =
|
|
|
150
155
|
M extends 'findMany' | 'createManyAndReturn' | 'updateManyAndReturnBy' | 'findListWhere' | 'findByList' ? TSelected[] :
|
|
151
156
|
M extends 'findUnique' | 'findFirst' | 'findWhere' | 'findByOne' ? TSelected | null :
|
|
152
157
|
M extends 'findUniqueOrThrow' | 'findFirstOrThrow' | 'create' | 'updateBy' | 'upsertBy' | 'deleteBy' ? TSelected :
|
|
153
|
-
M extends 'count' ? number : never;
|
|
158
|
+
M extends 'count' | 'countWhere' ? number : never;
|
|
159
|
+
|
|
160
|
+
type GetUpdateInput<I> = I extends { updateInput: infer U } ? U : unknown;
|
|
161
|
+
type GetCreateInput<I> = I extends { createInput: infer C } ? C : unknown;
|
|
162
|
+
type GetCreateManyInput<I> = I extends { createManyInput: infer CM } ? CM : unknown;
|
|
163
|
+
type GetUpdateManyInput<I> = I extends { updateManyInput: infer UM } ? UM : unknown;
|
|
164
|
+
type GetWhereInput<I> = I extends { whereInput: infer W } ? NonNullable<W> : unknown;
|
|
165
|
+
type GetCursorInput<I> = I extends { cursorInput: infer C } ? C : unknown;
|
|
166
|
+
type GetOrderByInput<I> = I extends { orderByInput: infer OB } ? OB : OrderOptions;
|
|
154
167
|
|
|
155
168
|
type ExtraArgs<M extends string, R extends string, I> = [
|
|
156
|
-
...(M extends 'upsertBy' ? [update: I
|
|
157
|
-
: M extends 'create' ? [data: I
|
|
158
|
-
: M extends 'updateBy' ? [data: I
|
|
159
|
-
: M extends 'createMany' | 'createManyAndReturn' ? [data: I
|
|
160
|
-
: M extends 'updateManyBy' | 'updateManyAndReturnBy' ? [data: I
|
|
161
|
-
: M extends 'findWhere' | 'findListWhere' ? [where: I
|
|
169
|
+
...(M extends 'upsertBy' ? [update: GetUpdateInput<I>, create: GetCreateInput<I>]
|
|
170
|
+
: M extends 'create' ? [data: GetCreateInput<I>]
|
|
171
|
+
: M extends 'updateBy' ? [data: GetUpdateInput<I>]
|
|
172
|
+
: M extends 'createMany' | 'createManyAndReturn' ? [data: GetCreateManyInput<I>]
|
|
173
|
+
: M extends 'updateManyBy' | 'updateManyAndReturnBy' ? [data: GetUpdateManyInput<I>]
|
|
174
|
+
: M extends 'findWhere' | 'findListWhere' | 'countWhere' ? [where: GetWhereInput<I>]
|
|
162
175
|
: []),
|
|
163
|
-
...(R extends `${string}PaginatedAndOrdered` ? [pagination: PaginationOptions<I
|
|
164
|
-
: R extends `${string}OrderedAndPaginated` ? [order: I
|
|
165
|
-
: R extends `${string}Paginated` ? [pagination: PaginationOptions<I
|
|
166
|
-
: R extends `${string}Ordered` ? [order: I
|
|
176
|
+
...(R extends `${string}PaginatedAndOrdered` ? [pagination: PaginationOptions<GetCursorInput<I>>, order: GetOrderByInput<I>]
|
|
177
|
+
: R extends `${string}OrderedAndPaginated` ? [order: GetOrderByInput<I>, pagination: PaginationOptions<GetCursorInput<I>>]
|
|
178
|
+
: R extends `${string}Paginated` ? [pagination: PaginationOptions<GetCursorInput<I>>]
|
|
179
|
+
: R extends `${string}Ordered` ? [order: GetOrderByInput<I>]
|
|
167
180
|
: [])
|
|
168
181
|
];
|
|
169
182
|
|
|
@@ -172,13 +185,17 @@ type PrismaDelegate<M extends Prisma.ModelName> = Uncapitalize<M> extends keyof
|
|
|
172
185
|
type FullModelType<M extends Prisma.ModelName> =
|
|
173
186
|
Prisma.Result<PrismaDelegate<M>, {}, 'findMany'> extends Array<infer U> ? U : never;
|
|
174
187
|
|
|
188
|
+
type PrecomputedSelects<M extends Prisma.ModelName, SelectModels> = {
|
|
189
|
+
[S in keyof SelectModels]: Prisma.Result<PrismaDelegate<M>, { select: SelectModels[S] }, 'findMany'> extends Array<infer U> ? U : never
|
|
190
|
+
};
|
|
191
|
+
|
|
175
192
|
type SelectedModel<M extends Prisma.ModelName, S, SelectModels> =
|
|
176
193
|
[S] extends [false]
|
|
177
194
|
? FullModelType<M>
|
|
178
195
|
: [S] extends [never]
|
|
179
196
|
? FullModelType<M>
|
|
180
197
|
: [S] extends [keyof SelectModels]
|
|
181
|
-
?
|
|
198
|
+
? PrecomputedSelects<M, SelectModels>[S]
|
|
182
199
|
: FullModelType<M>;
|
|
183
200
|
|
|
184
201
|
type CleanFields<R extends string> =
|
|
@@ -207,9 +224,18 @@ export type MethodOptions<S> = {
|
|
|
207
224
|
};
|
|
208
225
|
|
|
209
226
|
/**
|
|
210
|
-
* Versão de `MethodOptions` derivada de
|
|
227
|
+
* Versão de `MethodOptions` derivada diretamente de uma instância configurada de `VSRepository`.
|
|
228
|
+
*
|
|
229
|
+
* @template TRepo Instância de `VSRepository` configurada (use `typeof meuVSRepo`).
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* const usuarioVSRepo = setupVSRepo<Usuario, "usuario">()(config);
|
|
233
|
+
* type Opts = MethodOptionsModel<typeof usuarioVSRepo>;
|
|
211
234
|
*/
|
|
212
|
-
export type MethodOptionsModel<
|
|
235
|
+
export type MethodOptionsModel<TRepo> =
|
|
236
|
+
TRepo extends VSRepository<any, any, infer Config>
|
|
237
|
+
? MethodOptions<keyof ExtractSelectModels<Config> | false>
|
|
238
|
+
: never;
|
|
213
239
|
|
|
214
240
|
type MethodFn<MethodName extends string, T, M extends Prisma.ModelName, R extends string, SelectModels, DefaultSelect extends keyof SelectModels | false, I> =
|
|
215
241
|
<S extends keyof SelectModels | false = DefaultSelect>(...args: [...ExtractFields<T, CleanFields<R>, I>, ...ExtraArgs<MethodName, R, I>, options?: MethodOptions<S>]) => Promise<ResolveReturnType<MethodName, SelectedModel<M, S, SelectModels>>>;
|
|
@@ -217,10 +243,10 @@ type MethodFn<MethodName extends string, T, M extends Prisma.ModelName, R extend
|
|
|
217
243
|
type GetMappedMethod<K extends string, MethodConf> =
|
|
218
244
|
K extends `findBy${string}` ? (MethodConf extends { fbMode: 'one' } ? 'findByOne' : 'findByList') :
|
|
219
245
|
K extends `existsBy${string}` ? 'existsBy' :
|
|
220
|
-
K extends `findUniqueBy${string}` ? 'findUnique' :
|
|
221
246
|
K extends `findUniqueOrThrowBy${string}` ? 'findUniqueOrThrow' :
|
|
222
|
-
K extends `
|
|
247
|
+
K extends `findUniqueBy${string}` ? 'findUnique' :
|
|
223
248
|
K extends `findFirstOrThrowBy${string}` | `findFirstOrThrow${string}` ? 'findFirstOrThrow' :
|
|
249
|
+
K extends `findFirstBy${string}` | `findFirst${string}` ? 'findFirst' :
|
|
224
250
|
K extends `findManyBy${string}` | `findMany${string}` ? 'findMany' :
|
|
225
251
|
K extends `createManyAndReturn${string}` ? 'createManyAndReturn' :
|
|
226
252
|
K extends `createMany${string}` ? 'createMany' :
|
|
@@ -231,14 +257,26 @@ type GetMappedMethod<K extends string, MethodConf> =
|
|
|
231
257
|
K extends `upsertBy${string}` ? 'upsertBy' :
|
|
232
258
|
K extends `deleteManyBy${string}` ? 'deleteManyBy' :
|
|
233
259
|
K extends `deleteBy${string}` ? 'deleteBy' :
|
|
260
|
+
K extends `countWhere${string}` ? 'countWhere' :
|
|
234
261
|
K extends `countBy${string}` | `count${string}` ? 'count' :
|
|
235
262
|
K extends `findListWhere${string}` ? 'findListWhere' :
|
|
236
263
|
K extends `findWhere${string}` ? 'findWhere' :
|
|
264
|
+
K extends 'aggregate' ? 'aggregate' :
|
|
265
|
+
K extends 'groupBy' ? 'groupBy' :
|
|
237
266
|
never;
|
|
238
267
|
|
|
239
268
|
type ExtractPatternBase<K extends string> =
|
|
240
269
|
K extends `${string}By${infer R}` ? R :
|
|
241
|
-
K extends `
|
|
270
|
+
K extends `findFirstOrThrow${infer R}` ? R :
|
|
271
|
+
K extends `findFirst${infer R}` ? R :
|
|
272
|
+
K extends `findMany${infer R}` ? R :
|
|
273
|
+
K extends `createManyAndReturn${infer R}` ? R :
|
|
274
|
+
K extends `createMany${infer R}` ? R :
|
|
275
|
+
K extends `create${infer R}` ? R :
|
|
276
|
+
K extends `countWhere${infer R}` ? R :
|
|
277
|
+
K extends `count${infer R}` ? R :
|
|
278
|
+
K extends `findListWhere${infer R}` ? R :
|
|
279
|
+
K extends `findWhere${infer R}` ? R : '';
|
|
242
280
|
|
|
243
281
|
type MethodFactory<T, M extends Prisma.ModelName, K extends string, SelectModels, DefaultSelect extends keyof SelectModels | false, I, MethodConf> =
|
|
244
282
|
MethodFn<GetMappedMethod<K, MethodConf>, T, M, ExtractPatternBase<K>, SelectModels, DefaultSelect, I>;
|
|
@@ -252,10 +290,28 @@ type ExtractSelectModels<Config> = Config extends { selectModels: infer SM } ? S
|
|
|
252
290
|
type ExtractDefaultSelect<Config> = Config extends { defaultSelectModel: infer D } ? D : never;
|
|
253
291
|
type ExtractRelations<Config> = Config extends { relations: infer R } ? (R extends object ? R : {}) : {};
|
|
254
292
|
|
|
293
|
+
type AggregateMethod<M extends Prisma.ModelName> = <A extends Prisma.TypeMap['model'][M]['operations']['aggregate']['args']>(
|
|
294
|
+
prismaArgs: A,
|
|
295
|
+
options?: { db?: ClientOrTransaction }
|
|
296
|
+
) => Promise<Prisma.Result<PrismaDelegate<M>, A, 'aggregate'>>;
|
|
297
|
+
|
|
298
|
+
type GroupByMethod<M extends Prisma.ModelName> = <A extends Prisma.TypeMap['model'][M]['operations']['groupBy']['args']>(
|
|
299
|
+
prismaArgs: A,
|
|
300
|
+
options?: { db?: ClientOrTransaction }
|
|
301
|
+
) => Promise<Prisma.Result<PrismaDelegate<M>, A, 'groupBy'>>;
|
|
302
|
+
|
|
255
303
|
type DynamicMethods<T, M extends Prisma.ModelName, Config, I> = Config extends { methods: infer Methods }
|
|
256
304
|
? {
|
|
257
305
|
[K in keyof Methods as Methods[K] extends { map: true } ? K : never]: K extends string
|
|
258
|
-
?
|
|
306
|
+
? (Methods[K] extends { proxyTo: infer P extends string } ? P : K) extends infer ResolvedKey
|
|
307
|
+
? ResolvedKey extends 'aggregate'
|
|
308
|
+
? AggregateMethod<M>
|
|
309
|
+
: ResolvedKey extends 'groupBy'
|
|
310
|
+
? GroupByMethod<M>
|
|
311
|
+
: ResolvedKey extends string
|
|
312
|
+
? MethodFactory<T, M, ResolvedKey, ExtractSelectModels<Config>, ResolveSelectModel<Methods[K], Config, ExtractSelectModels<Config>>, I, Methods[K]>
|
|
313
|
+
: never
|
|
314
|
+
: never
|
|
259
315
|
: never;
|
|
260
316
|
}
|
|
261
317
|
: {};
|
|
@@ -463,7 +519,7 @@ type InjectedRemove<
|
|
|
463
519
|
/**
|
|
464
520
|
* Versão distributiva de `Omit`, preservando unions ao remover propriedades.
|
|
465
521
|
*/
|
|
466
|
-
|
|
522
|
+
type DistributiveOmit<T, K extends keyof any> = T extends any ? Omit<T, K> : never;
|
|
467
523
|
type ExtractUnionProp<T, K extends PropertyKey> = T extends any ? (K extends keyof T ? T[K] : never) : never;
|
|
468
524
|
|
|
469
525
|
type ExtractNestedCreateInput<M extends Prisma.ModelName, K extends PropertyKey> =
|
|
@@ -483,7 +539,7 @@ type RelationPayload<TField, TRelationConfig, M extends Prisma.ModelName, K exte
|
|
|
483
539
|
* Substitui os campos relacionais pelo formato compatível com os modos
|
|
484
540
|
* configurados em `relations`.
|
|
485
541
|
*/
|
|
486
|
-
|
|
542
|
+
type UpsertWithRelations<T, M extends Prisma.ModelName, TRelations> =
|
|
487
543
|
DistributiveOmit<ModelUpsertInput<M>, keyof TRelations> & {
|
|
488
544
|
[K in Extract<keyof TRelations, keyof T>]?: RelationPayload<T[K], TRelations[K], M, K>;
|
|
489
545
|
};
|
|
@@ -511,11 +567,27 @@ type RelationUpdatePayload<TField, TRelationConfig, M extends Prisma.ModelName,
|
|
|
511
567
|
* Substitui os campos relacionais pelo formato compatível com os modos
|
|
512
568
|
* configurados em `relations` para fluxos de Update.
|
|
513
569
|
*/
|
|
514
|
-
|
|
570
|
+
type UpdateWithRelations<T, M extends Prisma.ModelName, TRelations> =
|
|
515
571
|
DistributiveOmit<PrismaModelInputs<M>['updateInput'], keyof TRelations> & {
|
|
516
572
|
[K in Extract<keyof TRelations, keyof T>]?: RelationUpdatePayload<T[K], TRelations[K], M, K>;
|
|
517
573
|
};
|
|
518
574
|
|
|
575
|
+
/**
|
|
576
|
+
* Extrai o tipo de payload do método `save` a partir de uma instância de VSRepository configurada.
|
|
577
|
+
*/
|
|
578
|
+
export type SaveObject<TRepo> =
|
|
579
|
+
TRepo extends VSRepository<infer T, infer M, infer Config>
|
|
580
|
+
? UpsertWithRelations<T, M, Config extends { relations: infer R } ? (R extends object ? R : {}) : {}>
|
|
581
|
+
: never;
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Extrai o tipo de payload do método `patch` a partir de uma instância de VSRepository configurada.
|
|
585
|
+
*/
|
|
586
|
+
export type PacthObject<TRepo> =
|
|
587
|
+
TRepo extends VSRepository<infer T, infer M, infer Config>
|
|
588
|
+
? UpdateWithRelations<T, M, Config extends { relations: infer R } ? (R extends object ? R : {}) : {}>
|
|
589
|
+
: never;
|
|
590
|
+
|
|
519
591
|
type InjectedSave<
|
|
520
592
|
T, M extends Prisma.ModelName, Config, C extends BuildConfig<any> | undefined,
|
|
521
593
|
TSelects = ExtractSelectModels<Config>,
|
|
@@ -529,7 +601,7 @@ type InjectedSave<
|
|
|
529
601
|
* @returns O registro salvo com tipos refinados conforme a entrada.
|
|
530
602
|
*/
|
|
531
603
|
save<
|
|
532
|
-
O
|
|
604
|
+
O,
|
|
533
605
|
S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'save', TSelects>
|
|
534
606
|
>(
|
|
535
607
|
obj: O & UpsertWithRelations<T, M, TRelations>,
|
|
@@ -552,7 +624,7 @@ type InjectedPatch<
|
|
|
552
624
|
* @returns O registro atualizado refinado conforme a entrada.
|
|
553
625
|
*/
|
|
554
626
|
patch<
|
|
555
|
-
O
|
|
627
|
+
O,
|
|
556
628
|
S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'patch', TSelects>
|
|
557
629
|
>(
|
|
558
630
|
pk: T[TPk extends keyof T ? TPk : never],
|
|
@@ -726,7 +798,7 @@ export type RepoConfig<T, M extends Prisma.ModelName, SM extends Record<string,
|
|
|
726
798
|
*
|
|
727
799
|
* Combina métodos dinâmicos, métodos base e extensões personalizadas.
|
|
728
800
|
*/
|
|
729
|
-
|
|
801
|
+
type BuiltRepository<T extends object, M extends Prisma.ModelName, Config extends RepoConfig<T, M, any>, C extends BuildConfig<any> | undefined> = {
|
|
730
802
|
/**
|
|
731
803
|
* Estende o repository com métodos personalizados sem perder a tipagem.
|
|
732
804
|
*/
|
|
@@ -775,8 +847,8 @@ export type ValidateRepoConfig<T extends object, M extends Prisma.ModelName, Con
|
|
|
775
847
|
pkName: keyof T;
|
|
776
848
|
/** Mapa de select models disponíveis. */
|
|
777
849
|
selectModels?: SelectModels<M>;
|
|
778
|
-
/** Select model padrão. */
|
|
779
|
-
defaultSelectModel?:
|
|
850
|
+
/** Select model padrão. Deve ser uma chave dos `selectModels`. */
|
|
851
|
+
defaultSelectModel?: string;
|
|
780
852
|
/** Filtros globais aplicados às queries do repository. */
|
|
781
853
|
requiredWhere?: WhereModel<M>;
|
|
782
854
|
/** Relações gerenciadas automaticamente pelo `save` e pelo `patch`. */
|
|
@@ -784,9 +856,7 @@ export type ValidateRepoConfig<T extends object, M extends Prisma.ModelName, Con
|
|
|
784
856
|
/** Mapa dos métodos dinâmicos e suas regras de validação. */
|
|
785
857
|
methods?: {
|
|
786
858
|
[K in keyof (Config extends { methods: infer Meth } ? Meth : {})]: K extends string
|
|
787
|
-
?
|
|
788
|
-
? MethodConfig<M, Config extends { selectModels: infer SM } ? SM : any> & { proxyTo: ValidMethodPatterns }
|
|
789
|
-
: MethodConfig<M, Config extends { selectModels: infer SM } ? SM : any> & (K extends ValidMethodPatterns ? {} : { proxyTo: ValidMethodPatterns })
|
|
859
|
+
? MethodConfig<M, Config extends { selectModels: infer SM } ? SM : any> & (K extends ValidMethodPatterns ? {} : { proxyTo: ValidMethodPatterns })
|
|
790
860
|
: never;
|
|
791
861
|
};
|
|
792
862
|
};
|
|
@@ -96,7 +96,8 @@ export class VSRepository {
|
|
|
96
96
|
let existsMode = false;
|
|
97
97
|
let skipDuplicates;
|
|
98
98
|
let ignoreSkipDuplicates = true;
|
|
99
|
-
let whereIndex
|
|
99
|
+
let whereIndex;
|
|
100
|
+
let prismaArgsIndex;
|
|
100
101
|
const whereParams = [];
|
|
101
102
|
const otherParams = [];
|
|
102
103
|
|
|
@@ -131,6 +132,16 @@ export class VSRepository {
|
|
|
131
132
|
ignoreOrderByAndPagination = false;
|
|
132
133
|
ignoreSelect = true;
|
|
133
134
|
method = 'count';
|
|
135
|
+
} else if(keyToMap.startsWith('countWhere')) {
|
|
136
|
+
keyToMapReplaced = keyToMap.replace('countWhere', '');
|
|
137
|
+
ignoreOrderByAndPagination = false;
|
|
138
|
+
ignoreWhere = true;
|
|
139
|
+
onlyBaseWheres = true;
|
|
140
|
+
ignoreSelect = true;
|
|
141
|
+
method = 'count';
|
|
142
|
+
whereIndex = 0;
|
|
143
|
+
otherParams.push('where');
|
|
144
|
+
argsCount += 1;
|
|
134
145
|
} else if(keyToMap.startsWith('count')) {
|
|
135
146
|
keyToMapReplaced = keyToMap.replace('count', '');
|
|
136
147
|
ignoreOrderByAndPagination = false;
|
|
@@ -233,6 +244,22 @@ export class VSRepository {
|
|
|
233
244
|
keyToMapReplaced = keyToMap.replace('findBy', '');
|
|
234
245
|
ignoreOrderByAndPagination = false;
|
|
235
246
|
method = methods[originalKey].fbMode === 'one' ? 'findFirst' : 'findMany';
|
|
247
|
+
} else if(keyToMap === 'aggregate') {
|
|
248
|
+
keyToMapReplaced = keyToMap.replace('aggregate', '')
|
|
249
|
+
ignoreSelect = true;
|
|
250
|
+
ignoreWhere = true;
|
|
251
|
+
method = 'aggregate';
|
|
252
|
+
prismaArgsIndex = 0;
|
|
253
|
+
otherParams.push('prismaArgs');
|
|
254
|
+
argsCount++;
|
|
255
|
+
} else if(keyToMap === 'groupBy') {
|
|
256
|
+
keyToMapReplaced = keyToMap.replace('groupBy', '')
|
|
257
|
+
ignoreSelect = true;
|
|
258
|
+
ignoreWhere = true;
|
|
259
|
+
method = 'groupBy';
|
|
260
|
+
prismaArgsIndex = 0;
|
|
261
|
+
otherParams.push('prismaArgs');
|
|
262
|
+
argsCount++;
|
|
236
263
|
} else {
|
|
237
264
|
throw new VSRepoBuildError(`[VSRepository] (build) Unknown method: ${keyToMap}.`);
|
|
238
265
|
}
|
|
@@ -559,6 +586,8 @@ export class VSRepository {
|
|
|
559
586
|
}
|
|
560
587
|
|
|
561
588
|
buildInstance.vsrepocache.set(originalKey, (args, optionsSelectModel) => {
|
|
589
|
+
if (prismaArgsIndex !== undefined) return args.at(prismaArgsIndex);
|
|
590
|
+
|
|
562
591
|
const prismaArgs = {};
|
|
563
592
|
|
|
564
593
|
if(!ignoreSelect) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vsrepo",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "Uma biblioteca de repository pattern para Prisma",
|
|
5
5
|
"homepage": "https://github.com/jaobrabo123/VSRepository#readme",
|
|
6
6
|
"repository": {
|
|
@@ -38,8 +38,7 @@
|
|
|
38
38
|
"node": ">=18"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
|
-
"vsrepo": "node ./scripts/configure-prisma-import.mjs"
|
|
42
|
-
"configure:prisma-import": "node ./scripts/configure-prisma-import.mjs"
|
|
41
|
+
"vsrepo": "node ./scripts/configure-prisma-import.mjs"
|
|
43
42
|
},
|
|
44
43
|
"keywords": [
|
|
45
44
|
"prisma",
|
|
@@ -47,7 +46,8 @@
|
|
|
47
46
|
"orm",
|
|
48
47
|
"typescript",
|
|
49
48
|
"vsrepo",
|
|
50
|
-
"vsrepository"
|
|
49
|
+
"vsrepository",
|
|
50
|
+
"jparepository"
|
|
51
51
|
],
|
|
52
52
|
"author": "João Pedro Azevedo Freire Mecenas",
|
|
53
53
|
"license": "MIT",
|