vsrepo 1.0.0

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 ADDED
@@ -0,0 +1,281 @@
1
+ # VSRepo
2
+
3
+ Biblioteca de repository para projetos que usam Prisma. Ela permite criar repositories tipados com métodos base (`get`, `save` e `remove`) e métodos dinâmicos mapeados pelo nome, como `findByEmail`, `findManyPaginated`, `updateById` e `deleteManyByIdIn`.
4
+
5
+ ## Instalação
6
+
7
+ ```bash
8
+ pnpm add vsrepo @prisma/client
9
+ ```
10
+
11
+ O Prisma Client deve estar configurado no projeto:
12
+
13
+ ```bash
14
+ pnpm prisma generate
15
+ ```
16
+
17
+ ## Uso básico
18
+
19
+ Crie uma instância do Prisma Client:
20
+
21
+ ```ts
22
+ // src/db.ts
23
+ import { PrismaClient } from "@prisma/client";
24
+
25
+ const prisma = new PrismaClient();
26
+
27
+ export default prisma;
28
+ ```
29
+
30
+ Depois crie o repository do modelo:
31
+
32
+ ```ts
33
+ // src/repositories/usuarioRepository.ts
34
+ import prisma from "../db";
35
+ import { setupVSRepo, type SelectModels, type WhereModel } from "vsrepo";
36
+ import type { Prisma } from "@prisma/client";
37
+
38
+ type Usuario = Prisma.usuarioGetPayload<{
39
+ include: {
40
+ perfil: true;
41
+ postagens: true;
42
+ };
43
+ }>;
44
+
45
+ const usuarioSelectModels = {
46
+ public: {
47
+ id: true,
48
+ nome: true,
49
+ email: true,
50
+ },
51
+ minimal: {
52
+ id: true,
53
+ },
54
+ } satisfies SelectModels<"usuario">;
55
+
56
+ const usuarioRequiredWhere = {
57
+ ativo: true,
58
+ } satisfies WhereModel<"usuario">;
59
+
60
+ const usuarioVSRepo = setupVSRepo<Usuario, "usuario">()({
61
+ tableName: "usuario",
62
+ pkName: "id",
63
+ selectModels: usuarioSelectModels,
64
+ defaultSelectModel: "public",
65
+ requiredWhere: usuarioRequiredWhere,
66
+ methods: {
67
+ findByEmail: { map: true, fbMode: "one" },
68
+ findManyPaginated: { map: true },
69
+ updateById: { map: true },
70
+ deleteManyByIdIn: { map: true, whereType: "overwrite" },
71
+ count: { map: true },
72
+ },
73
+ });
74
+
75
+ const usuarioRepository = usuarioVSRepo.build(prisma);
76
+
77
+ export default usuarioRepository;
78
+ ```
79
+
80
+ Use o repository na aplicação:
81
+
82
+ ```ts
83
+ import usuarioRepository from "./repositories/usuarioRepository";
84
+
85
+ const usuario = await usuarioRepository.save({
86
+ nome: "Joao",
87
+ email: "joao@email.com",
88
+ senha: "password",
89
+ });
90
+
91
+ const usuarioEncontrado = await usuarioRepository.get(usuario.id);
92
+
93
+ const porEmail = await usuarioRepository.findByEmail("joao@email.com");
94
+
95
+ await usuarioRepository.updateById(usuario.id, {
96
+ nome: "Joao Pedro",
97
+ });
98
+
99
+ await usuarioRepository.remove(usuario.id);
100
+ ```
101
+
102
+ ## Métodos base
103
+
104
+ Ao chamar `build(prisma)`, o VSRepo cria três métodos por padrão:
105
+
106
+ | Método | Descrição |
107
+ | --- | --- |
108
+ | `get(pk, options?)` | Busca um registro pela primary key definida em `pkName`. |
109
+ | `save(obj, options?)` | Cria ou atualiza um registro. Se `obj` tiver a primary key, usa `upsert`; se não tiver, usa `create`. |
110
+ | `remove(pk, options?)` | Remove um registro pela primary key. |
111
+
112
+ Você pode configurar esses métodos no `build`:
113
+
114
+ ```ts
115
+ const usuarioRepository = usuarioVSRepo.build(prisma, {
116
+ freeze: true,
117
+ showWorking: false,
118
+ baseMethods: {
119
+ get: {
120
+ active: true,
121
+ defaultSelect: "public",
122
+ },
123
+ remove: {
124
+ defaultSelect: "minimal",
125
+ },
126
+ save: {
127
+ active: true,
128
+ },
129
+ },
130
+ });
131
+ ```
132
+
133
+ ## Select models
134
+
135
+ `selectModels` define selects reutilizáveis do Prisma. O `defaultSelectModel` é aplicado quando o método não recebe outro select.
136
+
137
+ ```ts
138
+ const usuario = await usuarioRepository.get(id, {
139
+ selectModel: "minimal",
140
+ });
141
+
142
+ const usuarioCompleto = await usuarioRepository.get(id, {
143
+ selectModel: false,
144
+ });
145
+ ```
146
+
147
+ Use `selectModel: false` para não aplicar nenhum select model e deixar o Prisma retornar o payload padrão.
148
+
149
+ ## Métodos dinâmicos
150
+
151
+ Métodos dinâmicos são declarados em `methods` com `map: true`. O nome do método informa qual operação do Prisma será usada e quais campos entram no `where`.
152
+
153
+ Exemplos:
154
+
155
+ ```ts
156
+ methods: {
157
+ findUniqueByIdAndEmail: { map: true },
158
+ findByNomeContainsInsensitive: { map: true },
159
+ findManyPaginated: { map: true },
160
+ findListWhereOrderedAndPaginated: { map: true, whereType: "overwrite" },
161
+ createManyAndReturn: { map: true },
162
+ updateById: { map: true },
163
+ deleteManyByIdIn: { map: true, whereType: "overwrite" },
164
+ existsByEmail: { map: true },
165
+ countByPerfil: { map: true },
166
+ }
167
+ ```
168
+
169
+ Uso:
170
+
171
+ ```ts
172
+ const usuario = await usuarioRepository.findUniqueByIdAndEmail(id, email);
173
+
174
+ const usuarios = await usuarioRepository.findByNomeContainsInsensitive("joao");
175
+
176
+ const pagina = await usuarioRepository.findManyPaginated({
177
+ take: 10,
178
+ skip: 0,
179
+ });
180
+
181
+ const ordenado = await usuarioRepository.findListWhereOrderedAndPaginated(
182
+ { nome: { startsWith: "A" } },
183
+ { dataCriacao: "desc" },
184
+ { take: 10 }
185
+ );
186
+ ```
187
+
188
+ ## Filtros pelo nome do método
189
+
190
+ O VSRepo interpreta sufixos no nome dos métodos para montar o `where`:
191
+
192
+ | Padrão | Exemplo |
193
+ | --- | --- |
194
+ | `And` / `Or` | `findByIdAndEmail`, `findByNomeOrEmail` |
195
+ | `In` / `NotIn` | `deleteManyByIdIn` |
196
+ | `Contains` / `StartsWith` / `EndsWith` | `findByNomeContains` |
197
+ | `Insensitive` | `findByNomeContainsInsensitive` |
198
+ | `GreaterThan` / `GreaterThanEqual` | `findByIdadeGreaterThan` |
199
+ | `LessThan` / `LessThanEqual` | `findByIdadeLessThanEqual` |
200
+ | `IsNull` / `IsNotNull` | `findByPerfilIsNotNull` |
201
+ | `IsTrue` / `IsFalse` | `findByAtivoIsTrue` |
202
+ | `Some` / `Every` / `None` | `findByPostagensSomeTituloContains` |
203
+ | `With` / `Without` | `findByPerfilWith`, `findByPerfilWithout` |
204
+
205
+ ## Relações no `save`
206
+
207
+ Configure `relations` para que `save` consiga criar, conectar, atualizar ou remover relações junto com o registro principal.
208
+
209
+ ```ts
210
+ const usuarioVSRepo = setupVSRepo<Usuario, "usuario">()({
211
+ tableName: "usuario",
212
+ pkName: "id",
213
+ relations: {
214
+ perfil: {
215
+ pk: "id",
216
+ mode: "oto",
217
+ restriction: "set",
218
+ },
219
+ postagens: {
220
+ pk: "id",
221
+ mode: "otm",
222
+ restriction: "set",
223
+ },
224
+ },
225
+ });
226
+ ```
227
+
228
+ Modos disponíveis:
229
+
230
+ | Modo | Relação |
231
+ | --- | --- |
232
+ | `oto` | one-to-one |
233
+ | `otm` | one-to-many |
234
+ | `mto` | many-to-one |
235
+ | `mtm` | many-to-many |
236
+
237
+ `restriction: "set"` substitui o conjunto atual quando aplicável. `restriction: "add"` adiciona/conecta sem limpar os registros já relacionados.
238
+
239
+ ## Transações
240
+
241
+ Todos os métodos aceitam `options.db`. Use isso para executar operações dentro de uma transação do Prisma:
242
+
243
+ ```ts
244
+ await prisma.$transaction(async (tx) => {
245
+ const usuario = await usuarioRepository.save(
246
+ {
247
+ nome: "Maria",
248
+ email: "maria@email.com",
249
+ senha: "password",
250
+ },
251
+ { db: tx }
252
+ );
253
+
254
+ await usuarioRepository.updateById(
255
+ usuario.id,
256
+ { ativo: true },
257
+ { db: tx }
258
+ );
259
+ });
260
+ ```
261
+
262
+ ## Estendendo um repository
263
+
264
+ Use `extend` para adicionar métodos manuais mantendo os métodos gerados:
265
+
266
+ ```ts
267
+ const repository = usuarioVSRepo
268
+ .build(prisma)
269
+ .extend((repo) => ({
270
+ async buscarAtivosPorDominio(dominio: string) {
271
+ return repo.findByEmailEndsWith(`@${dominio}`);
272
+ },
273
+ }));
274
+ ```
275
+
276
+ ## Scripts do projeto
277
+
278
+ ```bash
279
+ pnpm test:usuario
280
+ pnpm test:base-methods:user
281
+ ```
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "vsrepo",
3
+ "version": "1.0.0",
4
+ "description": "Uma biblioteca de repositório virtual para Prisma",
5
+ "main": "src/index.js",
6
+ "types": "src/index.d.ts",
7
+ "type": "module",
8
+ "scripts": {
9
+ "test:base-methods:user": "tsx ./src/tests/base-methods/user.bm.test.ts",
10
+ "test:usuario": "tsx ./src/tests/usuario.test.ts"
11
+ },
12
+ "files": [
13
+ "src/VSRepository.js",
14
+ "src/VSRepository.d.ts",
15
+ "src/VSRepoError.js",
16
+ "src/VSRepoError.d.ts",
17
+ "src/index.js",
18
+ "src/index.d.ts"
19
+ ],
20
+ "keywords": [
21
+ "prisma",
22
+ "repository",
23
+ "orm",
24
+ "typescript",
25
+ "vsrepo",
26
+ "vsrepository"
27
+ ],
28
+ "author": "João Pedro Azevedo",
29
+ "license": "MIT",
30
+ "peerDependencies": {
31
+ "@prisma/client": "^7.8.0"
32
+ },
33
+ "devDependencies": {
34
+ "@prisma/adapter-pg": "^7.8.0",
35
+ "@prisma/client": "^7.8.0",
36
+ "@types/node": "^25.6.0",
37
+ "dotenv": "^17.4.2",
38
+ "prisma": "^7.8.0",
39
+ "typescript": "^6.0.3"
40
+ }
41
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './VSRepository/VSRepoError';
2
+ export * from './VSRepository/VSRepository';
package/src/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from './VSRepository/VSRepoError.js';
2
+ export * from './VSRepository/VSRepository.js';