vsrepo 1.1.0 → 1.1.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 CHANGED
@@ -7,7 +7,7 @@ Biblioteca de repository pattern para projetos que usam **Prisma**, com suporte
7
7
 
8
8
  O VSRepository permite criar repositories fortemente tipados com:
9
9
 
10
- - **Métodos base** automáticos: `get`, `save`, `remove`
10
+ - **Métodos base** automáticos: `get`, `getOrThrow`, `save`, `remove`, `removeList`, `getAll`, `total`, `has`
11
11
  - **Métodos dinâmicos** inferidos pelo nome: `findByEmail`, `findManyPaginated`, `updateById`, `deleteManyByIdIn`
12
12
  - **Select models** reutilizáveis para diferentes projeções de dados
13
13
  - **Type safety** em 100% das operações
@@ -24,7 +24,7 @@ O VSRepository permite criar repositories fortemente tipados com:
24
24
  - [Integração com NestJS](#integração-com-nestjs)
25
25
  - [Métodos base](#métodos-base)
26
26
  - [Select Models](#select-models)
27
- - [requiredWhere](#requiredwhere)
27
+ - [Required Where](#requiredwhere)
28
28
  - [Métodos dinâmicos](#métodos-dinâmicos)
29
29
  - [Prefixos disponíveis](#prefixos-disponíveis)
30
30
  - [Filtros de campo](#filtros-de-campo)
@@ -38,6 +38,7 @@ O VSRepository permite criar repositories fortemente tipados com:
38
38
  - [Tratamento de erros](#tratamento-de-erros)
39
39
  - [Tipos utilitários](#tipos-utilitários)
40
40
  - [API Reference](#api-reference)
41
+ - [Contribuindo](#contribuindo)
41
42
  - [Requisitos](#requisitos)
42
43
  - [Troubleshooting](#troubleshooting)
43
44
 
@@ -94,9 +95,11 @@ src/generated/vsrepo/
94
95
  Após gerar, importe sempre a partir da pasta gerada:
95
96
 
96
97
  ```ts
98
+ // CORRETO ✅
97
99
  import { setupVSRepo } from "../generated/vsrepo";
98
- // ou
99
- import { setupVSRepo, type SelectModels, type WhereModel } from "../generated/vsrepo";
100
+
101
+ // ERRADO ❌
102
+ import { setupVSRepo } from "vsrepo";
100
103
  ```
101
104
 
102
105
  ---
@@ -128,22 +131,11 @@ import type { Usuario } from "../generated/prisma/client";
128
131
  const usuarioRepository = setupVSRepo<Usuario, "usuario">()({
129
132
  tableName: "usuario",
130
133
  pkName: "id",
131
-
132
134
  selectModels: {
133
135
  public: { id: true, nome: true, email: true },
134
- minimal: { id: true },
135
136
  },
136
137
  defaultSelectModel: "public",
137
-
138
138
  requiredWhere: { ativo: true },
139
-
140
- methods: {
141
- findByEmail: { map: true, fbMode: "one" },
142
- findManyPaginated: { map: true },
143
- updateById: { map: true },
144
- deleteManyByIdIn: { map: true, whereType: "overwrite" },
145
- count: { map: true },
146
- },
147
139
  }).build(prisma);
148
140
 
149
141
  export default usuarioRepository;
@@ -163,9 +155,11 @@ const usuario = await usuarioRepository.save({
163
155
  });
164
156
 
165
157
  const encontrado = await usuarioRepository.get(usuario.id);
166
- const porEmail = await usuarioRepository.findByEmail("joao@email.com");
158
+ const todos = await usuarioRepository.getAll();
159
+
160
+ usuario.nome = "Joao Pedro";
167
161
 
168
- await usuarioRepository.updateById(usuario.id, { nome: "Joao Pedro" });
162
+ await usuarioRepository.save(usuario);
169
163
  await usuarioRepository.remove(usuario.id);
170
164
  ```
171
165
 
@@ -182,7 +176,7 @@ O VSRepository pode ser facilmente integrado em projetos NestJS através de prov
182
176
  import { Provider } from "@nestjs/common";
183
177
  import { PrismaService } from "../../database/prisma.service";
184
178
  import { UserGetPayload } from "../../generated/prisma/models";
185
- import { RepositoryOf, setupVSRepo } from "../../generated/vsrepo";
179
+ import { setupVSRepo } from "../../generated/vsrepo";
186
180
 
187
181
  const userVSRepo = setupVSRepo<
188
182
  UserGetPayload<{ include: { profile: true } }>,
@@ -220,19 +214,28 @@ const userVSRepo = setupVSRepo<
220
214
  proxyTo: "findUniqueByEmail",
221
215
  selectModel: "auth",
222
216
  },
217
+ findByEmailEndsWith: {
218
+ map: true,
219
+ }
223
220
  },
224
221
  });
225
222
 
226
- export type UserRepository = RepositoryOf<typeof userVSRepo>;
223
+ const setupUserRepository = (prisma: PrismaService) => {
224
+ return userVSRepo.build(prisma).extend((repo) => ({
225
+ buscarPorDominio: async (dominio: string) => {
226
+ return repo.findByEmailEndsWith(`@${dominio}`);
227
+ },
228
+ }));
229
+ };
230
+
231
+ export type UserRepository = ReturnType<typeof setupUserRepository>;
227
232
 
228
233
  export const USER_REPOSITORY = Symbol("USER_REPOSITORY");
229
234
 
230
235
  export const UserRepositoryProvider: Provider = {
231
236
  provide: USER_REPOSITORY,
232
237
  inject: [PrismaService],
233
- useFactory: (prisma: PrismaService) => {
234
- return userVSRepo.build(prisma);
235
- },
238
+ useFactory: setupUserRepository,
236
239
  };
237
240
  ```
238
241
 
@@ -323,22 +326,27 @@ export class UserController {
323
326
 
324
327
  ## Métodos base
325
328
 
326
- Ao chamar `.build(prisma)`, três métodos são automaticamente disponibilizados:
329
+ Ao chamar `.build(prisma)` os métodos base abaixo são automaticamente disponibilizados:
327
330
 
328
331
  | Método | Descrição |
329
332
  | ------------ | ------------------------------------------ |
330
333
  | `get(pk)` | Busca um registro pela primary key |
331
- | `save(obj)` | Cria ou atualiza (upsert pela primary key) |
334
+ | `getOrThrow(pk)` | Busca um registro pela primary key e lança erro se não encontrar |
335
+ | `save(obj)` | Cria ou atualiza (se o objeto passado tiver a `pk` faz `upsert`, se não faz `create`) |
332
336
  | `remove(pk)` | Remove um registro pela primary key |
337
+ | `removeList(pks)` | Remove vários registros pela lista de primary keys — retorna `{ count }` |
338
+ | `getAll()` | Retorna todos os registros (aceita `pagination` e `order` no `options`) |
339
+ | `total()` | Retorna o total de registros |
340
+ | `has(pk)` | Verifica existência de um registro pela primary key — retorna `boolean` |
333
341
 
334
- Todos aceitam `options?: { selectModel?, db? }` como último argumento.
342
+ Todos aceitam `options` como último argumento.
335
343
 
336
344
  ### Configurando os métodos base
337
345
 
338
346
  ```ts
339
347
  usuarioVSRepo.build(prisma, {
340
- freeze: true, // Congela o objeto (padrão: true)
341
- showWorking: false, // Exibe logs do VSRepository no console, ótimo para debugar as queries criadas e os objetos passados para o prisma
348
+ freeze: true, // Congela o objeto (padrão = true)
349
+ showWorking: true, // Exibe logs do VSRepository no console, ótimo para debugar as queries criadas e os objetos passados para o prisma
342
350
 
343
351
  baseMethods: {
344
352
  get: {
@@ -350,9 +358,11 @@ usuarioVSRepo.build(prisma, {
350
358
  defaultSelect: "minimal",
351
359
  },
352
360
  save: {
353
- active: true,
354
- ignoreRequiredWhere: true, // Não aplica requiredWhere no upsert
361
+ ignoreRequiredWhere: true, // Não aplica requiredWhere no save
355
362
  },
363
+ has: {
364
+ active: false, // Desativa o 'has' (padrão = true)
365
+ }
356
366
  },
357
367
  });
358
368
  ```
@@ -388,7 +398,7 @@ const usuarioCompleto = await usuarioRepository.get(id, { selectModel: false });
388
398
 
389
399
  ---
390
400
 
391
- ## requiredWhere
401
+ ## Required Where
392
402
 
393
403
  `requiredWhere` define filtros aplicados automaticamente em todas as queries do repository.
394
404
 
@@ -433,8 +443,11 @@ O prefixo do nome do método determina qual operação Prisma será chamada e qu
433
443
  | ------------------------- | ------------------------ | ---------------------- | -------------------------------------------------------- |
434
444
  | `findBy` | `findMany` / `findFirst` | `T[]` ou `T \| null` | Padrão é lista; use `fbMode: "one"` para retorno único |
435
445
  | `findUniqueBy` | `findUnique` | `T \| null` | |
446
+ | `findUniqueOrThrowBy` | `findUniqueOrThrow` | `T` | Lança erro se não encontrar |
436
447
  | `findFirstBy` | `findFirst` | `T \| null` | Aceita campos como filtro |
448
+ | `findFirstOrThrowBy` | `findFirstOrThrow` | `T` | Aceita campos como filtro; lança erro se não encontrar |
437
449
  | `findFirst` | `findFirst` | `T \| null` | Sem filtros de campo; aplica só `requiredWhere` e `pushWhere` |
450
+ | `findFirstOrThrow` | `findFirstOrThrow` | `T` | Sem filtros de campo; aplica só `requiredWhere` e `pushWhere`; lança erro se não encontrar |
438
451
  | `findManyBy` | `findMany` | `T[]` | Aceita campos como filtro |
439
452
  | `findMany` | `findMany` | `T[]` | Sem filtros de campo; aplica só `requiredWhere` e `pushWhere` |
440
453
  | `findWhere` | `findFirst` | `T \| null` | Recebe um objeto `where` explícito como argumento |
@@ -474,10 +487,10 @@ Os filtros são sufixos aplicados ao nome do campo dentro do método. O campo em
474
487
  | `GreaterThanEqual` | `gte` | sim |
475
488
  | `LessThan` | `lt` | sim |
476
489
  | `LessThanEqual` | `lte` | sim |
477
- | `IsNull` | `null` | não (zero-arg) |
478
- | `IsNotNull` | `not: null` | não (zero-arg) |
479
- | `IsTrue` | `true` | não (zero-arg) |
480
- | `IsFalse` | `false` | não (zero-arg) |
490
+ | `IsNull` | `null` | não |
491
+ | `IsNotNull` | `not: null` | não |
492
+ | `IsTrue` | `true` | não |
493
+ | `IsFalse` | `false` | não |
481
494
  | `Insensitive` | `mode: 'insensitive'` | combinador |
482
495
 
483
496
  `Insensitive` é um combinador e pode ser usado junto com outro filtro de texto:
@@ -820,7 +833,7 @@ try {
820
833
 
821
834
  | Classe | Quando é lançada |
822
835
  | -------------------- | ------------------------------------------------------- |
823
- | `VSRepoConfigError` | Configuração inválida em `setupVSRepo` ou `build` |
836
+ | `VSRepoConfigError` | Configuração inválida em `setupVSRepo` |
824
837
  | `VSRepoBuildError` | Nome de método inválido ou desconhecido no `build` |
825
838
  | `VSRepoExtendError` | Argumento inválido em `extend` |
826
839
  | `VSRepoRuntimeError` | Erro em tempo de execução durante uma operação |
@@ -985,13 +998,24 @@ setupVSRepo<TPayload, TTableName>()({
985
998
 
986
999
  ```ts
987
1000
  vsRepo.build(prisma, {
988
- freeze?: boolean; // Congela o objeto (padrão: true)
989
- showWorking?: boolean; // Exibe logs internos no console
1001
+ freeze?: boolean; // Congela o objeto (default = true)
1002
+ showWorking?: boolean; // Exibe logs internos no console (default = false)
990
1003
 
1004
+ // `active` serve para definir se o método vai existir depois do build (default = true)
1005
+ // `defaultSelect` serve para definir qual `selectModel` esse método vai usar por default (default = `defaultSelectModel` definido no `setupVSRepo`)
1006
+ // `ignoreRequiredWhere` serve para definir se o método vai ignorar o `requiredWhere` definido no `setupVSRepo` (default = false)
991
1007
  baseMethods?: {
992
- get?: { active?: boolean; defaultSelect?: string };
993
- remove?: { active?: boolean; defaultSelect?: string };
994
- save?: { active?: boolean; ignoreRequiredWhere?: boolean };
1008
+ // Métodos que podem utilizar um `defaultSelect`
1009
+ get?: { active?: boolean; defaultSelect?: string; ignoreRequiredWhere?: boolean };
1010
+ getOrThrow?:{ active?: boolean; defaultSelect?: string; ignoreRequiredWhere?: boolean };
1011
+ remove?: { active?: boolean; defaultSelect?: string; ignoreRequiredWhere?: boolean };
1012
+ save?: { active?: boolean; defaultSelect?: string; ignoreRequiredWhere?: boolean };
1013
+ getAll?: { active?: boolean; defaultSelect?: string; ignoreRequiredWhere?: boolean };
1014
+
1015
+ // Métodos que NÃO aceitam `defaultSelect`
1016
+ removeList?: { active?: boolean; ignoreRequiredWhere?: boolean };
1017
+ total?: { active?: boolean; ignoreRequiredWhere?: boolean };
1018
+ has?: { active?: boolean; ignoreRequiredWhere?: boolean };
995
1019
  };
996
1020
  });
997
1021
  ```
@@ -1000,12 +1024,25 @@ vsRepo.build(prisma, {
1000
1024
 
1001
1025
  ```ts
1002
1026
  repo.extend((repo) => ({
1003
- meuMetodo() { ... }
1027
+ meuMetodo: () => { ... }
1004
1028
  }));
1005
1029
  ```
1006
1030
 
1007
1031
  ---
1008
1032
 
1033
+ ## Contribuindo
1034
+
1035
+ Contribuições são bem-vindas! Se você encontrou um bug, tem uma ideia de melhoria ou quer ajudar com a documentação, sinta-se à vontade para participar (**[Repositório do GitHub](https://github.com/jaobrabo123/VSRepository)**):
1036
+
1037
+ 1. Faça um **Fork** do projeto.
1038
+ 2. Crie uma nova branch com a sua alteração: `git checkout -b corrigindo-bug`.
1039
+ 3. Faça o push para a sua branch: `git push origin corrigindo-bug`.
1040
+ 4. Abra um **Pull Request**.
1041
+
1042
+ Para reportar problemas ou sugerir novas funcionalidades, abra uma **Issue**.
1043
+
1044
+ ---
1045
+
1009
1046
  ## Requisitos
1010
1047
 
1011
1048
  - Node.js 16+ (ESM)
@@ -1038,4 +1075,4 @@ repo.extend((repo) => ({
1038
1075
 
1039
1076
  **`proxyTo` obrigatório** — Nomes fora dos moldes (ex.: `buscarPorEmail`) não são parseados diretamente. Use `proxyTo: "findByEmail"` nesses casos.
1040
1077
 
1041
- **Select model retorna campos inesperados** — Verifique se o select model define exatamente os campos que o seu tipo TypeScript espera. Campos com `false` não serão retornados pelo Prisma.
1078
+ **Select model retorna campos inesperados** — Verifique se o select model define exatamente os campos que o seu tipo TypeScript espera. Campos com `false` não serão retornados pelo Prisma.
@@ -0,0 +1,84 @@
1
+ import { VSRepoConfigError } from "./VSRepoError.js";
2
+
3
+ export class FieldValidator {
4
+ constructor(throws) {
5
+ this.throws = throws;
6
+ }
7
+
8
+ validate(
9
+ field,
10
+ fieldName,
11
+ mustBe,
12
+ undefinedAble,
13
+ nullAble,
14
+ customReason
15
+ ) {
16
+ if (field === undefined) {
17
+ if (undefinedAble) return;
18
+ throw this.instanceError(fieldName, customReason ?? "cannot be undefined");
19
+ }
20
+
21
+ if (field === null) {
22
+ if (nullAble) return;
23
+ throw this.instanceError(fieldName, customReason ?? "cannot be null");
24
+ }
25
+
26
+ const condition = typeof mustBe === "function" ? !mustBe(field) : typeof field !== mustBe;
27
+
28
+ if(condition) {
29
+ throw this.instanceError(fieldName, customReason ?? `must be a valid ${mustBe}`);
30
+ };
31
+ }
32
+
33
+ instanceError(fieldName, reason) {
34
+ const error = new this.throws("");
35
+ error.message = `[VSRepository] (${error.type}) '${fieldName}' ${reason}.`;
36
+ return error;
37
+ }
38
+ }
39
+
40
+ export function validateConfig(config) {
41
+ const validator = new FieldValidator(VSRepoConfigError);
42
+
43
+ validator.validate(config, "config", "object");
44
+ validator.validate(config.tableName, "tableName", "string");
45
+ validator.validate(config.pkName, "pkName", "string");
46
+ validator.validate(config.selectModels, "selectModels", "object", true);
47
+
48
+ if(config.defaultSelectModel !== undefined) {
49
+ validator.validate(config.defaultSelectModel, "defaultSelectModel", "string");
50
+
51
+ validator.validate(config.defaultSelectModel, "defaultSelectModel", (field) => {
52
+ return !!(config.selectModels && Object.keys(config.selectModels).includes(config.defaultSelectModel))
53
+ }, false, false, "must be a valid key of 'selectModels'");
54
+ }
55
+
56
+ if(config.relations !== undefined) {
57
+ validator.validate(config.relations, "relations", "object");
58
+
59
+ for (const key of Object.keys(config.relations)) {
60
+ const relation = config.relations[key];
61
+
62
+ validator.validate(relation.pk, "pk", "string", false, false, `of relation '${key}' must be a string`);
63
+ validator.validate(relation.mode, "mode", (field) => ['otm', 'mtm', 'mto', 'oto'].includes(field), false, false, `of relation '${key}' must be 'otm', 'mtm', 'mto' or 'oto'`);
64
+ validator.validate(relation.restriction, "restriction", (field) => ['set', 'add'].includes(field), false, false, `of relation '${key}' must be 'set' or 'add'`);
65
+ }
66
+ }
67
+
68
+ validator.validate(config.requiredWhere, "requiredWhere", "object", true);
69
+
70
+ if(config.methods !== undefined) {
71
+ validator.validate(config.methods, "methods", "object");
72
+
73
+ for (const [key, value] of Object.entries(config.methods)) {
74
+ validator.validate(value.map, "map", "boolean", false, false, `on ${key} must be a valid boolean`);
75
+ validator.validate(value.whereType, "whereType", (field) => ['extending', 'overwrite'].includes(field), true, false, `on ${key} must be 'extending' or 'overwrite'`);
76
+ validator.validate(value.selectModel, "selectModel", (field) => !!(field === false || (config.selectModels && Object.keys(config.selectModels).includes(field))), true, false, `on ${key} must be a valid key of 'selectModels'`);
77
+ validator.validate(value.proxyTo, "proxyTo", "string", true, false, `on ${key} must be a valid string`);
78
+ validator.validate(value.fbMode, "fbMode", (field) => ['one', 'list'].includes(field), true, false, `on ${key} must be 'one' or 'list'`);
79
+ validator.validate(value.pushWhere, "pushWhere", "object", true, false, `on ${key} must be a valid object`);
80
+ validator.validate(value.injectOrdenation, "injectOrdenation", "object", true, false, `on ${key} must be a valid object or array`);
81
+ validator.validate(value.injectPagination, "injectPagination", "object", true, false, `on ${key} must be a valid object`);
82
+ }
83
+ }
84
+ }
@@ -43,9 +43,12 @@ export type PaginationOptions<TCursor = unknown> = {
43
43
  export type OrderOptions = OrderPattern | OrderPattern[];
44
44
 
45
45
  type ValidMethodPatterns =
46
- | `existsBy${string}` | `findBy${string}` | `findUniqueBy${string}`
47
- | `findFirstBy${string}` | `findFirst${string}` | `findManyBy${string}`
48
- | `findMany${string}` | `createManyAndReturn${string}` | `createMany${string}`
46
+ | `existsBy${string}` | `findBy${string}`
47
+ | `findUniqueBy${string}` | `findUniqueOrThrowBy${string}`
48
+ | `findFirstBy${string}` | `findFirst${string}`
49
+ | `findFirstOrThrowBy${string}` | `findFirstOrThrow${string}`
50
+ | `findManyBy${string}` | `findMany${string}`
51
+ | `createManyAndReturn${string}` | `createMany${string}`
49
52
  | `create${string}` | `updateManyAndReturnBy${string}` | `updateManyBy${string}`
50
53
  | `updateBy${string}` | `upsertBy${string}` | `deleteManyBy${string}`
51
54
  | `deleteBy${string}` | `countBy${string}` | `count${string}`
@@ -55,9 +58,6 @@ type StringModifiers =
55
58
  | 'NotStartsWith' | 'StartsWith' | 'NotEndsWith' | 'EndsWith'
56
59
  | 'NotContains' | 'Contains' | 'NotIn' | 'In' | 'Not';
57
60
 
58
- type NumberModifiers =
59
- | 'LessThanEqual' | 'LessThan' | 'GreaterThanEqual' | 'GreaterThan';
60
-
61
61
  type StripModifier<S extends string> =
62
62
  S extends `${infer Base}${StringModifiers}Insensitive` ? Base :
63
63
  S extends `${infer Base}NotStartsWith` ? Base :
@@ -149,7 +149,7 @@ type ResolveReturnType<M extends string, TSelected> =
149
149
  M extends 'createMany' | 'updateManyBy' | 'deleteManyBy' ? { count: number } :
150
150
  M extends 'findMany' | 'createManyAndReturn' | 'updateManyAndReturnBy' | 'findListWhere' | 'findByList' ? TSelected[] :
151
151
  M extends 'findUnique' | 'findFirst' | 'findWhere' | 'findByOne' ? TSelected | null :
152
- M extends 'create' | 'updateBy' | 'upsertBy' | 'deleteBy' ? TSelected :
152
+ M extends 'findUniqueOrThrow' | 'findFirstOrThrow' | 'create' | 'updateBy' | 'upsertBy' | 'deleteBy' ? TSelected :
153
153
  M extends 'count' ? number : never;
154
154
 
155
155
  type ExtraArgs<M extends string, R extends string, I> = [
@@ -218,7 +218,9 @@ type GetMappedMethod<K extends string, MethodConf> =
218
218
  K extends `findBy${string}` ? (MethodConf extends { fbMode: 'one' } ? 'findByOne' : 'findByList') :
219
219
  K extends `existsBy${string}` ? 'existsBy' :
220
220
  K extends `findUniqueBy${string}` ? 'findUnique' :
221
+ K extends `findUniqueOrThrowBy${string}` ? 'findUniqueOrThrow' :
221
222
  K extends `findFirstBy${string}` | `findFirst${string}` ? 'findFirst' :
223
+ K extends `findFirstOrThrowBy${string}` | `findFirstOrThrow${string}` ? 'findFirstOrThrow' :
222
224
  K extends `findManyBy${string}` | `findMany${string}` ? 'findMany' :
223
225
  K extends `createManyAndReturn${string}` ? 'createManyAndReturn' :
224
226
  K extends `createMany${string}` ? 'createMany' :
@@ -236,7 +238,7 @@ type GetMappedMethod<K extends string, MethodConf> =
236
238
 
237
239
  type ExtractPatternBase<K extends string> =
238
240
  K extends `${string}By${infer R}` ? R :
239
- K extends `findFirst${infer R}` | `findMany${infer R}` | `createManyAndReturn${infer R}` | `createMany${infer R}` | `create${infer R}` | `count${infer R}` | `findWhere${infer R}` | `findListWhere${infer R}` ? R : '';
241
+ K extends `findFirst${infer R}` | `findFirstOrThrow${infer R}` | `findMany${infer R}` | `createManyAndReturn${infer R}` | `createMany${infer R}` | `create${infer R}` | `count${infer R}` | `findWhere${infer R}` | `findListWhere${infer R}` ? R : '';
240
242
 
241
243
  type MethodFactory<T, M extends Prisma.ModelName, K extends string, SelectModels, DefaultSelect extends keyof SelectModels | false, I, MethodConf> =
242
244
  MethodFn<GetMappedMethod<K, MethodConf>, T, M, ExtractPatternBase<K>, SelectModels, DefaultSelect, I>;
@@ -346,7 +348,7 @@ type BaseMethodConfig<TSelectKeys extends PropertyKey = string> = {
346
348
  active?: boolean;
347
349
  /** Select model padrão usado pelo método base. */
348
350
  defaultSelect?: TSelectKeys;
349
- /** Ignora o `requiredWhere` no `save`. */
351
+ /** Ignora o `requiredWhere`. */
350
352
  ignoreRequiredWhere?: boolean;
351
353
  };
352
354
 
@@ -364,14 +366,24 @@ export type BuildConfig<TSelectKeys extends PropertyKey = string> = {
364
366
  baseMethods?: {
365
367
  /** Configuração do método `get`. */
366
368
  get?: BaseMethodConfig<TSelectKeys>;
369
+ /** Configuração do método `getOrThrow`. */
370
+ getOrThrow?: BaseMethodConfig<TSelectKeys>;
367
371
  /** Configuração do método `remove`. */
368
372
  remove?: BaseMethodConfig<TSelectKeys>;
369
373
  /** Configuração do método `save`. */
370
374
  save?: BaseMethodConfig<TSelectKeys>;
375
+ /** Configuração do método `removeList` (exclusão em lote). Não aceita select. */
376
+ removeList?: Omit<BaseMethodConfig<TSelectKeys>, 'defaultSelect'>;
377
+ /** Configuração do método `getAll` (listagem total). */
378
+ getAll?: BaseMethodConfig<TSelectKeys>;
379
+ /** Configuração do método `total` (contagem). Não aceita select. */
380
+ total?: Omit<BaseMethodConfig<TSelectKeys>, 'defaultSelect'>;
381
+ /** Configuração do método `has` (verificação de existência). Não aceita select. */
382
+ has?: Omit<BaseMethodConfig<TSelectKeys>, 'defaultSelect'>;
371
383
  };
372
384
  };
373
385
 
374
- type ResolveMethodDefaultSelect<Config, C, Method extends 'get' | 'remove' | 'save', TSelects = ExtractSelectModels<Config>> =
386
+ type ResolveMethodDefaultSelect<Config, C, Method extends 'get' | 'getOrThrow' | 'remove' | 'save' | 'getAll', TSelects = ExtractSelectModels<Config>> =
375
387
  C extends { baseMethods?: { [_ in Method]?: { defaultSelect?: infer D } } }
376
388
  ? D extends keyof TSelects
377
389
  ? D
@@ -406,6 +418,17 @@ type InjectedGet<
406
418
  ): Promise<ResolveCurrentReturn<M, TSelects, S, TDefault> | null>;
407
419
  };
408
420
 
421
+ type InjectedGetOrThrow<
422
+ T, M extends Prisma.ModelName, Config, C extends BuildConfig<any> | undefined,
423
+ TSelects = ExtractSelectModels<Config>,
424
+ TDefault = ExtractDefaultSelect<Config>,
425
+ TPk = ExtractPkName<T, Config>
426
+ > = C extends { baseMethods: { getOrThrow: { active: false } } } ? {} : {
427
+ getOrThrow<S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'getOrThrow', TSelects>>(
428
+ pk: T[TPk extends keyof T ? TPk : never], options?: MethodOptions<S>
429
+ ): Promise<ResolveCurrentReturn<M, TSelects, S, TDefault>>;
430
+ };
431
+
409
432
  type InjectedRemove<
410
433
  T, M extends Prisma.ModelName, Config, C extends BuildConfig<any> | undefined,
411
434
  TSelects = ExtractSelectModels<Config>,
@@ -460,10 +483,59 @@ type InjectedSave<
460
483
  ): Promise<RefineSaveResult<ResolveCurrentReturn<M, TSelects, S, TDefault>, O>>;
461
484
  };
462
485
 
486
+ type InjectedRemoveList<
487
+ T, M extends Prisma.ModelName, Config, C extends BuildConfig<any> | undefined,
488
+ TPk = ExtractPkName<T, Config>
489
+ > = C extends { baseMethods: { removeList: { active: false } } } ? {} : {
490
+ /** Remove múltiplos registros de uma vez pelas suas chaves primárias. */
491
+ removeList(
492
+ pks: T[TPk extends keyof T ? TPk : never][],
493
+ options?: { db?: ClientOrTransaction }
494
+ ): Promise<{ count: number }>;
495
+ };
496
+
497
+ type InjectedGetAll<
498
+ T, M extends Prisma.ModelName, Config, C extends BuildConfig<any> | undefined,
499
+ TSelects = ExtractSelectModels<Config>,
500
+ TDefault = ExtractDefaultSelect<Config>,
501
+ I = PrismaModelInputs<M>
502
+ > = C extends { baseMethods: { getAll: { active: false } } } ? {} : {
503
+ /** Busca todos os registros, respeitando o `requiredWhere` se houver. */
504
+ getAll<S extends keyof TSelects | false = ResolveMethodDefaultSelect<Config, C, 'getAll', TSelects>>(
505
+ options?: MethodOptions<S> & {
506
+ pagination?: PaginationOptions<I extends { cursorInput: infer Curs } ? Curs : unknown>;
507
+ order?: I extends { orderByInput: infer OB } ? OB : OrderOptions;
508
+ }
509
+ ): Promise<ResolveCurrentReturn<M, TSelects, S, TDefault>[]>;
510
+ };
511
+
512
+ type InjectedTotal<
513
+ T, M extends Prisma.ModelName, Config, C extends BuildConfig<any> | undefined
514
+ > = C extends { baseMethods: { total: { active: false } } } ? {} : {
515
+ /** Retorna a quantidade total de registros, respeitando o `requiredWhere` se houver. */
516
+ total(options?: { db?: ClientOrTransaction }): Promise<number>;
517
+ };
518
+
519
+ type InjectedHas<
520
+ T, M extends Prisma.ModelName, Config, C extends BuildConfig<any> | undefined,
521
+ TPk = ExtractPkName<T, Config>
522
+ > = C extends { baseMethods: { has: { active: false } } } ? {} : {
523
+ /** Verifica de forma otimizada se um registro existe pela chave primária. */
524
+ has(
525
+ pk: T[TPk extends keyof T ? TPk : never],
526
+ options?: { db?: ClientOrTransaction }
527
+ ): Promise<boolean>;
528
+ };
529
+
463
530
  type InjectedBaseMethods<T, M extends Prisma.ModelName, Config, C extends BuildConfig<any> | undefined> =
464
531
  InjectedGet<T, M, Config, C> &
532
+ InjectedGetOrThrow<T, M, Config, C> &
465
533
  InjectedRemove<T, M, Config, C> &
466
- InjectedSave<T, M, Config, C>;
534
+ InjectedSave<T, M, Config, C> &
535
+ InjectedRemoveList<T, M, Config, C> &
536
+ InjectedGetAll<T, M, Config, C> &
537
+ InjectedTotal<T, M, Config, C> &
538
+ InjectedHas<T, M, Config, C>;
467
539
 
468
540
  /**
469
541
  * Infere automaticamente a configuração de relação possível a partir de um campo.
@@ -8,7 +8,8 @@
8
8
  export * from "./VSRepoError.js";
9
9
 
10
10
  // * Importando classes de erro
11
- import { VSRepoConfigError, VSRepoBuildError, VSRepoExtendError, VSRepoRuntimeError } from "./VSRepoError.js";
11
+ import { VSRepoBuildError, VSRepoExtendError, VSRepoRuntimeError } from "./VSRepoError.js";
12
+ import { validateConfig } from "./VSRepoUtils.js";
12
13
 
13
14
  // * Essa é a classe pincipal, é a partir dela que serão criados os objetos dos repositories
14
15
  export class VSRepository {
@@ -28,92 +29,7 @@ export class VSRepository {
28
29
  methods;
29
30
 
30
31
  constructor(config) {
31
- if(typeof config !== 'object' || config === null){
32
- throw new VSRepoConfigError(`[VSRepository] (config) 'config' must be a valid object.`);
33
- }
34
- if(typeof config.tableName !== 'string') {
35
- throw new VSRepoConfigError(`[VSRepository] (config) 'tableName' must be a valid string.`);
36
- }
37
- if(typeof config.pkName !== 'string') {
38
- throw new VSRepoConfigError(`[VSRepository] (config) 'pkName' must be a valid string.`);
39
- }
40
- if(config.selectModels !== undefined && typeof config.selectModels !== 'object' || config.selectModels === null) {
41
- throw new VSRepoConfigError(`[VSRepository] (config) 'selectModels' must be a valid object.`);
42
- }
43
- if(config.defaultSelectModel !== undefined) {
44
- if(!config.selectModels) {
45
- throw new VSRepoConfigError(`[VSRepository] (config) 'defaultSelectModel' can only be passed with 'selectModels'.`);
46
- }
47
- if(typeof config.defaultSelectModel !== 'string') {
48
- throw new VSRepoConfigError(`[VSRepository] (config) 'defaultSelectModel' must be a valid string.`);
49
- }
50
- if(!Object.keys(config.selectModels).includes(config.defaultSelectModel)){
51
- throw new VSRepoConfigError(`[VSRepository] (config) Invalid 'defaultSelectModel': ${config.defaultSelectModel}`);
52
- }
53
- }
54
- if(config.relations !== undefined) {
55
- const relations = config.relations;
56
- if(typeof relations !== 'object' || relations === null){
57
- throw new VSRepoConfigError(`[VSRepository] (config) 'relations' must be a valid object.`);
58
- }
59
-
60
- for (const key of Object.keys(relations)) {
61
- const relation = relations[key];
62
- if(typeof relation.pk !== 'string'){
63
- throw new VSRepoConfigError(`[VSRepository] (config) The property 'pk' of relation '${key}' must be a string.`);
64
- }
65
- if(typeof relation.mode !== 'string'){
66
- throw new VSRepoConfigError(`[VSRepository] (config) The property 'mode' of relation '${key}' must be 'otm', 'mtm', 'mto' or 'oto'.`);
67
- }
68
- if(typeof relation.restriction !== 'string'){
69
- throw new VSRepoConfigError(`[VSRepository] (config) The property 'restriction' of relation '${key}' must be 'set' or 'add'.`);
70
- }
71
- }
72
- }
73
- if(config.requiredWhere !== undefined && typeof config.requiredWhere !== 'object' || config.requiredWhere === null) {
74
- throw new VSRepoConfigError(`[VSRepository] (config) 'requiredWhere' must be a valid object.`);
75
- }
76
- if(config.methods !== undefined) {
77
- if(typeof config.methods !== 'object' || config.methods === null){
78
- throw new VSRepoConfigError(`[VSRepository] (config) 'methods' must be a valid object.`);
79
- } else {
80
- for (const [key, value] of Object.entries(config.methods)) {
81
-
82
- if(typeof value.map !== "boolean") {
83
- throw new VSRepoConfigError(`[VSRepository] (config) 'map' on ${key} must be a valid boolean.`);
84
- }
85
-
86
- if(value.whereType !== undefined && !['extending', 'overwrite'].includes(value.whereType)){
87
- throw new VSRepoConfigError(`[VSRepository] (config) Invalid 'whereType' on ${key}: ${value.whereType}`);
88
- }
89
-
90
- if(value.selectModel !== undefined && value.selectModel !== false && (!config.selectModels || !Object.keys(config.selectModels).includes(value.selectModel))){
91
- throw new VSRepoConfigError(`[VSRepository] (config) Invalid 'selectModel' on ${key}: ${value.selectModel}`);
92
- }
93
-
94
- if(value.proxyTo !== undefined && typeof value.proxyTo !== 'string') {
95
- throw new VSRepoConfigError(`[VSRepository] (config) 'proxyTo' on ${key} must be a valid string.`);
96
- }
97
-
98
- if(value.fbMode !== undefined && !['one', 'list'].includes(value.fbMode)) {
99
- throw new VSRepoConfigError(`[VSRepository] (config) Invalid 'fbMode' on ${key}: ${value.whereType}`);
100
- }
101
-
102
- if(value.pushWhere !== undefined && (typeof value.pushWhere !== 'object' || value.pushWhere === null)) {
103
- throw new VSRepoConfigError(`[VSRepository] (config) 'pushWhere' on ${key} must be a valid object.`);
104
- }
105
-
106
- if(value.injectOrdenation !== undefined && (typeof value.injectOrdenation !== 'object' || value.injectOrdenation === null)) {
107
- throw new VSRepoConfigError(`[VSRepository] (config) 'injectOrdenation' on ${key} must be a valid object or array.`);
108
- }
109
-
110
- if(value.injectPagination !== undefined && (typeof value.injectPagination !== 'object' || value.injectPagination === null)) {
111
- throw new VSRepoConfigError(`[VSRepository] (config) 'injectPagination' on ${key} must be a valid object.`);
112
- }
113
-
114
- }
115
- }
116
- }
32
+ validateConfig(config);
117
33
 
118
34
  this.vsrepocache = new Map();
119
35
  this.tableName = config.tableName;
@@ -185,9 +101,22 @@ export class VSRepository {
185
101
  const whereParams = [];
186
102
  const otherParams = [];
187
103
 
188
- if(keyToMap.startsWith('findUniqueBy')) {
104
+ if(keyToMap.startsWith('findUniqueOrThrowBy')) {
105
+ keyToMapReplaced = keyToMap.replace('findUniqueOrThrowBy', '');
106
+ method = 'findUniqueOrThrow';
107
+ } else if(keyToMap.startsWith('findUniqueBy')) {
189
108
  keyToMapReplaced = keyToMap.replace('findUniqueBy', '');
190
109
  method = 'findUnique';
110
+ } else if(keyToMap.startsWith('findFirstOrThrowBy')) {
111
+ keyToMapReplaced = keyToMap.replace('findFirstOrThrowBy', '')
112
+ ignoreOrderByAndPagination = false;
113
+ method = 'findFirstOrThrow';
114
+ } else if(keyToMap.startsWith('findFirstOrThrow')) {
115
+ keyToMapReplaced = keyToMap.replace('findFirstOrThrow', '');
116
+ ignoreOrderByAndPagination = false;
117
+ ignoreWhere = true;
118
+ onlyBaseWheres = true;
119
+ method = 'findFirstOrThrow';
191
120
  } else if(keyToMap.startsWith('findFirstBy')) {
192
121
  keyToMapReplaced = keyToMap.replace('findFirstBy', '')
193
122
  ignoreOrderByAndPagination = false;
@@ -811,10 +740,7 @@ export class VSRepository {
811
740
 
812
741
  if(config.baseMethods?.get?.active !== false) {
813
742
  buildInstance.get = async(pk, options = {}) => {
814
- let db;
815
- if(options?.db) db = options.db;
816
- else db = prisma;
817
-
743
+ let db = options?.db ?? prisma;
818
744
  const prismaArgs = {};
819
745
 
820
746
  const where = { [buildInstance.pkName]: pk };
@@ -851,12 +777,48 @@ export class VSRepository {
851
777
  }
852
778
  }
853
779
  }
780
+ if(config.baseMethods?.getOrThrow?.active !== false) {
781
+ buildInstance.getOrThrow = async(pk, options = {}) => {
782
+ let db = options?.db ?? prisma;
783
+ const prismaArgs = {};
784
+
785
+ const where = { [buildInstance.pkName]: pk };
786
+ if(buildInstance.requiredWhere && !config.baseMethods?.getOrThrow?.ignoreRequiredWhere) {
787
+ Object.assign(where, buildInstance.requiredWhere);
788
+ }
789
+ prismaArgs.where = where;
790
+
791
+ let selectModelKey = options?.selectModel ?? config.baseMethods?.getOrThrow?.defaultSelect ?? buildInstance.defaultSelectModel;
792
+ if(selectModelKey){
793
+ prismaArgs.select = buildInstance.selectModels[selectModelKey];
794
+ }
795
+
796
+ let start;
797
+ if(showWorking){
798
+ console.log(`[VSRepository] (runtime) Executing getOrThrow on ${buildInstance.tableName}.`);
799
+ console.log(`[VSRepository] (runtime) Built arguments to getOrThrow on ${buildInstance.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
800
+ start = performance.now();
801
+ }
802
+
803
+ try {
804
+ const result = await db[buildInstance.tableName].findUniqueOrThrow(prismaArgs);
805
+
806
+ if(showWorking) {
807
+ const end = performance.now();
808
+ const duration = (end - start).toFixed(2);
809
+ console.log(`[VSRepository] (runtime) Executed getOrThrow on ${buildInstance.tableName} (took: ${duration}ms).`);
810
+ }
811
+
812
+ return result;
813
+ } catch (err) {
814
+ console.log(`[VSRepository] (runtime) Fatal error when trying to getOrThrow on ${buildInstance.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
815
+ throw err;
816
+ }
817
+ }
818
+ }
854
819
  if(config.baseMethods?.remove?.active !== false) {
855
820
  buildInstance.remove = async (pk, options = {}) => {
856
- let db;
857
- if(options?.db) db = options.db;
858
- else db = prisma;
859
-
821
+ let db = options?.db ?? prisma;
860
822
  const prismaArgs = {};
861
823
 
862
824
  const where = { [buildInstance.pkName]: pk };
@@ -894,10 +856,7 @@ export class VSRepository {
894
856
  }
895
857
  if(config.baseMethods?.save?.active !== false) {
896
858
  buildInstance.save = async (obj, options = {}) => {
897
- let db;
898
- if(options?.db) db = options.db;
899
- else db = prisma;
900
-
859
+ let db = options?.db ?? prisma;
901
860
  const prismaArgs = {};
902
861
 
903
862
  let selectModelKey = options?.selectModel ?? config.baseMethods?.save?.defaultSelect ?? buildInstance.defaultSelectModel;
@@ -1106,6 +1065,137 @@ export class VSRepository {
1106
1065
  throw err;
1107
1066
  }
1108
1067
  }
1068
+ if(config.baseMethods?.removeList?.active !== false) {
1069
+ buildInstance.removeList = async (pks, options = {}) => {
1070
+ let db = options?.db ?? prisma;
1071
+ const prismaArgs = {};
1072
+
1073
+ const where = { [buildInstance.pkName]: { in: pks } };
1074
+ if(buildInstance.requiredWhere && !config.baseMethods?.removeList?.ignoreRequiredWhere) {
1075
+ Object.assign(where, buildInstance.requiredWhere);
1076
+ }
1077
+ prismaArgs.where = where;
1078
+
1079
+ let start;
1080
+ if(showWorking){
1081
+ console.log(`[VSRepository] (runtime) Executing removeList on ${buildInstance.tableName}.`);
1082
+ console.log(`[VSRepository] (runtime) Built arguments to removeList on ${buildInstance.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
1083
+ start = performance.now();
1084
+ }
1085
+ try {
1086
+ const result = await db[buildInstance.tableName].deleteMany(prismaArgs);
1087
+ if(showWorking) {
1088
+ const end = performance.now();
1089
+ console.log(`[VSRepository] (runtime) Executed removeList on ${buildInstance.tableName} (took: ${(end - start).toFixed(2)}ms).`);
1090
+ }
1091
+ return result;
1092
+ } catch (err) {
1093
+ console.log(`[VSRepository] (runtime) Fatal error when trying to removeList on ${buildInstance.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
1094
+ throw err;
1095
+ }
1096
+ }
1097
+ }
1098
+ if(config.baseMethods?.getAll?.active !== false) {
1099
+ buildInstance.getAll = async (options = {}) => {
1100
+ let db = options?.db ?? prisma;
1101
+ const prismaArgs = {};
1102
+
1103
+ if(buildInstance.requiredWhere && !config.baseMethods?.getAll?.ignoreRequiredWhere) {
1104
+ prismaArgs.where = { ...buildInstance.requiredWhere };
1105
+ }
1106
+
1107
+ let selectModelKey = options?.selectModel ?? config.baseMethods?.getAll?.defaultSelect ?? buildInstance.defaultSelectModel;
1108
+ if(selectModelKey){
1109
+ prismaArgs.select = buildInstance.selectModels[selectModelKey];
1110
+ }
1111
+
1112
+ if(options.pagination) {
1113
+ prismaArgs.skip = options.pagination.skip;
1114
+ prismaArgs.take = options.pagination.take;
1115
+ prismaArgs.cursor = options.pagination.cursor;
1116
+ }
1117
+ if(options.order) {
1118
+ prismaArgs.orderBy = options.order;
1119
+ }
1120
+
1121
+ let start;
1122
+ if(showWorking){
1123
+ console.log(`[VSRepository] (runtime) Executing getAll on ${buildInstance.tableName}.`);
1124
+ console.log(`[VSRepository] (runtime) Built arguments to getAll on ${buildInstance.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
1125
+ start = performance.now();
1126
+ }
1127
+ try {
1128
+ const result = await db[buildInstance.tableName].findMany(prismaArgs);
1129
+ if(showWorking) {
1130
+ const end = performance.now();
1131
+ console.log(`[VSRepository] (runtime) Executed getAll on ${buildInstance.tableName} (took: ${(end - start).toFixed(2)}ms).`);
1132
+ }
1133
+ return result;
1134
+ } catch (err) {
1135
+ console.log(`[VSRepository] (runtime) Fatal error when trying to getAll on ${buildInstance.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
1136
+ throw err;
1137
+ }
1138
+ }
1139
+ }
1140
+ if(config.baseMethods?.total?.active !== false) {
1141
+ buildInstance.total = async (options = {}) => {
1142
+ let db = options?.db ?? prisma;
1143
+ const prismaArgs = {};
1144
+
1145
+ if(buildInstance.requiredWhere && !config.baseMethods?.total?.ignoreRequiredWhere) {
1146
+ prismaArgs.where = { ...buildInstance.requiredWhere };
1147
+ }
1148
+
1149
+ let start;
1150
+ if(showWorking){
1151
+ console.log(`[VSRepository] (runtime) Executing total on ${buildInstance.tableName}.`);
1152
+ console.log(`[VSRepository] (runtime) Built arguments to total on ${buildInstance.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
1153
+ start = performance.now();
1154
+ }
1155
+ try {
1156
+ const result = await db[buildInstance.tableName].count(prismaArgs);
1157
+ if(showWorking) {
1158
+ const end = performance.now();
1159
+ console.log(`[VSRepository] (runtime) Executed total on ${buildInstance.tableName} (took: ${(end - start).toFixed(2)}ms).`);
1160
+ }
1161
+ return result;
1162
+ } catch (err) {
1163
+ console.log(`[VSRepository] (runtime) Fatal error when trying to total on ${buildInstance.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
1164
+ throw err;
1165
+ }
1166
+ }
1167
+ }
1168
+ if(config.baseMethods?.has?.active !== false) {
1169
+ buildInstance.has = async (pk, options = {}) => {
1170
+ let db = options?.db ?? prisma;
1171
+ const prismaArgs = {};
1172
+
1173
+ const where = { [buildInstance.pkName]: pk };
1174
+ if(buildInstance.requiredWhere && !config.baseMethods?.has?.ignoreRequiredWhere) {
1175
+ Object.assign(where, buildInstance.requiredWhere);
1176
+ }
1177
+ prismaArgs.where = where;
1178
+ prismaArgs.select = { [buildInstance.pkName]: true };
1179
+
1180
+ let start;
1181
+ if(showWorking){
1182
+ console.log(`[VSRepository] (runtime) Executing has on ${buildInstance.tableName}.`);
1183
+ console.log(`[VSRepository] (runtime) Built arguments to has on ${buildInstance.tableName}:\n`, JSON.stringify(prismaArgs, null, 2));
1184
+ start = performance.now();
1185
+ }
1186
+ try {
1187
+ const result = await db[buildInstance.tableName].findUnique(prismaArgs);
1188
+ if(showWorking) {
1189
+ const end = performance.now();
1190
+ console.log(`[VSRepository] (runtime) Executed has on ${buildInstance.tableName} (took: ${(end - start).toFixed(2)}ms).`);
1191
+ }
1192
+ return !!result;
1193
+ } catch (err) {
1194
+ console.log(`[VSRepository] (runtime) Fatal error when trying to has on ${buildInstance.tableName}:\n`, JSON.stringify({ prismaArgs }, null, 2));
1195
+ throw err;
1196
+ }
1197
+ }
1198
+ }
1109
1199
  }
1110
1200
 
1111
1201
  if(config.freeze) Object.freeze(buildInstance)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vsrepo",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Uma biblioteca de repository pattern para Prisma",
5
5
  "homepage": "https://github.com/jaobrabo123/VSRepository#readme",
6
6
  "repository": {
@@ -61,6 +61,7 @@
61
61
  "@types/node": "^25.6.0",
62
62
  "dotenv": "^17.4.2",
63
63
  "prisma": "^7.8.0",
64
+ "tsx": "^4.22.3",
64
65
  "typescript": "^6.0.3"
65
66
  }
66
67
  }
@@ -10,6 +10,15 @@ const scriptDirectory = path.dirname(fileURLToPath(import.meta.url));
10
10
 
11
11
  const DEFAULT_OUTPUT = 'src/generated/vsrepo';
12
12
  const DEFAULT_PRISMA = 'src/generated/prisma';
13
+ const GENERATED_HEADER = `/**
14
+ * ! THIS FILE IS AUTO-GENERATED.
15
+ * ! DO NOT EDIT MANUALLY.
16
+ */
17
+ /* eslint-disable */
18
+ /* biome-ignore-all lint: generated file */
19
+ // @ts-nocheck
20
+
21
+ `;
13
22
 
14
23
  const command = args[0]?.startsWith('-') ? 'generate' : args[0] ?? 'generate';
15
24
  const commandArgs = command === 'generate' && args[0] !== command ? args : args.slice(1);
@@ -91,7 +100,7 @@ for (const fileName of typeFiles) {
91
100
  `from '${relativeImportPath(path.dirname(targetFile), prismaTargetPath)}'`
92
101
  );
93
102
 
94
- fs.writeFileSync(targetFile, contents, 'utf8');
103
+ fs.writeFileSync(targetFile, GENERATED_HEADER + contents, 'utf8');
95
104
 
96
105
  console.log(`Gerado: ${path.relative(workspaceRoot, targetFile)}`);
97
106
  }
@@ -166,7 +175,7 @@ export type * from './VSRepository.types';
166
175
  for (const file of tsFiles) {
167
176
  const targetFile = path.join(outputDir, file.fileName);
168
177
 
169
- fs.writeFileSync(targetFile, file.content, 'utf8');
178
+ fs.writeFileSync(targetFile, GENERATED_HEADER + file.content, 'utf8');
170
179
 
171
180
  console.log(`Gerado: ${path.relative(workspaceRoot, targetFile)}`);
172
181
  }