@vsrepo/prisma7-adapter 1.0.0 → 1.0.3
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 +43 -0
- package/README.pt-BR.md +43 -0
- package/dist/prisma7.adapter.d.ts +12 -4
- package/dist/prisma7.adapter.js +31 -23
- package/dist/resolvers/merge-entities.resolver.js +6 -1
- package/dist/types/adapter-config.type.d.ts +4 -0
- package/dist/validators/adapter-config.schema.d.ts +1 -0
- package/dist/validators/adapter-config.schema.js +1 -0
- package/package.json +84 -84
package/README.md
CHANGED
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
- [`relations` in method options (read)](#relations-in-method-options-read)
|
|
35
35
|
- [`merge`](#merge)
|
|
36
36
|
- [`createMany`/`createManyReturning`/`updateMany`/`updateManyReturning` don't support nested writes](#createmanycreatemanyreturningupdatemanyupdatemanyreturning-dont-support-nested-writes)
|
|
37
|
+
- [Provider-specific limitations](#provider-specific-limitations)
|
|
37
38
|
- [Transactions](#transactions)
|
|
38
39
|
- [Logging](#logging)
|
|
39
40
|
- [Requirements](#requirements)
|
|
@@ -202,6 +203,18 @@ For to-many relations (`otm`/`mtm`), items in the stored record and items in `ob
|
|
|
202
203
|
|
|
203
204
|
> Note on return order: `createManyReturning` don't guarantee the returned records follow the order of the input payload (`objs`). Their result comes from a second `findMany` (re-querying the inserted/updated rows by primary key), so the order is only guaranteed when you pass `order` in the options.
|
|
204
205
|
|
|
206
|
+
## Provider-specific limitations
|
|
207
|
+
|
|
208
|
+
Some Prisma features this adapter relies on aren't available on every database provider. If you use one of these features on an unsupported provider, Prisma itself will throw a validation error (or, in future versions, the adapter may validate this upfront — see below).
|
|
209
|
+
|
|
210
|
+
| Feature | Supported providers | Not supported |
|
|
211
|
+
| --- | --- | --- |
|
|
212
|
+
| `mode: "insensitive"` (used by `findByXIgnoreCase` dynamic methods) | PostgreSQL, MongoDB | MySQL, SQLite, SQL Server, CockroachDB — MySQL and SQL Server are case-insensitive by default, so no `mode` is needed there; SQLite is only case-insensitive for ASCII characters |
|
|
213
|
+
| `createManyReturning` / `updateManyReturning` (built on Prisma's `createManyAndReturn`/`updateManyAndReturn`) | PostgreSQL, CockroachDB, SQLite | MySQL, SQL Server, MongoDB |
|
|
214
|
+
| `skipDuplicates` on `createManyIgnoreConflicts` / `createManyReturningIgnoreConflicts` | PostgreSQL, MySQL, CockroachDB | MongoDB, SQL Server, SQLite |
|
|
215
|
+
|
|
216
|
+
> These limitations come from Prisma itself, not from this adapter — see [Prisma's case sensitivity docs](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#mode) and [CRUD reference](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud) for details.
|
|
217
|
+
|
|
205
218
|
## Transactions
|
|
206
219
|
|
|
207
220
|
**Every** method accepts `options.db` and runs its operation on the client/transaction you pass — the difference is in **how** each one treats it:
|
|
@@ -223,6 +236,36 @@ await userRepository.transaction(async tx => {
|
|
|
223
236
|
});
|
|
224
237
|
```
|
|
225
238
|
|
|
239
|
+
### Concurrency in `deleteManyReturning`
|
|
240
|
+
|
|
241
|
+
`deleteManyReturning` runs a `findMany` on the given `where` (to capture the records it will return) and then **re-applies the same `where`** to a `deleteMany`. Prisma has no native `deleteManyAndReturn`, which is why the delete is driven by the `where` instead of by the records fetched in the `findMany`.
|
|
242
|
+
|
|
243
|
+
Because of this two-step shape, a concurrent change between the `findMany` and the `deleteMany` can make them diverge:
|
|
244
|
+
|
|
245
|
+
- a row **inserted after** the `findMany` that matches the `where` will still be deleted, even though it wasn't returned;
|
|
246
|
+
- a row that **stops matching** the `where` before the `deleteMany` runs won't be deleted, even though it was returned.
|
|
247
|
+
|
|
248
|
+
In other words, the returned records and the rows actually deleted are not guaranteed to be identical under concurrency.
|
|
249
|
+
|
|
250
|
+
If you need to guarantee there are no concurrency issues, run this method inside a `repository.transaction()` at a higher isolation level — e.g. `SERIALIZABLE`:
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
import { VSRepository, TransactionIsolationLevel } from "vsrepo";
|
|
254
|
+
|
|
255
|
+
await userRepository.transaction(async tx => {
|
|
256
|
+
// Atomic: no concurrent insert/update can slip between the findMany
|
|
257
|
+
// and the deleteMany, since SERIALIZABLE isolates this transaction.
|
|
258
|
+
// `deleteManyReturning` is reached through the dynamic method you mapped
|
|
259
|
+
// to the adapter (e.g. a `@DynamicMethod()` exposing `deleteManyReturning`),
|
|
260
|
+
// always passing `{ db: tx }` so it runs inside this transaction.
|
|
261
|
+
const deleted = await userRepository.deleteManyReturningByIdIn([...], { db: tx });
|
|
262
|
+
}, {
|
|
263
|
+
isolationLevel: TransactionIsolationLevel.SERIALIZABLE,
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
> The isolation level applies only when the repository call actually runs **inside** that transaction (i.e. with `{ db: tx }`). When `deleteManyReturning` starts its own internal transaction (no `options.db` passed), it falls back to the default isolation level.
|
|
268
|
+
|
|
226
269
|
## Logging
|
|
227
270
|
|
|
228
271
|
The adapter uses `VSLogger` (from `vsrepo`) internally: every method logs a `DEBUG` line with the resolved Prisma arg, and start/end performance logs (surfacing a `WARN` for slow operations). Set `logLevel` in the constructor config to control verbosity; it defaults to `VSLogLevel.WARN`.
|
package/README.pt-BR.md
CHANGED
|
@@ -34,6 +34,7 @@ Implementação de `VSRepoAdapter` para o [VSRepository v2](https://github.com/j
|
|
|
34
34
|
- [`relations` nas options (leitura)](#relations-nas-options-leitura)
|
|
35
35
|
- [`merge`](#merge)
|
|
36
36
|
- [`createMany`/`createManyReturning`/`updateMany`/`updateManyReturning` não suportam nested writes](#createmanycreatemanyreturningupdatemanyupdatemanyreturning-não-suportam-nested-writes)
|
|
37
|
+
- [Limitações por provider](#limitações-por-provider)
|
|
37
38
|
- [Transactions](#transactions)
|
|
38
39
|
- [Logging](#logging)
|
|
39
40
|
- [Requisitos](#requisitos)
|
|
@@ -202,6 +203,18 @@ Pra relations to-many (`otm`/`mtm`), os itens do registro salvo e os itens de `o
|
|
|
202
203
|
|
|
203
204
|
> Nota sobre a ordem de retorno: `createManyReturning` não garante que os registros devolvidos seguem a ordem do payload de entrada (`objs`). O resultado vem de um segundo `findMany` (re-buscando as linhas inseridas/atualizadas pela primary key), então a ordem só é garantida quando você passa `order` nas options.
|
|
204
205
|
|
|
206
|
+
## Limitações por provider
|
|
207
|
+
|
|
208
|
+
Alguns recursos do Prisma que esse adapter usa não estão disponíveis em todo banco. Se você usar um desses recursos num provider sem suporte, o próprio Prisma lança um erro de validação (ou, em versões futuras, o adapter pode validar isso antecipadamente — ver abaixo).
|
|
209
|
+
|
|
210
|
+
| Recurso | Providers com suporte | Sem suporte |
|
|
211
|
+
| --- | --- | --- |
|
|
212
|
+
| `mode: "insensitive"` (usado pelos métodos dinâmicos `findByXIgnoreCase`) | PostgreSQL, MongoDB | MySQL, SQLite, SQL Server, CockroachDB — MySQL e SQL Server já são case-insensitive por padrão, então não precisam de `mode`; SQLite só é case-insensitive pra caracteres ASCII |
|
|
213
|
+
| `createManyReturning` / `updateManyReturning` (baseados no `createManyAndReturn`/`updateManyAndReturn` do Prisma) | PostgreSQL, CockroachDB, SQLite | MySQL, SQL Server, MongoDB |
|
|
214
|
+
| `skipDuplicates` no `createManyIgnoreConflicts` / `createManyReturningIgnoreConflicts` | PostgreSQL, MySQL, CockroachDB | MongoDB, SQL Server, SQLite |
|
|
215
|
+
|
|
216
|
+
> Essas limitações vêm do próprio Prisma, não do adapter — veja a [doc de case sensitivity](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#mode) e a [referência de CRUD](https://www.prisma.io/docs/orm/v7/prisma-client/queries/crud) do Prisma pra mais detalhes.
|
|
217
|
+
|
|
205
218
|
## Transactions
|
|
206
219
|
|
|
207
220
|
**Todos** os métodos aceitam `options.db` e executam a operação no client/transaction passado — a diferença está em **como** cada um o trata:
|
|
@@ -223,6 +236,36 @@ await userRepository.transaction(async tx => {
|
|
|
223
236
|
});
|
|
224
237
|
```
|
|
225
238
|
|
|
239
|
+
### Concorrência em `deleteManyReturning`
|
|
240
|
+
|
|
241
|
+
O `deleteManyReturning` roda um `findMany` no `where` informado (pra capturar os registros que vai devolver) e depois **re-aplica o mesmo `where`** num `deleteMany`. Como o Prisma não tem um `deleteManyAndReturn` nativo, o delete é guiado pelo `where` — e não pelos registros retornados no `findMany`.
|
|
242
|
+
|
|
243
|
+
Por causa desse formato em duas etapas, uma alteração concorrente entre o `findMany` e o `deleteMany` pode fazer os dois divergirem:
|
|
244
|
+
|
|
245
|
+
- uma linha **inserida depois** do `findMany` que bate com o `where` ainda será deletada, mesmo não tendo sido retornada;
|
|
246
|
+
- uma linha que **deixa de bater** com o `where` antes do `deleteMany` rodar não será deletada, mesmo tendo sido retornada.
|
|
247
|
+
|
|
248
|
+
Ou seja: os registros retornados e as linhas realmente deletadas não têm garantia de serem idênticos sob concorrência.
|
|
249
|
+
|
|
250
|
+
Se você quiser garantir que não haverá problemas de concorrência, rode esse método **dentro** de um `repository.transaction()` num nível de isolamento mais alto — ex.: `SERIALIZABLE`:
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
import { VSRepository, TransactionIsolationLevel } from "vsrepo";
|
|
254
|
+
|
|
255
|
+
await userRepository.transaction(async tx => {
|
|
256
|
+
// Atômico: nenhum insert/update concorrente consegue entrar entre o
|
|
257
|
+
// findMany e o deleteMany, pois o SERIALIZABLE isola esta transaction.
|
|
258
|
+
// O `deleteManyReturning` é acessado através do método dinâmico que você
|
|
259
|
+
// mapeou pro adapter (ex.: um `@DynamicMethod()` expondo `deleteManyReturning`),
|
|
260
|
+
// sempre passando `{ db: tx }` pra rodar dentro desta transaction.
|
|
261
|
+
const deleted = await userRepository.deleteManyReturningByIdIn([...], { db: tx });
|
|
262
|
+
}, {
|
|
263
|
+
isolationLevel: TransactionIsolationLevel.SERIALIZABLE,
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
> O nível de isolamento só se aplica quando a chamada roda **dentro** daquela transaction (ou seja, com `{ db: tx }`). Quando o `deleteManyReturning` inicia a própria transaction interna (sem `options.db`), ele usa o nível de isolamento padrão.
|
|
268
|
+
|
|
226
269
|
## Logging
|
|
227
270
|
|
|
228
271
|
O adapter usa o `VSLogger` (de `vsrepo`) internamente: todo método loga uma linha `DEBUG` com o arg resolvido do Prisma, além de logs de performance de início/fim (com `WARN` pra operações lentas). Configure `logLevel` na config do construtor pra controlar a verbosidade; o default é `VSLogLevel.WARN`.
|
|
@@ -79,10 +79,18 @@ export declare class VSRepoPrisma7Adapter<T> extends VSRepoAdapter<T> {
|
|
|
79
79
|
deleteMany(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<CountResult>;
|
|
80
80
|
/**
|
|
81
81
|
* Deletes every record matching `where`, returning the deleted records.
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
82
|
+
*
|
|
83
|
+
* Prisma has no `deleteManyAndReturn`, so this does a `findMany` on
|
|
84
|
+
* `where` first and then re-applies the same `where` to a `deleteMany`,
|
|
85
|
+
* both inside a transaction (`runTransactional`).
|
|
86
|
+
*
|
|
87
|
+
* Because the delete is driven by the same `where` (not by the fetched
|
|
88
|
+
* records), a concurrent change between the two operations can make them
|
|
89
|
+
* diverge — e.g. a row inserted after the `findMany` matching the `where`
|
|
90
|
+
* would still be deleted, while a row changed to stop matching wouldn't.
|
|
91
|
+
* If you need to guarantee no concurrency issues, run this method inside a
|
|
92
|
+
* `repository.transaction()` with a higher isolation level, e.g.
|
|
93
|
+
* `TransactionIsolationLevel.SERIALIZABLE`.
|
|
86
94
|
*/
|
|
87
95
|
deleteManyReturning(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T[]>;
|
|
88
96
|
/** Updates a single record matching `where`. */
|
package/dist/prisma7.adapter.js
CHANGED
|
@@ -40,7 +40,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
40
40
|
this.tableName = validated.tableName;
|
|
41
41
|
this.pkName = validated.pkName;
|
|
42
42
|
this.relations = validated.relations;
|
|
43
|
-
this.logger = new vsrepo_1.VSLogger(validated.logLevel ?? vsrepo_1.VSLogLevel.WARN, this.constructor.name + "Logger");
|
|
43
|
+
this.logger = new vsrepo_1.VSLogger(validated.logLevel ?? vsrepo_1.VSLogLevel.WARN, this.constructor.name + "Logger", validated.logSlowThresholdMs ?? 300);
|
|
44
44
|
this.logger.logInfo(`${this.constructor.name} initialized for table '${this.tableName}' (pkName: '${this.pkName}'${this.relations ? `, relations: [${Object.keys(this.relations).join(", ")}]` : ""})`);
|
|
45
45
|
}
|
|
46
46
|
getPrismaRepository(db) {
|
|
@@ -121,7 +121,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
121
121
|
}
|
|
122
122
|
/** Fetches a single record matching `where`. */
|
|
123
123
|
async findOne(where, options) {
|
|
124
|
-
const start = this.logger.startPerformLog("findOne");
|
|
124
|
+
const start = this.logger.startPerformLog("run findOne");
|
|
125
125
|
try {
|
|
126
126
|
const arg = { ...this.resolveReadArg(options), where: (0, where_parser_1.parsePrismaWhere)(where) };
|
|
127
127
|
this.logger.logDebug("Resolved Prisma arg for 'findOne'", arg);
|
|
@@ -136,7 +136,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
136
136
|
}
|
|
137
137
|
/** Fetches a single record matching `where`, throwing if none is found. */
|
|
138
138
|
async findOneOrThrow(where, options) {
|
|
139
|
-
const start = this.logger.startPerformLog("findOneOrThrow");
|
|
139
|
+
const start = this.logger.startPerformLog("run findOneOrThrow");
|
|
140
140
|
try {
|
|
141
141
|
const arg = { ...this.resolveReadArg(options), where: (0, where_parser_1.parsePrismaWhere)(where) };
|
|
142
142
|
this.logger.logDebug("Resolved Prisma arg for 'findOneOrThrow'", arg);
|
|
@@ -151,7 +151,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
151
151
|
}
|
|
152
152
|
/** Fetches all records matching `where`. */
|
|
153
153
|
async findMany(where, options) {
|
|
154
|
-
const start = this.logger.startPerformLog("findMany");
|
|
154
|
+
const start = this.logger.startPerformLog("run findMany");
|
|
155
155
|
try {
|
|
156
156
|
const arg = { ...this.resolveReadArg(options), where: (0, where_parser_1.parsePrismaWhere)(where) };
|
|
157
157
|
this.logger.logDebug("Resolved Prisma arg for 'findMany'", arg);
|
|
@@ -166,7 +166,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
166
166
|
}
|
|
167
167
|
/** Creates or updates (upsert) a single record. */
|
|
168
168
|
async save(obj, options) {
|
|
169
|
-
const start = this.logger.startPerformLog("save");
|
|
169
|
+
const start = this.logger.startPerformLog("run save");
|
|
170
170
|
try {
|
|
171
171
|
const objAny = obj;
|
|
172
172
|
const pkValue = objAny[this.pkName];
|
|
@@ -197,7 +197,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
197
197
|
* `runTransactional`).
|
|
198
198
|
*/
|
|
199
199
|
async saveMany(objs, options) {
|
|
200
|
-
const start = this.logger.startPerformLog("saveMany");
|
|
200
|
+
const start = this.logger.startPerformLog("run saveMany");
|
|
201
201
|
try {
|
|
202
202
|
this.logger.logDebug(`Saving ${objs.length} record(s) individually inside a transaction`);
|
|
203
203
|
return await this.runTransactional(options?.db, tx => Promise.all(objs.map(obj => this.save(obj, { ...options, db: tx }))));
|
|
@@ -211,7 +211,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
211
211
|
}
|
|
212
212
|
/** Deletes a single record matching `where`. */
|
|
213
213
|
async delete(where, options) {
|
|
214
|
-
const start = this.logger.startPerformLog("delete");
|
|
214
|
+
const start = this.logger.startPerformLog("run delete");
|
|
215
215
|
try {
|
|
216
216
|
const arg = { ...this.resolveReadArg(options), where: (0, where_parser_1.parsePrismaWhere)(where) };
|
|
217
217
|
this.logger.logDebug("Resolved Prisma arg for 'delete'", arg);
|
|
@@ -226,7 +226,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
226
226
|
}
|
|
227
227
|
/** Deletes every record matching `where`, returning the count of affected rows. */
|
|
228
228
|
async deleteMany(where, options) {
|
|
229
|
-
const start = this.logger.startPerformLog("deleteMany");
|
|
229
|
+
const start = this.logger.startPerformLog("run deleteMany");
|
|
230
230
|
try {
|
|
231
231
|
const arg = { where: (0, where_parser_1.parsePrismaWhere)(where) };
|
|
232
232
|
this.logger.logDebug("Resolved Prisma arg for 'deleteMany'", arg);
|
|
@@ -241,13 +241,21 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
241
241
|
}
|
|
242
242
|
/**
|
|
243
243
|
* Deletes every record matching `where`, returning the deleted records.
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
244
|
+
*
|
|
245
|
+
* Prisma has no `deleteManyAndReturn`, so this does a `findMany` on
|
|
246
|
+
* `where` first and then re-applies the same `where` to a `deleteMany`,
|
|
247
|
+
* both inside a transaction (`runTransactional`).
|
|
248
|
+
*
|
|
249
|
+
* Because the delete is driven by the same `where` (not by the fetched
|
|
250
|
+
* records), a concurrent change between the two operations can make them
|
|
251
|
+
* diverge — e.g. a row inserted after the `findMany` matching the `where`
|
|
252
|
+
* would still be deleted, while a row changed to stop matching wouldn't.
|
|
253
|
+
* If you need to guarantee no concurrency issues, run this method inside a
|
|
254
|
+
* `repository.transaction()` with a higher isolation level, e.g.
|
|
255
|
+
* `TransactionIsolationLevel.SERIALIZABLE`.
|
|
248
256
|
*/
|
|
249
257
|
async deleteManyReturning(where, options) {
|
|
250
|
-
const start = this.logger.startPerformLog("deleteManyReturning");
|
|
258
|
+
const start = this.logger.startPerformLog("run deleteManyReturning");
|
|
251
259
|
try {
|
|
252
260
|
const prismaWhere = (0, where_parser_1.parsePrismaWhere)(where);
|
|
253
261
|
const findArg = { ...this.resolveReadArg(options), where: prismaWhere };
|
|
@@ -272,7 +280,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
272
280
|
}
|
|
273
281
|
/** Updates a single record matching `where`. */
|
|
274
282
|
async update(where, obj, options) {
|
|
275
|
-
const start = this.logger.startPerformLog("update");
|
|
283
|
+
const start = this.logger.startPerformLog("run update");
|
|
276
284
|
try {
|
|
277
285
|
const { update } = (0, data_parser_1.parsePrismaWriteData)(obj, this.pkName, this.relations);
|
|
278
286
|
const arg = {
|
|
@@ -292,7 +300,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
292
300
|
}
|
|
293
301
|
/** Updates every record matching `where`, returning the count of affected rows. */
|
|
294
302
|
async updateMany(where, obj, options) {
|
|
295
|
-
const start = this.logger.startPerformLog("updateMany");
|
|
303
|
+
const start = this.logger.startPerformLog("run updateMany");
|
|
296
304
|
try {
|
|
297
305
|
const data = this.stripRelationFields(obj);
|
|
298
306
|
const arg = { where: (0, where_parser_1.parsePrismaWhere)(where), data };
|
|
@@ -308,7 +316,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
308
316
|
}
|
|
309
317
|
/** Updates every record matching `where`, returning the updated records. */
|
|
310
318
|
async updateManyReturning(where, obj, options) {
|
|
311
|
-
const start = this.logger.startPerformLog("updateManyReturning");
|
|
319
|
+
const start = this.logger.startPerformLog("run updateManyReturning");
|
|
312
320
|
try {
|
|
313
321
|
const data = this.stripRelationFields(obj);
|
|
314
322
|
const readArg = this.resolveReadArg(options);
|
|
@@ -341,7 +349,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
341
349
|
}
|
|
342
350
|
/** Returns the number of records matching `where`. */
|
|
343
351
|
async count(where, options) {
|
|
344
|
-
const start = this.logger.startPerformLog("count");
|
|
352
|
+
const start = this.logger.startPerformLog("run count");
|
|
345
353
|
try {
|
|
346
354
|
const arg = { where: (0, where_parser_1.parsePrismaWhere)(where) };
|
|
347
355
|
this.logger.logDebug("Resolved Prisma arg for 'count'", arg);
|
|
@@ -356,7 +364,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
356
364
|
}
|
|
357
365
|
/** Checks whether at least one record matching `where` exists. */
|
|
358
366
|
async exists(where, options) {
|
|
359
|
-
const start = this.logger.startPerformLog("exists");
|
|
367
|
+
const start = this.logger.startPerformLog("run exists");
|
|
360
368
|
try {
|
|
361
369
|
const arg = { where: (0, where_parser_1.parsePrismaWhere)(where), select: { [this.pkName]: true } };
|
|
362
370
|
this.logger.logDebug("Resolved Prisma arg for 'exists'", arg);
|
|
@@ -391,7 +399,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
391
399
|
}
|
|
392
400
|
/** Creates a single record. */
|
|
393
401
|
async create(obj, options) {
|
|
394
|
-
const start = this.logger.startPerformLog("create");
|
|
402
|
+
const start = this.logger.startPerformLog("run create");
|
|
395
403
|
try {
|
|
396
404
|
const { create } = (0, data_parser_1.parsePrismaWriteData)(obj, this.pkName, this.relations);
|
|
397
405
|
const arg = { ...this.resolveReadArg(options), data: create };
|
|
@@ -411,7 +419,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
411
419
|
* support nested writes.
|
|
412
420
|
*/
|
|
413
421
|
async createMany(objs, options) {
|
|
414
|
-
const start = this.logger.startPerformLog("createMany");
|
|
422
|
+
const start = this.logger.startPerformLog("run createMany");
|
|
415
423
|
try {
|
|
416
424
|
const data = objs.map(obj => this.stripRelationFields(obj));
|
|
417
425
|
const arg = { data, skipDuplicates: options?.ignoreConflicts };
|
|
@@ -429,7 +437,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
429
437
|
* Creates multiple records in a single operation, returning the created records.
|
|
430
438
|
*/
|
|
431
439
|
async createManyReturning(objs, options) {
|
|
432
|
-
const start = this.logger.startPerformLog("createManyReturning");
|
|
440
|
+
const start = this.logger.startPerformLog("run createManyReturning");
|
|
433
441
|
try {
|
|
434
442
|
const data = objs.map(obj => this.stripRelationFields(obj));
|
|
435
443
|
const readArg = this.resolveReadArg(options);
|
|
@@ -463,7 +471,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
463
471
|
* what to do with the result (e.g. call `save` next).
|
|
464
472
|
*/
|
|
465
473
|
async merge(where, obj, options) {
|
|
466
|
-
const start = this.logger.startPerformLog("merge");
|
|
474
|
+
const start = this.logger.startPerformLog("run merge");
|
|
467
475
|
try {
|
|
468
476
|
const arg = { ...this.resolveReadArg(options), where: (0, where_parser_1.parsePrismaWhere)(where) };
|
|
469
477
|
this.logger.logDebug("Resolved Prisma arg for 'merge'", arg);
|
|
@@ -481,7 +489,7 @@ class VSRepoPrisma7Adapter extends vsrepo_1.VSRepoAdapter {
|
|
|
481
489
|
}
|
|
482
490
|
/** Creates a record if none matches `where`, otherwise updates it. */
|
|
483
491
|
async upsert(where, create, update, options) {
|
|
484
|
-
const start = this.logger.startPerformLog("upsert");
|
|
492
|
+
const start = this.logger.startPerformLog("run upsert");
|
|
485
493
|
try {
|
|
486
494
|
const parsedCreate = (0, data_parser_1.parsePrismaWriteData)(create, this.pkName, this.relations).create;
|
|
487
495
|
const parsedUpdate = (0, data_parser_1.parsePrismaWriteData)(update, this.pkName, this.relations).update;
|
|
@@ -46,7 +46,12 @@ function mergeToManyRelation(target, source, relationPk) {
|
|
|
46
46
|
}
|
|
47
47
|
function mergeEntities(result, obj, relations) {
|
|
48
48
|
if (!relations) {
|
|
49
|
-
|
|
49
|
+
const definedObj = {};
|
|
50
|
+
for (const key of Object.keys(obj)) {
|
|
51
|
+
if (obj[key] !== undefined)
|
|
52
|
+
definedObj[key] = obj[key];
|
|
53
|
+
}
|
|
54
|
+
return (0, deepmerge_1.default)(result, definedObj, {
|
|
50
55
|
arrayMerge: (target, source) => target.concat(source),
|
|
51
56
|
});
|
|
52
57
|
}
|
|
@@ -19,4 +19,8 @@ export interface VSRepoPrisma7AdapterConfig<T = any> {
|
|
|
19
19
|
relations?: AdapterRelations<T>;
|
|
20
20
|
/** Minimum log level for the adapter's internal `VSLogger`. @default VSLogLevel.WARN */
|
|
21
21
|
logLevel?: VSLogLevel;
|
|
22
|
+
/**
|
|
23
|
+
* Duration (in ms) above which a finished operation is logged, flagging potentially slow queries. Defaults to 300ms.
|
|
24
|
+
*/
|
|
25
|
+
logSlowThresholdMs?: number;
|
|
22
26
|
}
|
|
@@ -10,4 +10,5 @@ export declare const adapterConfigSchema: v.ObjectSchema<{
|
|
|
10
10
|
readonly nullable: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
11
11
|
}, undefined>, undefined>, undefined>;
|
|
12
12
|
readonly logLevel: v.OptionalSchema<v.EnumSchema<typeof VSLogLevel, undefined>, undefined>;
|
|
13
|
+
readonly logSlowThresholdMs: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.GtValueAction<number, 0, undefined>]>, undefined>;
|
|
13
14
|
}, undefined>;
|
|
@@ -42,4 +42,5 @@ exports.adapterConfigSchema = v.object({
|
|
|
42
42
|
pkName: v.pipe(v.string(), v.minLength(1)),
|
|
43
43
|
relations: v.optional(v.record(v.string(), relation_schema_1.relationSchema)),
|
|
44
44
|
logLevel: v.optional(v.enum(vsrepo_1.VSLogLevel)),
|
|
45
|
+
logSlowThresholdMs: v.optional(v.pipe(v.number(), v.gtValue(0))),
|
|
45
46
|
});
|
package/package.json
CHANGED
|
@@ -1,84 +1,84 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@vsrepo/prisma7-adapter",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "VSRepository adapter implementation backed by Prisma 7, translating every VSRepository operation into Prisma Client calls.",
|
|
5
|
-
"homepage": "https://github.com/jaobrabo123/VSRepoPrisma7Adapter#readme",
|
|
6
|
-
"repository": {
|
|
7
|
-
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/jaobrabo123/VSRepoPrisma7Adapter.git"
|
|
9
|
-
},
|
|
10
|
-
"main": "./dist/index.js",
|
|
11
|
-
"types": "./dist/index.d.ts",
|
|
12
|
-
"exports": {
|
|
13
|
-
".": {
|
|
14
|
-
"types": "./dist/index.d.ts",
|
|
15
|
-
"import": "./dist/index.js",
|
|
16
|
-
"require": "./dist/index.js"
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
"type": "commonjs",
|
|
20
|
-
"files": [
|
|
21
|
-
"dist",
|
|
22
|
-
"README.md",
|
|
23
|
-
"README.pt-BR.md"
|
|
24
|
-
],
|
|
25
|
-
"engines": {
|
|
26
|
-
"node": ">=18"
|
|
27
|
-
},
|
|
28
|
-
"scripts": {
|
|
29
|
-
"clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\"",
|
|
30
|
-
"build": "npm run clean && tsc -p tsconfig.build.json",
|
|
31
|
-
"prepack": "npm run build",
|
|
32
|
-
"typecheck": "tsc --noEmit -p tsconfig.build.json",
|
|
33
|
-
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest",
|
|
34
|
-
"test:watch": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --watch",
|
|
35
|
-
"test:types": "tsc --noEmit -p tests/tsconfig.json"
|
|
36
|
-
},
|
|
37
|
-
"keywords": [
|
|
38
|
-
"prisma",
|
|
39
|
-
"prisma7",
|
|
40
|
-
"repository",
|
|
41
|
-
"orm",
|
|
42
|
-
"typescript",
|
|
43
|
-
"repository-pattern",
|
|
44
|
-
"vsrepo",
|
|
45
|
-
"vsrepository",
|
|
46
|
-
"adapter"
|
|
47
|
-
],
|
|
48
|
-
"author": "João Pedro Azevedo Freire Mecenas",
|
|
49
|
-
"license": "MIT",
|
|
50
|
-
"peerDependencies": {
|
|
51
|
-
"@prisma/client": "^7.10.0",
|
|
52
|
-
"vsrepo": "^2.0.0"
|
|
53
|
-
},
|
|
54
|
-
"dependencies": {
|
|
55
|
-
"deepmerge": "^4.3.1",
|
|
56
|
-
"valibot": "^1.4.2"
|
|
57
|
-
},
|
|
58
|
-
"devDependencies": {
|
|
59
|
-
"@babel/core": "^7.29.7",
|
|
60
|
-
"@babel/plugin-proposal-decorators": "^7.29.7",
|
|
61
|
-
"@babel/preset-env": "^7.29.7",
|
|
62
|
-
"@babel/preset-typescript": "^7.29.7",
|
|
63
|
-
"@jest/globals": "^30.5.0",
|
|
64
|
-
"@prisma/adapter-pg": "^7.10.0",
|
|
65
|
-
"@types/jest": "^30.0.0",
|
|
66
|
-
"@types/node": "^26.4.0",
|
|
67
|
-
"@types/pg": "^8.23.1",
|
|
68
|
-
"babel-jest": "^30.5.0",
|
|
69
|
-
"cross-env": "^10.1.0",
|
|
70
|
-
"dotenv": "^17.4.2",
|
|
71
|
-
"jest": "^30.5.0",
|
|
72
|
-
"pg": "^8.23.0",
|
|
73
|
-
"prisma": "^7.10.0",
|
|
74
|
-
"tsx": "^4.23.12",
|
|
75
|
-
"typescript": "^7.0.2"
|
|
76
|
-
},
|
|
77
|
-
"allowScripts": {
|
|
78
|
-
"prisma@7.10.0": true,
|
|
79
|
-
"@parcel/watcher@2.6.0": true,
|
|
80
|
-
"unrs-resolver@1.12.2": true,
|
|
81
|
-
"@prisma/engines@7.10.0": true,
|
|
82
|
-
"esbuild@0.28.2": true
|
|
83
|
-
}
|
|
84
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@vsrepo/prisma7-adapter",
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "VSRepository adapter implementation backed by Prisma 7, translating every VSRepository operation into Prisma Client calls.",
|
|
5
|
+
"homepage": "https://github.com/jaobrabo123/VSRepoPrisma7Adapter#readme",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/jaobrabo123/VSRepoPrisma7Adapter.git"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"require": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"type": "commonjs",
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"README.md",
|
|
23
|
+
"README.pt-BR.md"
|
|
24
|
+
],
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\"",
|
|
30
|
+
"build": "npm run clean && tsc -p tsconfig.build.json",
|
|
31
|
+
"prepack": "npm run build",
|
|
32
|
+
"typecheck": "tsc --noEmit -p tsconfig.build.json",
|
|
33
|
+
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest",
|
|
34
|
+
"test:watch": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --watch",
|
|
35
|
+
"test:types": "tsc --noEmit -p tests/tsconfig.json"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"prisma",
|
|
39
|
+
"prisma7",
|
|
40
|
+
"repository",
|
|
41
|
+
"orm",
|
|
42
|
+
"typescript",
|
|
43
|
+
"repository-pattern",
|
|
44
|
+
"vsrepo",
|
|
45
|
+
"vsrepository",
|
|
46
|
+
"adapter"
|
|
47
|
+
],
|
|
48
|
+
"author": "João Pedro Azevedo Freire Mecenas",
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"@prisma/client": "^7.10.0",
|
|
52
|
+
"vsrepo": "^2.0.0"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"deepmerge": "^4.3.1",
|
|
56
|
+
"valibot": "^1.4.2"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@babel/core": "^7.29.7",
|
|
60
|
+
"@babel/plugin-proposal-decorators": "^7.29.7",
|
|
61
|
+
"@babel/preset-env": "^7.29.7",
|
|
62
|
+
"@babel/preset-typescript": "^7.29.7",
|
|
63
|
+
"@jest/globals": "^30.5.0",
|
|
64
|
+
"@prisma/adapter-pg": "^7.10.0",
|
|
65
|
+
"@types/jest": "^30.0.0",
|
|
66
|
+
"@types/node": "^26.4.0",
|
|
67
|
+
"@types/pg": "^8.23.1",
|
|
68
|
+
"babel-jest": "^30.5.0",
|
|
69
|
+
"cross-env": "^10.1.0",
|
|
70
|
+
"dotenv": "^17.4.2",
|
|
71
|
+
"jest": "^30.5.0",
|
|
72
|
+
"pg": "^8.23.0",
|
|
73
|
+
"prisma": "^7.10.0",
|
|
74
|
+
"tsx": "^4.23.12",
|
|
75
|
+
"typescript": "^7.0.2"
|
|
76
|
+
},
|
|
77
|
+
"allowScripts": {
|
|
78
|
+
"prisma@7.10.0": true,
|
|
79
|
+
"@parcel/watcher@2.6.0": true,
|
|
80
|
+
"unrs-resolver@1.12.2": true,
|
|
81
|
+
"@prisma/engines@7.10.0": true,
|
|
82
|
+
"esbuild@0.28.2": true
|
|
83
|
+
}
|
|
84
|
+
}
|