@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/CHANGELOG.md +147 -29
- package/README.md +142 -51
- package/README.pt-BR.md +142 -51
- package/dist/index.d.ts +2 -1
- package/dist/parsers/data.parser.d.ts +1 -1
- package/dist/parsers/data.parser.js +66 -27
- package/dist/prisma7.adapter.d.ts +12 -0
- package/dist/prisma7.adapter.js +24 -8
- package/dist/types/adapter-config.type.d.ts +16 -0
- package/dist/types/adapter-relations.type.d.ts +13 -7
- package/dist/types/prisma7-global-config.type.d.ts +17 -0
- package/dist/types/prisma7-global-config.type.js +1 -0
- package/dist/types/relation.type.d.ts +110 -22
- package/package.json +7 -7
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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",
|
|
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
|
-
|
|
|
114
|
-
|
|
|
115
|
-
| Where you define it
|
|
116
|
-
| Shape
|
|
117
|
-
| Purpose
|
|
118
|
-
| Consumed by
|
|
119
|
-
| Depends on the other? | No — it only affects writes
|
|
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",
|
|
132
|
-
address: { mode: "oto",
|
|
133
|
-
author: { mode: "mto",
|
|
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
|
|
144
|
-
|
|
|
145
|
-
| `oto`
|
|
146
|
-
| `mto`
|
|
147
|
-
| `otm`
|
|
148
|
-
| `mtm`
|
|
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
|
-
|
|
178
|
+
How `save`/`update`/`upsert` write the relation on update. The values accepted depend on the `mode`.
|
|
151
179
|
|
|
152
|
-
|
|
180
|
+
**To-one (`oto`/`mto`)**, when the related object has its `pk`:
|
|
153
181
|
|
|
154
|
-
- **`"
|
|
155
|
-
- **`"
|
|
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
|
-
|
|
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
|
-
- **`
|
|
160
|
-
- **`
|
|
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
|
|
165
|
-
|
|
|
166
|
-
| `create`
|
|
167
|
-
| `update` / `upsert` (`update` half) / `save` (upsert branch)
|
|
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,
|
|
183
|
-
author: { profile: true },
|
|
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
|
|
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
|
|
238
|
-
|
|
|
239
|
-
| `ignoreCase` (translated to Prisma's `mode: "insensitive"`; used by `findByXIgnoreCase` dynamic methods)
|
|
240
|
-
| `createManyReturning` / `updateManyReturning` (built on Prisma's `createManyAndReturn`/`updateManyAndReturn`) | PostgreSQL, CockroachDB, SQLite | MySQL, SQL Server
|
|
241
|
-
| `ignoreConflicts: true` on `createMany` / `createManyReturning` (Prisma's `skipDuplicates`)
|
|
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.
|
|
301
|
-
- `@prisma/client` ^7.10.
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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",
|
|
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
|
-
|
|
|
114
|
-
|
|
|
115
|
-
| Onde você define
|
|
116
|
-
| Formato
|
|
117
|
-
| Propósito
|
|
118
|
-
| Quem consome
|
|
119
|
-
| Precisa da outra? | Não — só afeta escritas
|
|
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",
|
|
132
|
-
address: { mode: "oto",
|
|
133
|
-
author: { mode: "mto",
|
|
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
|
|
144
|
-
|
|
|
145
|
-
| `oto`
|
|
146
|
-
| `mto`
|
|
147
|
-
| `otm`
|
|
148
|
-
| `mtm`
|
|
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
|
-
|
|
178
|
+
Como `save`/`update`/`upsert` escrevem a relation no update. Os valores aceitos dependem do `mode`.
|
|
151
179
|
|
|
152
|
-
|
|
180
|
+
**To-one (`oto`/`mto`)**, quando o objeto relacionado tem a `pk`:
|
|
153
181
|
|
|
154
|
-
- **`"
|
|
155
|
-
- **`"
|
|
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
|
-
|
|
187
|
+
**To-many (`otm`/`mtm`)**, pros itens que já existem (casados por `pk`) e pros que **não** foram enviados:
|
|
158
188
|
|
|
159
|
-
- **`
|
|
160
|
-
- **`
|
|
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
|
|
165
|
-
|
|
|
166
|
-
| `create`
|
|
167
|
-
| `update` / `upsert` (metade do `update`) / `save` (branch de upsert)
|
|
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,
|
|
183
|
-
author: { profile: true },
|
|
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
|
|
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
|
|
238
|
-
|
|
|
239
|
-
| `ignoreCase` (traduzido pro `mode: "insensitive"` do Prisma; usado pelos métodos dinâmicos `findByXIgnoreCase`)
|
|
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)
|
|
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.
|
|
301
|
-
- `@prisma/client` ^7.10.
|
|
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;
|