@vsrepo/prisma7-adapter 2.0.0-dev → 2.0.0-dev.1

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
@@ -24,14 +24,19 @@
24
24
  - [Installation](#installation)
25
25
  - [Basic usage](#basic-usage)
26
26
  - [Constructor config](#constructor-config)
27
+ - [Global config](#global-config)
27
28
  - [Relations](#relations)
28
- - [The two `relations`](#the-two-relations)
29
- - [`relations` in the constructor (write)](#relations-in-the-constructor-write)
30
- - [`mode`](#mode)
31
- - [`restriction`](#restriction)
32
- - [`pk` and `nullable`](#pk-and-nullable)
33
- - [How each write method resolves relations](#how-each-write-method-resolves-relations)
34
- - [`relations` in method options (read)](#relations-in-method-options-read)
29
+ - [The two `relations`](#the-two-relations)
30
+ - [`relations` in the constructor (write)](#relations-in-the-constructor-write)
31
+ - [`mode`](#mode)
32
+ - [`pk`](#pk)
33
+ - [`onUpdate`](#onupdate)
34
+ - [`onDisconnect`](#ondisconnect)
35
+ - [Ignoring a relation (`"ignore"`)](#ignoring-a-relation-ignore)
36
+ - [`fkHere` and `fkThere`](#fkhere-and-fkthere)
37
+ - [`allowOmitPk`](#allowomitpk)
38
+ - [How each write method resolves relations](#how-each-write-method-resolves-relations)
39
+ - [`relations` in method options (read)](#relations-in-method-options-read)
35
40
  - [Atomic and aggregation methods](#atomic-and-aggregation-methods)
36
41
  - [`createMany`/`createManyReturning`/`updateMany`/`updateManyReturning` don't support nested writes](#createmanycreatemanyreturningupdatemanyupdatemanyreturning-dont-support-nested-writes)
37
42
  - [Provider-specific limitations](#provider-specific-limitations)
@@ -67,7 +72,7 @@ class UserRepository extends VSRepository<User, string, MyOrmTypes> {
67
72
  modelName: "user",
68
73
  pkName: "id",
69
74
  relations: {
70
- posts: { mode: "otm", restriction: "add", pk: "id" },
75
+ posts: { mode: "otm", pk: "id" },
71
76
  },
72
77
  logLevel: VSLogLevel.WARN,
73
78
  }),
@@ -93,6 +98,7 @@ new Prisma7Adapter(prisma, {
93
98
  relations: { ... }, // optional — see "relations in the constructor (write)" below
94
99
  provider: "postgresql", // optional — detected from the Prisma Client when omitted
95
100
  logLevel: VSLogLevel.WARN, // optional — default: VSLogLevel.WARN
101
+ allowOmitPk: false, // optional — default: false. Read "`allowOmitPk`" before turning it on
96
102
  });
97
103
  ```
98
104
 
@@ -102,7 +108,22 @@ At construction, the adapter checks the Prisma Client and the model, and resolve
102
108
  - a `modelName` with no matching delegate on the client (`prisma.<modelName>`) throws `MODEL_NOT_FOUND`;
103
109
  - the provider comes from `provider` when set; otherwise it's detected from the generated client (`_engineConfig.activeProvider`, falling back to the driver adapter's `provider`). If it can't be detected, construction throws `NOT_SUPPORTED` — set `provider` explicitly in that case (one of `postgresql`, `cockroachdb`, `mysql`, `sqlite`, `sqlserver`).
104
110
 
105
- The other fields (`pkName`, `relations`, `logLevel`) are checked by TypeScript only, not at runtime.
111
+ The other fields (`pkName`, `relations`, `logLevel`, `allowOmitPk`) are checked by TypeScript only, not at runtime.
112
+
113
+ ## Global config
114
+
115
+ `provider`, `logLevel` and `allowOmitPk` can be set once for every adapter, through the static `setGlobalConfig`:
116
+
117
+ ```typescript
118
+ import { VSLogLevel } from "vsrepo";
119
+ import { Prisma7Adapter } from "@vsrepo/prisma7-adapter";
120
+
121
+ Prisma7Adapter.setGlobalConfig({ logLevel: VSLogLevel.WARN });
122
+ ```
123
+
124
+ - It only affects adapters created **after** the call, so call it before instantiating your repositories.
125
+ - Each call **replaces** the previous global config — it doesn't merge with it.
126
+ - A value set in an adapter's own config always wins over the global one.
106
127
 
107
128
  ## Relations
108
129
 
@@ -110,13 +131,13 @@ The other fields (`pkName`, `relations`, `logLevel`) are checked by TypeScript o
110
131
 
111
132
  The name `relations` appears in **two different places** in the API, with **different shapes and purposes** — easy to confuse. In a nutshell:
112
133
 
113
- | | `relations` in the **constructor** | `relations` in **method options** |
114
- | --- | --- | --- |
115
- | Where you define it | `new Prisma7Adapter(prisma, { relations: ... })` | `repository.get(where, { relations: ... })` — and other methods |
116
- | Shape | One **config object** per field: `{ mode, restriction, pk, nullable? }` | One **`true`/sub-object** per field: `{ posts: true }` |
117
- | Purpose | **Write** — when a `create`/`update`/`upsert`/`save` payload contains a relation field, tells the adapter how to turn it into a Prisma nested write (`create`/`connectOrCreate`/`upsert`/`disconnect`/`deleteMany`/`set`) | **Read** — eager loading: which relations to fetch alongside the result (becomes a Prisma `include`) |
118
- | Consumed by | `parsePrismaWriteData` (write resolver) | `parsePrismaInclude` (via `resolveReadArg`) |
119
- | Depends on the other? | No — it only affects writes | No — it works even with no `relations` in the constructor |
134
+ | | `relations` in the **constructor** | `relations` in **method options** |
135
+ | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
136
+ | Where you define it | `new Prisma7Adapter(prisma, { relations: ... })` | `repository.get(where, { relations: ... })` — and other methods |
137
+ | Shape | One **config object** per field (`{ mode, pk, onUpdate?, onDisconnect?, fkHere?, fkThere? }`), or `"ignore"` | One **`true`/sub-object** per field: `{ posts: true }` |
138
+ | Purpose | **Write** — when a `create`/`update`/`upsert`/`save` payload contains a relation field, tells the adapter how to turn it into a Prisma nested write (`create`/`connect`/`connectOrCreate`/`upsert`/`disconnect`/`deleteMany`/`set`) | **Read** — eager loading: which relations to fetch alongside the result (becomes a Prisma `include`) |
139
+ | Consumed by | `parsePrismaWriteData` (write resolver) | `parsePrismaInclude` (via `resolveReadArg`) |
140
+ | Depends on the other? | No — it only affects writes | No — it works even with no `relations` in the constructor |
120
141
 
121
142
  Neither depends on the other: the method-options `relations` does eager loading even when the constructor has no `relations`, and the constructor `relations` governs write behavior even if you never pass `relations` in options. The two subsections below cover each one.
122
143
 
@@ -128,9 +149,10 @@ Each relation is configured by its field name:
128
149
 
129
150
  ```typescript
130
151
  relations: {
131
- posts: { mode: "otm", restriction: "add", pk: "id" },
132
- address: { mode: "oto", restriction: "set", pk: "id" },
133
- author: { mode: "mto", restriction: "set", pk: "id", nullable: true },
152
+ posts: { mode: "otm", pk: "id", onUpdate: "set" },
153
+ address: { mode: "oto", pk: "id", onUpdate: "upsert", onDisconnect: "delete" },
154
+ author: { mode: "mto", pk: "id" }, // every option has a default
155
+ audit: "ignore", // never written through this repository
134
156
  }
135
157
  ```
136
158
 
@@ -140,32 +162,103 @@ Without `relations`, every field — including relation fields — is passed str
140
162
 
141
163
  Cardinality of the relation, from the point of view of the entity that owns the field:
142
164
 
143
- | `mode` | Meaning | Field shape you send |
144
- | --- | --- | --- |
145
- | `oto` | one-to-one | a single object, or `null` |
146
- | `mto` | many-to-one | a single object, or `null` |
147
- | `otm` | one-to-many | an array of objects |
148
- | `mtm` | many-to-many | an array of objects |
165
+ | `mode` | Meaning | Field shape you send | Options |
166
+ | ------ | ------------ | -------------------------- | ------------------------------------------------------------------------------------------ |
167
+ | `oto` | one-to-one | a single object, or `null` | `pk`, `onUpdate` (to-one), `onDisconnect` (`"disconnect"`/`"delete"`), `fkHere`, `fkThere` |
168
+ | `mto` | many-to-one | a single object, or `null` | `pk`, `onUpdate` (to-one), `onDisconnect` (`"disconnect"`/`"delete"`), `fkHere`, `fkThere` |
169
+ | `otm` | one-to-many | an array of objects | `pk`, `onUpdate` (to-many), `fkThere` |
170
+ | `mtm` | many-to-many | an array of objects | `pk`, `onUpdate` (to-many), `fkThere` |
171
+
172
+ #### `pk`
173
+
174
+ The field used to identify an existing related record. An item **with** `pk` in the payload is connected to (or upserted into) the existing record; an item **without** it is created.
175
+
176
+ #### `onUpdate`
149
177
 
150
- #### `restriction`
178
+ How `save`/`update`/`upsert` write the relation on update. The values accepted depend on the `mode`.
151
179
 
152
- Controls how `save`/`update`/`upsert` handle relation items that already exist (matched by `pk`) and, for to-many relations, items that were **not** included in the payload:
180
+ **To-one (`oto`/`mto`)**, when the related object has its `pk`:
153
181
 
154
- - **`"add"`** — only creates/connects/upserts the items you send. Existing items that aren't in the payload are left untouched.
155
- - **`"set"`** — same as `"add"`, but also removes what wasn't sent: for `otm` it runs a `deleteMany` on the items missing from the array; for `mtm` it resets the join (`set: []`) before reconnecting; for `oto`/`mto` with `nullable: true`, sending `null` deletes/disconnects the relation (see below).
182
+ - **`"connect"`** never creates nor overwrites the related record: it only points the relation to it.
183
+ - **`"connectOrCreate"`** creates the related record when it is missing.
184
+ - **`"upsert"`** is the one that **overwrites** the related record with the fields you sent.
185
+ - When the owner record itself is being created (`create`, or the `create` branch of `save`), a related object with `pk` always becomes a `connectOrCreate`.
156
186
 
157
- #### `pk` and `nullable`
187
+ **To-many (`otm`/`mtm`)**, for the items that already exist (matched by `pk`) and for the ones that were **not** sent:
158
188
 
159
- - **`pk`** — the field used to identify an existing related record. An item **with** `pk` in the payload becomes a `connectOrCreate`/`upsert`; an item **without** it becomes a plain `create`.
160
- - **`nullable`** — relevant for `oto`/`mto` to-one relations. When `true`, sending `null` for the field resolves to `disconnect` on update (`delete` instead for `oto` with `restriction: "set"` — an `oto` side can't just be "disconnected", the owned row is removed). When omitted/`false`, sending `null` for a to-one relation throws a `VSRepoAdapterError` (code `INVALID_DATA`) telling you the relation is not nullable.
189
+ - **`"add"`** (default) — only creates/connects/upserts the items you send. Existing items that aren't in the payload are left untouched.
190
+ - **`"set"`** — same as `"add"`, but also removes what wasn't sent: `otm` runs a `deleteMany` on the items missing from the array, and `mtm` resets the join (`set: []`) before reconnecting.
191
+
192
+ #### `onDisconnect`
193
+
194
+ What sending `null` to a to-one relation does on update:
195
+
196
+ - **`"disconnect"`** (default) — detaches the related record and keeps it. Prisma rejects it when the relation is required.
197
+ - **`"delete"`** — deletes the related record. Available for `oto` and `mto`, and always opt-in. Be careful on an `mto`: the related record is shared with other rows, so deleting it affects all of them, and Prisma rejects the write while other rows still reference it (unless the FK has a referential action such as `onDelete: Cascade`).
198
+
199
+ #### Ignoring a relation (`"ignore"`)
200
+
201
+ Setting a relation to `"ignore"` leaves that field out of every write (`create`, `update`, `save`...): the object (or array) is simply dropped. It is useful for a relation you **load** but don't want to **persist** through this entity.
202
+
203
+ ```typescript
204
+ // AddressRepository
205
+ relations: {
206
+ user: "ignore";
207
+ }
208
+ ```
209
+
210
+ Since the relation object is dropped, a scalar FK in the payload (`userId`) goes through as is, together with the primary key. That makes it the simplest way around the [`allowOmitPk` problem](#allowomitpk) when you only want to keep the FK: `address.save(addressLoadedWithItsUser)` updates the address and never touches the user.
211
+
212
+ #### `fkHere` and `fkThere`
213
+
214
+ In a one-to-one or many-to-one relation, only one side keeps the foreign key column. For `Address.user`, that's `Address.userId`. Tell the adapter which side each entity is on:
215
+
216
+ | Entity | Relation field | Holds the FK? | Config |
217
+ | ---------------------- | -------------- | --------------------------------------------------- | ------------------- |
218
+ | `Address` (owner side) | `user` | **yes** — `userId` is a column of `Address` | `fkHere: "userId"` |
219
+ | `User` (inverse side) | `address` | no — the FK lives in the related entity (`Address`) | `fkThere: "userId"` |
220
+
221
+ ```typescript
222
+ // UserRepository
223
+ relations: { address: { mode: "oto", pk: "id", fkThere: "userId" } }
224
+
225
+ // AddressRepository
226
+ relations: { user: { mode: "oto", pk: "id", fkHere: "userId" } }
227
+ ```
228
+
229
+ - **`fkThere`** — name of the FK that lives in the **related** entity. A related object loaded with `get`/`find` usually carries it (`address: { id, street, userId }`), but the relation already sets it, and Prisma doesn't accept it inside the nested write. The adapter strips it from the related payload(s) before building the write.
230
+ - **`fkHere`** — name of the FK that lives in **this** entity. Prisma doesn't accept the scalar FK together with the relation object, so when the relation field is in the payload the adapter drops this field from `create` and `update`. A payload that carries only the scalar FK (and no relation object) is left as it is.
231
+
232
+ `fkHere` has one more consequence, for the primary key — read the next section.
233
+
234
+ #### `allowOmitPk`
235
+
236
+ `allowOmitPk` is an adapter option (it can also be set in the [global config](#global-config)), but it only matters for relations configured with `fkHere`.
237
+
238
+ **The problem.** Take an `Address` loaded together with its `user` (`relations: { user: true }`) and sent back to `save`. The payload has the primary key (`id`) **and** a relation that holds its FK in the entity itself. Once the relation object is there, Prisma won't take the scalar FK nor the primary key (`Unknown argument 'id'`), so the adapter can't send everything.
239
+
240
+ **What the adapter does:**
241
+
242
+ - **`allowOmitPk: false`** (default) — throws a `VSRepoAdapterError` (`INVALID_DATA`) **before** touching the database, explaining what to do. Payloads without a primary key (e.g. a plain `create`), or without the relation object, are not affected.
243
+ - **`allowOmitPk: true`** — drops the primary key from `create` and `update`. Records that already exist are still found through `where: { id }`, so **updates work normally**. The catch is the `create` branch of `save`: if the record doesn't exist yet, it is created with a **database-generated primary key, not the one you sent** — and nothing warns you.
244
+
245
+ **When to turn it on.** Only if you really need it, and only if it's not your application that manages the ids — i.e. the database generates them (`autoincrement`, `uuid()`/`cuid()` defaults, sequences...). If your application assigns the ids (client-generated UUIDs, ids imported from another system, ids that other records already reference), keep it **off**: a record that doesn't exist would silently be stored under a different id.
246
+
247
+ **Ways around it, without `allowOmitPk`:**
248
+
249
+ 1. **Ignore the relation** when you only want to keep the FK: `relations: { user: "ignore" }` (see [Ignoring a relation](#ignoring-a-relation-ignore)). The payload keeps `id` and `userId`, and the related entity is not written.
250
+ 2. **Send the scalar FK instead of the relation object.** `address.save({ id, city, userId })` keeps both `id` and `userId`, since there's no relation object. Persist the related entity on its own (through its repository) when it also changed — ideally in one `transaction`.
251
+ 3. **Send only what changed.** `address.update({ id }, { city })` carries neither the primary key nor the relation.
252
+ 4. **Save from the other side.** `user.save({ ...user, address })` keeps the primary keys (configure `fkThere` there): the FK lives in `Address`, so `User` has no FK of its own to conflict with.
253
+ 5. **Let the database generate the key for new records.** Don't send `id` when creating: `address.create({ city, user })`.
161
254
 
162
255
  #### How each write method resolves relations
163
256
 
164
- | Method | Relations |
165
- | --- | --- |
166
- | `create` | `create`/`connectOrCreate` only (no upsert — there's nothing to update yet) |
167
- | `update` / `upsert` (`update` half) / `save` (upsert branch) | Full resolution: `create`/`connectOrCreate`/`upsert`/`disconnect`/`delete`/`deleteMany`/`set`, per `mode`/`restriction` |
168
- | `createMany` / `createManyReturning` / `updateMany` / `updateManyReturning` | Not supported — throws a `VSRepoAdapterError` naming the offending field if the payload contains a configured relation |
257
+ | Method | Relations |
258
+ | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
259
+ | `create` | `create`/`connectOrCreate` only (no upsert — there's nothing to update yet) |
260
+ | `update` / `upsert` (`update` half) / `save` (upsert branch) | Full resolution: `create`/`connect`/`connectOrCreate`/`upsert`/`disconnect`/`delete`/`deleteMany`/`set`, per `mode`/`onUpdate`/`onDisconnect` |
261
+ | `createMany` / `createManyReturning` / `updateMany` / `updateManyReturning` | Not supported — throws a `VSRepoAdapterError` naming the offending field if the payload contains a configured relation |
169
262
 
170
263
  ### `relations` in method options (read)
171
264
 
@@ -179,10 +272,10 @@ const user = await userRepository.get(
179
272
  "...", // primary key
180
273
  {
181
274
  relations: {
182
- posts: true, // fetch posts along
183
- author: { profile: true }, // and, inside author, its profile (nested eager loading)
275
+ posts: true, // fetch posts along
276
+ author: { profile: true }, // and, inside author, its profile (nested eager loading)
184
277
  },
185
- }
278
+ },
186
279
  );
187
280
  ```
188
281
 
@@ -192,16 +285,14 @@ The `select` and `relations` you pass in the options are turned into a Prisma `s
192
285
 
193
286
  ```ts
194
287
  const prismaSelect = options.select && parsePrismaSelect(options.select);
195
- const prismaInclude = prismaSelect
196
- ? undefined
197
- : options.relations && parsePrismaInclude(options.relations);
288
+ const prismaInclude = prismaSelect ? undefined : options.relations && parsePrismaInclude(options.relations);
198
289
  ```
199
290
 
200
291
  ## Atomic and aggregation methods
201
292
 
202
293
  The adapter implements the 12 abstract methods `VSRepository`'s `increment`/`decrement`/`multiply`/`divide`, their `*Many` counterparts, and `sum`/`average`/`min`/`max` delegate to: `incrementOne`, `decrementOne`, `multiplyOne`, `divideOne`, `incrementMany`, `decrementMany`, `multiplyMany`, `divideMany`, `sum`, `average`, `min`, `max`.
203
294
 
204
- - `incrementOne`/`decrementOne`/`multiplyOne`/`divideOne` translate directly into Prisma's native single-field atomic write — `data: { [field]: { increment: value } }` (and `decrement`/`multiply`/`divide`) — so the operation is evaluated **server-side** against the row's *current* value (`UPDATE ... SET field = field + value`), not as a fetch-then-save round trip on the client. Prisma's `update()` already returns the row reflecting the state *after* the write, so the adapter never issues a follow-up read.
295
+ - `incrementOne`/`decrementOne`/`multiplyOne`/`divideOne` translate directly into Prisma's native single-field atomic write — `data: { [field]: { increment: value } }` (and `decrement`/`multiply`/`divide`) — so the operation is evaluated **server-side** against the row's _current_ value (`UPDATE ... SET field = field + value`), not as a fetch-then-save round trip on the client. Prisma's `update()` already returns the row reflecting the state _after_ the write, so the adapter never issues a follow-up read.
205
296
  - `incrementMany`/`decrementMany`/`multiplyMany`/`divideMany` apply that same native write to **every** record matching `where`, through Prisma's `updateMany`, also evaluated server-side. They return a `{ count }` (`CountResult`) instead of the records.
206
297
  - `sum`/`average`/`min`/`max` translate into Prisma's `aggregate()` with `_sum`/`_avg`/`_min`/`_max: { [field]: true }`. The raw result (`number`, `bigint`, a `Decimal` instance, or `null`) is normalized to `number | null` — `null` is returned as-is (mirroring SQL's `SUM()`/`AVG()`/`MIN()`/`MAX()`, which return `NULL`, not `0`, over an empty set), and a `Decimal`/`DecimalLike` value is converted via its `.toNumber()`.
207
298
 
@@ -234,11 +325,11 @@ const mostExpensive = await productRepository.max("price");
234
325
 
235
326
  Some features this adapter relies on aren't available on every database provider. The adapter checks every feature below upfront and throws a `VSRepoAdapterError` (code `NOT_SUPPORTED`) before touching the database.
236
327
 
237
- | Feature | Supported providers | Not supported |
238
- | --- | --- | --- |
239
- | `ignoreCase` (translated to Prisma's `mode: "insensitive"`; used by `findByXIgnoreCase` dynamic methods) | PostgreSQL, CockroachDB | MySQL, SQLite, SQL Server — MySQL and SQL Server are case-insensitive by default (depending on the collation), so no `mode` is needed there; SQLite is only case-insensitive for ASCII characters |
240
- | `createManyReturning` / `updateManyReturning` (built on Prisma's `createManyAndReturn`/`updateManyAndReturn`) | PostgreSQL, CockroachDB, SQLite | MySQL, SQL Server |
241
- | `ignoreConflicts: true` on `createMany` / `createManyReturning` (Prisma's `skipDuplicates`) | PostgreSQL, MySQL, CockroachDB | SQL Server, SQLite |
328
+ | Feature | Supported providers | Not supported |
329
+ | ------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
330
+ | `ignoreCase` (translated to Prisma's `mode: "insensitive"`; used by `findByXIgnoreCase` dynamic methods) | PostgreSQL, CockroachDB | MySQL, SQLite, SQL Server — MySQL and SQL Server are case-insensitive by default (depending on the collation), so no `mode` is needed there; SQLite is only case-insensitive for ASCII characters |
331
+ | `createManyReturning` / `updateManyReturning` (built on Prisma's `createManyAndReturn`/`updateManyAndReturn`) | PostgreSQL, CockroachDB, SQLite | MySQL, SQL Server |
332
+ | `ignoreConflicts: true` on `createMany` / `createManyReturning` (Prisma's `skipDuplicates`) | PostgreSQL, MySQL, CockroachDB | SQL Server, SQLite |
242
333
 
243
334
  The `like` operator isn't supported on any provider — Prisma has no equivalent, so the adapter throws `NOT_SUPPORTED`. Use `contains`, `startsWith` or `endsWith` instead.
244
335
 
@@ -297,7 +388,7 @@ The adapter uses `VSLogger` (from `vsrepo`) internally: every method logs a `DEB
297
388
 
298
389
  ## Requirements
299
390
 
300
- - `vsrepo` ^3.0.0-dev.2
301
- - `@prisma/client` ^7.10.0
391
+ - `vsrepo` ^3.0.0-dev.3
392
+ - `@prisma/client` ^7.10.1
302
393
  - Node.js `>=22`
303
394
  - A PostgreSQL, CockroachDB, MySQL, SQLite or SQL Server database (all covered by the integration tests)
package/README.pt-BR.md CHANGED
@@ -24,14 +24,19 @@ Implementação de `VSRepoAdapter` para o [VSRepository v3](https://github.com/V
24
24
  - [Instalação](#instalação)
25
25
  - [Uso básico](#uso-básico)
26
26
  - [Config do construtor](#config-do-construtor)
27
+ - [Config global](#config-global)
27
28
  - [Relations](#relations)
28
- - [Os dois `relations`](#os-dois-relations)
29
- - [`relations` no construtor (escrita)](#relations-no-construtor-escrita)
30
- - [`mode`](#mode)
31
- - [`restriction`](#restriction)
32
- - [`pk` e `nullable`](#pk-e-nullable)
33
- - [Como cada método de escrita resolve relations](#como-cada-método-de-escrita-resolve-relations)
34
- - [`relations` nas options (leitura)](#relations-nas-options-leitura)
29
+ - [Os dois `relations`](#os-dois-relations)
30
+ - [`relations` no construtor (escrita)](#relations-no-construtor-escrita)
31
+ - [`mode`](#mode)
32
+ - [`pk`](#pk)
33
+ - [`onUpdate`](#onupdate)
34
+ - [`onDisconnect`](#ondisconnect)
35
+ - [Ignorando uma relation (`"ignore"`)](#ignorando-uma-relation-ignore)
36
+ - [`fkHere` e `fkThere`](#fkhere-e-fkthere)
37
+ - [`allowOmitPk`](#allowomitpk)
38
+ - [Como cada método de escrita resolve relations](#como-cada-método-de-escrita-resolve-relations)
39
+ - [`relations` nas options (leitura)](#relations-nas-options-leitura)
35
40
  - [Métodos atômicos e de agregação](#métodos-atômicos-e-de-agregação)
36
41
  - [`createMany`/`createManyReturning`/`updateMany`/`updateManyReturning` não suportam nested writes](#createmanycreatemanyreturningupdatemanyupdatemanyreturning-não-suportam-nested-writes)
37
42
  - [Limitações por provider](#limitações-por-provider)
@@ -67,7 +72,7 @@ class UserRepository extends VSRepository<User, string, MyOrmTypes> {
67
72
  modelName: "user",
68
73
  pkName: "id",
69
74
  relations: {
70
- posts: { mode: "otm", restriction: "add", pk: "id" },
75
+ posts: { mode: "otm", pk: "id" },
71
76
  },
72
77
  logLevel: VSLogLevel.WARN,
73
78
  }),
@@ -93,6 +98,7 @@ new Prisma7Adapter(prisma, {
93
98
  relations: { ... }, // opcional — ver "relations no construtor (escrita)" abaixo
94
99
  provider: "postgresql", // opcional — detectado a partir do Prisma Client quando omitido
95
100
  logLevel: VSLogLevel.WARN, // opcional — default: VSLogLevel.WARN
101
+ allowOmitPk: false, // opcional — default: false. Leia "`allowOmitPk`" antes de ativar
96
102
  });
97
103
  ```
98
104
 
@@ -102,7 +108,22 @@ Na construção, o adapter confere o Prisma Client e o model, e resolve o provid
102
108
  - um `modelName` sem delegate correspondente no client (`prisma.<modelName>`) lança `MODEL_NOT_FOUND`;
103
109
  - o provider vem do `provider`, quando informado; senão é detectado a partir do client gerado (`_engineConfig.activeProvider`, com fallback pro `provider` do driver adapter). Se não for detectável, a construção lança `NOT_SUPPORTED` — nesse caso, informe o `provider` explicitamente (um de `postgresql`, `cockroachdb`, `mysql`, `sqlite`, `sqlserver`).
104
110
 
105
- Os outros campos (`pkName`, `relations`, `logLevel`) são checados só pelo TypeScript, não em runtime.
111
+ Os outros campos (`pkName`, `relations`, `logLevel`, `allowOmitPk`) são checados só pelo TypeScript, não em runtime.
112
+
113
+ ## Config global
114
+
115
+ `provider`, `logLevel` e `allowOmitPk` podem ser definidos uma vez pra todos os adapters, pelo `setGlobalConfig` estático:
116
+
117
+ ```typescript
118
+ import { VSLogLevel } from "vsrepo";
119
+ import { Prisma7Adapter } from "@vsrepo/prisma7-adapter";
120
+
121
+ Prisma7Adapter.setGlobalConfig({ logLevel: VSLogLevel.WARN });
122
+ ```
123
+
124
+ - Só afeta adapters criados **depois** da chamada, então chame antes de instanciar seus repositories.
125
+ - Cada chamada **substitui** a config global anterior — não faz merge com ela.
126
+ - Um valor definido na config do próprio adapter sempre vence o global.
106
127
 
107
128
  ## Relations
108
129
 
@@ -110,13 +131,13 @@ Os outros campos (`pkName`, `relations`, `logLevel`) são checados só pelo Type
110
131
 
111
132
  O nome `relations` aparece em **dois lugares diferentes** da API, com **formas e propósitos diferentes** — fácil de confundir. Em resumo:
112
133
 
113
- | | `relations` no **construtor** | `relations` nas **options** |
114
- | --- | --- | --- |
115
- | Onde você define | `new Prisma7Adapter(prisma, { relations: ... })` | `repository.get(where, { relations: ... })` — e demais métodos |
116
- | Formato | Um objeto de **configuração** por campo: `{ mode, restriction, pk, nullable? }` | Um objeto por campo **só com `true` ou sub-objeto**: `{ posts: true }` |
117
- | Propósito | **Escrita** — quando um payload de `create`/`update`/`upsert`/`save` tem campo de relação, diz como transformá-lo num nested write do Prisma (`create`/`connectOrCreate`/`upsert`/`disconnect`/`deleteMany`/`set`) | **Leitura** — eager loading: quais relations trazer junto no resultado (vira um `include` do Prisma) |
118
- | Quem consome | `parsePrismaWriteData` (resolver de escrita) | `parsePrismaInclude` (via `resolveReadArg`) |
119
- | Precisa da outra? | Não — só afeta escritas | Não — funciona mesmo sem `relations` no construtor |
134
+ | | `relations` no **construtor** | `relations` nas **options** |
135
+ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
136
+ | Onde você define | `new Prisma7Adapter(prisma, { relations: ... })` | `repository.get(where, { relations: ... })` — e demais métodos |
137
+ | Formato | Um objeto de **configuração** por campo (`{ mode, pk, onUpdate?, onDisconnect?, fkHere?, fkThere? }`), ou `"ignore"` | Um objeto por campo **só com `true` ou sub-objeto**: `{ posts: true }` |
138
+ | Propósito | **Escrita** — quando um payload de `create`/`update`/`upsert`/`save` tem campo de relação, diz como transformá-lo num nested write do Prisma (`create`/`connect`/`connectOrCreate`/`upsert`/`disconnect`/`deleteMany`/`set`) | **Leitura** — eager loading: quais relations trazer junto no resultado (vira um `include` do Prisma) |
139
+ | Quem consome | `parsePrismaWriteData` (resolver de escrita) | `parsePrismaInclude` (via `resolveReadArg`) |
140
+ | Precisa da outra? | Não — só afeta escritas | Não — funciona mesmo sem `relations` no construtor |
120
141
 
121
142
  Nenhum depende do outro: o `relations` das options faz eager loading de leitura mesmo quando o construtor não tem `relations`; e o `relations` do construtor governa o comportamento de escrita mesmo que você nunca passe `relations` nas options. As duas subseções abaixo detalham cada um.
122
143
 
@@ -128,9 +149,10 @@ Cada relation é configurada pelo nome do campo:
128
149
 
129
150
  ```typescript
130
151
  relations: {
131
- posts: { mode: "otm", restriction: "add", pk: "id" },
132
- address: { mode: "oto", restriction: "set", pk: "id" },
133
- author: { mode: "mto", restriction: "set", pk: "id", nullable: true },
152
+ posts: { mode: "otm", pk: "id", onUpdate: "set" },
153
+ address: { mode: "oto", pk: "id", onUpdate: "upsert", onDisconnect: "delete" },
154
+ author: { mode: "mto", pk: "id" }, // toda opção tem default
155
+ audit: "ignore", // nunca é escrita por este repository
134
156
  }
135
157
  ```
136
158
 
@@ -140,32 +162,103 @@ Sem `relations`, todo campo — incluindo campos de relação — é repassado d
140
162
 
141
163
  Cardinalidade da relation, do ponto de vista da entidade dona do campo:
142
164
 
143
- | `mode` | Significado | Formato do campo que você envia |
144
- | --- | --- | --- |
145
- | `oto` | one-to-one | um único objeto, ou `null` |
146
- | `mto` | many-to-one | um único objeto, ou `null` |
147
- | `otm` | one-to-many | um array de objetos |
148
- | `mtm` | many-to-many | um array de objetos |
165
+ | `mode` | Significado | Formato do campo que você envia | Opções |
166
+ | ------ | ------------ | ------------------------------- | ------------------------------------------------------------------------------------------ |
167
+ | `oto` | one-to-one | um único objeto, ou `null` | `pk`, `onUpdate` (to-one), `onDisconnect` (`"disconnect"`/`"delete"`), `fkHere`, `fkThere` |
168
+ | `mto` | many-to-one | um único objeto, ou `null` | `pk`, `onUpdate` (to-one), `onDisconnect` (`"disconnect"`/`"delete"`), `fkHere`, `fkThere` |
169
+ | `otm` | one-to-many | um array de objetos | `pk`, `onUpdate` (to-many), `fkThere` |
170
+ | `mtm` | many-to-many | um array de objetos | `pk`, `onUpdate` (to-many), `fkThere` |
171
+
172
+ #### `pk`
173
+
174
+ O campo usado pra identificar um registro relacionado já existente. Um item **com** `pk` no payload é conectado (ou recebe upsert) ao registro existente; um item **sem** ele é criado.
175
+
176
+ #### `onUpdate`
149
177
 
150
- #### `restriction`
178
+ Como `save`/`update`/`upsert` escrevem a relation no update. Os valores aceitos dependem do `mode`.
151
179
 
152
- Controla como `save`/`update`/`upsert` tratam itens de relação que já existem (casados pela `pk`) e, pra relations to-many, itens que **não** vieram no payload:
180
+ **To-one (`oto`/`mto`)**, quando o objeto relacionado tem a `pk`:
153
181
 
154
- - **`"add"`** — só cria/conecta/faz upsert dos itens enviados. Itens já existentes que não estão no payload permanecem intocados.
155
- - **`"set"`** — igual a `"add"`, mas também remove o que não foi enviado: em `otm` roda um `deleteMany` nos itens que faltam no array; em `mtm` reseta o vínculo (`set: []`) antes de reconectar; em `oto`/`mto` com `nullable: true`, enviar `null` apaga/desconecta a relation (ver abaixo).
182
+ - **`"connect"`** nunca cria nem sobrescreve o registro relacionado: só aponta a relation pra ele.
183
+ - **`"connectOrCreate"`** cria o relacionado quando ele não existe.
184
+ - **`"upsert"`** é a que **sobrescreve** o relacionado com os campos enviados.
185
+ - Quando o próprio registro dono está sendo criado (`create`, ou o ramo `create` do `save`), um relacionado com `pk` sempre vira `connectOrCreate`.
156
186
 
157
- #### `pk` e `nullable`
187
+ **To-many (`otm`/`mtm`)**, pros itens que já existem (casados por `pk`) e pros que **não** foram enviados:
158
188
 
159
- - **`pk`** — o campo usado pra identificar um registro relacionado já existente. Um item **com** `pk` no payload vira um `connectOrCreate`/`upsert`; um item **sem** `pk` vira um `create` simples.
160
- - **`nullable`** — relevante pras relações to-one `oto`/`mto`. Quando `true`, enviar `null` no campo resolve pra `disconnect` no update (`delete` no caso de `oto` com `restriction: "set"` — um lado `oto` não dá só pra "desconectar", a linha possuída é removida). Quando omitido/`false`, enviar `null` numa relação to-one lança um `VSRepoAdapterError` (code `INVALID_DATA`) avisando que a relation não é nullable.
189
+ - **`"add"`** (default) — só cria/conecta/faz upsert dos itens enviados. Itens já existentes que não estão no payload permanecem intocados.
190
+ - **`"set"`** — igual ao `"add"`, mas também remove o que não foi enviado: `otm` roda um `deleteMany` nos itens ausentes do array, e `mtm` zera o join (`set: []`) antes de reconectar.
191
+
192
+ #### `onDisconnect`
193
+
194
+ O que enviar `null` pra uma relation to-one faz no update:
195
+
196
+ - **`"disconnect"`** (default) — desanexa o registro relacionado e o mantém. O Prisma rejeita quando a relation é obrigatória.
197
+ - **`"delete"`** — apaga o registro relacionado. Existe pra `oto` e `mto`, e é sempre opt-in. Cuidado num `mto`: o relacionado é compartilhado com outras linhas, então apagar afeta todas elas, e o Prisma rejeita a escrita enquanto outras linhas ainda o referenciam (a menos que a FK tenha uma ação referencial como `onDelete: Cascade`).
198
+
199
+ #### Ignorando uma relation (`"ignore"`)
200
+
201
+ Definir uma relation como `"ignore"` deixa o campo fora de toda escrita (`create`, `update`, `save`...): o objeto (ou array) é simplesmente descartado. Serve pra uma relation que você **carrega** mas não quer **persistir** por essa entidade.
202
+
203
+ ```typescript
204
+ // AddressRepository
205
+ relations: {
206
+ user: "ignore";
207
+ }
208
+ ```
209
+
210
+ Como o objeto de relation é descartado, uma FK escalar no payload (`userId`) passa como está, junto da primary key. Isso faz dela a forma mais simples de contornar o [problema do `allowOmitPk`](#allowomitpk) quando você só quer manter a FK: `address.save(addressCarregadoComUser)` atualiza o address e nunca toca no user.
211
+
212
+ #### `fkHere` e `fkThere`
213
+
214
+ Numa relation one-to-one ou many-to-one, só um dos lados guarda a coluna da foreign key. Em `Address.user`, é a `Address.userId`. Informe ao adapter em qual lado cada entidade está:
215
+
216
+ | Entidade | Campo da relation | Guarda a FK? | Config |
217
+ | --------------------- | ----------------- | --------------------------------------------------- | ------------------- |
218
+ | `Address` (lado dono) | `user` | **sim** — `userId` é uma coluna de `Address` | `fkHere: "userId"` |
219
+ | `User` (lado inverso) | `address` | não — a FK fica na entidade relacionada (`Address`) | `fkThere: "userId"` |
220
+
221
+ ```typescript
222
+ // UserRepository
223
+ relations: { address: { mode: "oto", pk: "id", fkThere: "userId" } }
224
+
225
+ // AddressRepository
226
+ relations: { user: { mode: "oto", pk: "id", fkHere: "userId" } }
227
+ ```
228
+
229
+ - **`fkThere`** — nome da FK que fica na entidade **relacionada**. Um objeto relacionado carregado com `get`/`find` normalmente a traz (`address: { id, street, userId }`), mas a relation já define esse valor, e o Prisma não aceita ela dentro do nested write. O adapter remove a FK do(s) payload(s) relacionado(s) antes de montar a escrita.
230
+ - **`fkHere`** — nome da FK que fica **nesta** entidade. O Prisma não aceita a FK escalar junto do objeto de relation, então, quando o campo da relation está no payload, o adapter remove esse campo do `create` e do `update`. Um payload que traz só a FK escalar (sem o objeto de relation) fica como está.
231
+
232
+ O `fkHere` tem mais uma consequência, pra primary key — leia a próxima seção.
233
+
234
+ #### `allowOmitPk`
235
+
236
+ `allowOmitPk` é uma opção do adapter (também dá pra definir na [config global](#config-global)), mas só importa pra relations configuradas com `fkHere`.
237
+
238
+ **O problema.** Pegue um `Address` carregado junto com o `user` (`relations: { user: true }`) e enviado de volta pro `save`. O payload tem a primary key (`id`) **e** uma relation que guarda a FK na própria entidade. Com o objeto de relation presente, o Prisma não aceita nem a FK escalar nem a primary key (`Unknown argument 'id'`), então o adapter não consegue enviar tudo.
239
+
240
+ **O que o adapter faz:**
241
+
242
+ - **`allowOmitPk: false`** (default) — lança um `VSRepoAdapterError` (`INVALID_DATA`) **antes** de tocar no banco, explicando o que fazer. Payloads sem primary key (um `create` simples, por exemplo) ou sem o objeto de relation não são afetados.
243
+ - **`allowOmitPk: true`** — remove a primary key do `create` e do `update`. Registros que já existem continuam sendo achados pelo `where: { id }`, então **os updates funcionam normalmente**. O porém é o ramo `create` do `save`: se o registro ainda não existe, ele é criado com uma **primary key gerada pelo banco, e não a que você enviou** — e nada te avisa disso.
244
+
245
+ **Quando ativar.** Só se for realmente necessário, e só se não for a sua aplicação que gerencia os ids — ou seja, o banco os gera (`autoincrement`, defaults `uuid()`/`cuid()`, sequences...). Se a aplicação atribui os ids (UUIDs gerados no client, ids importados de outro sistema, ids que outros registros já referenciam), mantenha **desativado**: um registro que não existe seria gravado, sem aviso, com outro id.
246
+
247
+ **Formas de contornar, sem `allowOmitPk`:**
248
+
249
+ 1. **Ignorar a relation** quando você só quer manter a FK: `relations: { user: "ignore" }` (veja [Ignorando uma relation](#ignorando-uma-relation-ignore)). O payload mantém `id` e `userId`, e a entidade relacionada não é escrita.
250
+ 2. **Enviar a FK escalar no lugar do objeto de relation.** `address.save({ id, city, userId })` mantém `id` e `userId`, já que não há objeto de relation. Persista a entidade relacionada por conta própria (pelo repository dela) quando ela também mudou — de preferência numa só `transaction`.
251
+ 3. **Enviar só o que mudou.** `address.update({ id }, { city })` não carrega nem a primary key nem a relation.
252
+ 4. **Salvar pelo outro lado.** `user.save({ ...user, address })` mantém as primary keys (configure o `fkThere` lá): a FK fica em `Address`, então `User` não tem FK própria pra conflitar.
253
+ 5. **Deixar o banco gerar a key dos registros novos.** Não envie `id` ao criar: `address.create({ city, user })`.
161
254
 
162
255
  #### Como cada método de escrita resolve relations
163
256
 
164
- | Método | Relations |
165
- | --- | --- |
166
- | `create` | Só `create`/`connectOrCreate` (sem upsert — ainda não existe nada pra atualizar) |
167
- | `update` / `upsert` (metade do `update`) / `save` (branch de upsert) | Resolução completa: `create`/`connectOrCreate`/`upsert`/`disconnect`/`delete`/`deleteMany`/`set`, conforme `mode`/`restriction` |
168
- | `createMany` / `createManyReturning` / `updateMany` / `updateManyReturning` | Não suportado — lança um `VSRepoAdapterError` apontando o campo problemático se o payload tiver uma relation configurada |
257
+ | Método | Relations |
258
+ | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
259
+ | `create` | Só `create`/`connectOrCreate` (sem upsert — ainda não existe nada pra atualizar) |
260
+ | `update` / `upsert` (metade do `update`) / `save` (branch de upsert) | Resolução completa: `create`/`connect`/`connectOrCreate`/`upsert`/`disconnect`/`delete`/`deleteMany`/`set`, conforme `mode`/`onUpdate`/`onDisconnect` |
261
+ | `createMany` / `createManyReturning` / `updateMany` / `updateManyReturning` | Não suportado — lança um `VSRepoAdapterError` apontando o campo problemático se o payload tiver uma relation configurada |
169
262
 
170
263
  ### `relations` nas options (leitura)
171
264
 
@@ -179,10 +272,10 @@ const user = await userRepository.get(
179
272
  "...", // primary key
180
273
  {
181
274
  relations: {
182
- posts: true, // carrega os posts junto
183
- author: { profile: true }, // e, dentro do author, o profile (eager loading aninhado)
275
+ posts: true, // carrega os posts junto
276
+ author: { profile: true }, // e, dentro do author, o profile (eager loading aninhado)
184
277
  },
185
- }
278
+ },
186
279
  );
187
280
  ```
188
281
 
@@ -192,16 +285,14 @@ O `select` e o `relations` que você passa nas options são transformados num `s
192
285
 
193
286
  ```ts
194
287
  const prismaSelect = options.select && parsePrismaSelect(options.select);
195
- const prismaInclude = prismaSelect
196
- ? undefined
197
- : options.relations && parsePrismaInclude(options.relations);
288
+ const prismaInclude = prismaSelect ? undefined : options.relations && parsePrismaInclude(options.relations);
198
289
  ```
199
290
 
200
291
  ## Métodos atômicos e de agregação
201
292
 
202
293
  O adapter implementa os 12 métodos abstratos pros quais `increment`/`decrement`/`multiply`/`divide`, suas versões `*Many` e `sum`/`average`/`min`/`max` do `VSRepository` delegam: `incrementOne`, `decrementOne`, `multiplyOne`, `divideOne`, `incrementMany`, `decrementMany`, `multiplyMany`, `divideMany`, `sum`, `average`, `min`, `max`.
203
294
 
204
- - `incrementOne`/`decrementOne`/`multiplyOne`/`divideOne` traduzem direto pra escrita atômica nativa de campo único do Prisma — `data: { [field]: { increment: value } }` (e `decrement`/`multiply`/`divide`) — então a operação é avaliada **server-side** contra o valor *atual* do registro (`UPDATE ... SET field = field + value`), e não como um fetch-then-save no cliente. O `update()` do Prisma já retorna a linha refletindo o estado *após* a escrita, então o adapter nunca precisa fazer uma leitura extra.
295
+ - `incrementOne`/`decrementOne`/`multiplyOne`/`divideOne` traduzem direto pra escrita atômica nativa de campo único do Prisma — `data: { [field]: { increment: value } }` (e `decrement`/`multiply`/`divide`) — então a operação é avaliada **server-side** contra o valor _atual_ do registro (`UPDATE ... SET field = field + value`), e não como um fetch-then-save no cliente. O `update()` do Prisma já retorna a linha refletindo o estado _após_ a escrita, então o adapter nunca precisa fazer uma leitura extra.
205
296
  - `incrementMany`/`decrementMany`/`multiplyMany`/`divideMany` aplicam essa mesma escrita nativa em **todo** registro que casa com `where`, através do `updateMany` do Prisma, também avaliada server-side. Eles retornam um `{ count }` (`CountResult`) em vez dos registros.
206
297
  - `sum`/`average`/`min`/`max` traduzem pro `aggregate()` do Prisma, com `_sum`/`_avg`/`_min`/`_max: { [field]: true }`. O resultado bruto (`number`, `bigint`, uma instância de `Decimal`, ou `null`) é normalizado pra `number | null` — `null` é repassado como está (espelhando o `SUM()`/`AVG()`/`MIN()`/`MAX()` do SQL, que retornam `NULL`, não `0`, sobre um conjunto vazio), e um valor `Decimal`/`DecimalLike` é convertido via seu `.toNumber()`.
207
298
 
@@ -234,11 +325,11 @@ const mostExpensive = await productRepository.max("price");
234
325
 
235
326
  Alguns recursos que esse adapter usa não estão disponíveis em todo banco. O adapter checa todos os recursos abaixo antecipadamente e lança um `VSRepoAdapterError` (code `NOT_SUPPORTED`) antes de tocar no banco.
236
327
 
237
- | Recurso | Providers com suporte | Sem suporte |
238
- | --- | --- | --- |
239
- | `ignoreCase` (traduzido pro `mode: "insensitive"` do Prisma; usado pelos métodos dinâmicos `findByXIgnoreCase`) | PostgreSQL, CockroachDB | MySQL, SQLite, SQL Server — MySQL e SQL Server já são case-insensitive por padrão (conforme a collation), então não precisam de `mode`; SQLite só é case-insensitive pra caracteres ASCII |
240
- | `createManyReturning` / `updateManyReturning` (baseados no `createManyAndReturn`/`updateManyAndReturn` do Prisma) | PostgreSQL, CockroachDB, SQLite | MySQL, SQL Server |
241
- | `ignoreConflicts: true` no `createMany` / `createManyReturning` (o `skipDuplicates` do Prisma) | PostgreSQL, MySQL, CockroachDB | SQL Server, SQLite |
328
+ | Recurso | Providers com suporte | Sem suporte |
329
+ | ----------------------------------------------------------------------------------------------------------------- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
330
+ | `ignoreCase` (traduzido pro `mode: "insensitive"` do Prisma; usado pelos métodos dinâmicos `findByXIgnoreCase`) | PostgreSQL, CockroachDB | MySQL, SQLite, SQL Server — MySQL e SQL Server já são case-insensitive por padrão (conforme a collation), então não precisam de `mode`; SQLite só é case-insensitive pra caracteres ASCII |
331
+ | `createManyReturning` / `updateManyReturning` (baseados no `createManyAndReturn`/`updateManyAndReturn` do Prisma) | PostgreSQL, CockroachDB, SQLite | MySQL, SQL Server |
332
+ | `ignoreConflicts: true` no `createMany` / `createManyReturning` (o `skipDuplicates` do Prisma) | PostgreSQL, MySQL, CockroachDB | SQL Server, SQLite |
242
333
 
243
334
  O operador `like` não é suportado em nenhum provider — o Prisma não tem equivalente, então o adapter lança `NOT_SUPPORTED`. Use `contains`, `startsWith` ou `endsWith`.
244
335
 
@@ -297,7 +388,7 @@ O adapter usa o `VSLogger` (de `vsrepo`) internamente: todo método loga uma lin
297
388
 
298
389
  ## Requisitos
299
390
 
300
- - `vsrepo` ^3.0.0-dev.2
301
- - `@prisma/client` ^7.10.0
391
+ - `vsrepo` ^3.0.0-dev.3
392
+ - `@prisma/client` ^7.10.1
302
393
  - Node.js `>=22`
303
394
  - Um banco PostgreSQL, CockroachDB, MySQL, SQLite ou SQL Server (todos cobertos pelos testes de integração)
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  export { VSRepoPrisma7Adapter, VSRepoPrisma7Adapter as Prisma7Adapter } from "./prisma7.adapter.js";
2
- export type { Relation } from "./types/relation.type.js";
2
+ export type { Relation, DisconnectStrategy, RelationMode, ToManyStrategy, ToOneStrategy, } from "./types/relation.type.js";
3
3
  export type { Prisma7OrmTypes } from "./types/prisma7-orm-types.type.js";
4
4
  export type { Prisma7ClientLike } from "./types/prisma7-client-like.type.js";
5
5
  export type { AdapterRelations } from "./types/adapter-relations.type.js";
6
6
  export type { Prisma7AdapterConfig } from "./types/adapter-config.type.js";
7
7
  export type { PrismaClientModels } from "./types/prisma-client-models.type.js";
8
8
  export type { PrismaProvider } from "./types/prisma-provider.type.js";
9
+ export type { Prisma7GlobalConfig } from "./types/prisma7-global-config.type.js";
@@ -4,4 +4,4 @@ export interface PrismaWriteData {
4
4
  create: PlainObject;
5
5
  update: PlainObject;
6
6
  }
7
- export declare function parsePrismaWriteData<T>(obj: PlainObject, pkName: string, relations?: AdapterRelations<T>, omitPkInUpdate?: boolean): PrismaWriteData;
7
+ export declare function parsePrismaWriteData<T>(obj: PlainObject, pkName: string, relations?: AdapterRelations<T>, omitPkInUpdate?: boolean, allowOmitPkWhenNeeded?: boolean): PrismaWriteData;