@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.
@@ -12,42 +12,53 @@ function splitByPk(items, pk) {
12
12
  }
13
13
  return { withPk, withoutPk };
14
14
  }
15
+ /** `Relation.onUpdate` of a to-one relation when the config doesn't set one. */
16
+ const DEFAULT_TO_ONE_STRATEGY = "connect";
17
+ /** `Relation.onUpdate` of a to-many relation when the config doesn't set one. */
18
+ const DEFAULT_TO_MANY_STRATEGY = "add";
19
+ /** `Relation.onDisconnect` of a to-one relation when the config doesn't set one. */
20
+ const DEFAULT_DISCONNECT_STRATEGY = "disconnect";
21
+ /**
22
+ * `update` half of a to-one relation whose related object has its `pk`,
23
+ * according to the relation's `onUpdate` ({@link ToOneStrategy}).
24
+ */
25
+ function resolveExistingToOneUpdate(strategy, pk, where, field) {
26
+ switch (strategy) {
27
+ case "connect":
28
+ return { connect: where };
29
+ case "connectOrCreate":
30
+ return { connectOrCreate: { where, create: field } };
31
+ case "upsert":
32
+ return { upsert: { where, create: field, update: omitKey(field, pk) } };
33
+ }
34
+ }
15
35
  function parseToOneRelation(field, relation) {
36
+ const updateStrategy = relation.onUpdate ?? DEFAULT_TO_ONE_STRATEGY;
16
37
  if (field === null) {
17
- if (!relation.nullable) {
18
- throw new VSRepoAdapterError(`You cannot provide null for a to-one relation when it is not nullable.`, AdapterErrorCode.INVALID_DATA, null);
19
- }
20
- if (relation.mode === "oto") {
21
- if (relation.restriction === "set") {
22
- return { update: { delete: true } };
23
- }
24
- return { update: { disconnect: true } };
25
- }
26
- // relation.mode === "mto"
27
- return { update: { disconnect: true } };
38
+ const disconnectStrategy = relation.onDisconnect ?? DEFAULT_DISCONNECT_STRATEGY;
39
+ return disconnectStrategy === "delete" ? { update: { delete: true } } : { update: { disconnect: true } };
40
+ }
41
+ if (relation.fkThere !== undefined) {
42
+ field = omitKey(field, relation.fkThere);
28
43
  }
29
44
  const pkValue = field[relation.pk];
30
45
  if (pkValue === undefined) {
31
46
  return {
32
47
  create: { create: field },
33
- update: relation.restriction === "add" ? { create: field } : { upsert: { create: field, update: field } },
48
+ update: updateStrategy === "upsert" ? { upsert: { create: field, update: field } } : { create: field },
34
49
  };
35
50
  }
36
- const connectOrCreate = { where: { [relation.pk]: pkValue }, create: field };
51
+ const where = { [relation.pk]: pkValue };
37
52
  return {
38
- create: { connectOrCreate },
39
- update: relation.restriction === "add"
40
- ? { connectOrCreate }
41
- : {
42
- upsert: {
43
- where: { [relation.pk]: pkValue },
44
- create: field,
45
- update: omitKey(field, relation.pk),
46
- },
47
- },
53
+ create: { connectOrCreate: { where, create: field } },
54
+ update: resolveExistingToOneUpdate(updateStrategy, relation.pk, where, field),
48
55
  };
49
56
  }
50
57
  function parseToManyRelation(field, relation) {
58
+ const updateStrategy = relation.onUpdate ?? DEFAULT_TO_MANY_STRATEGY;
59
+ if (relation.fkThere !== undefined) {
60
+ field = field.map(f => omitKey(f, relation.fkThere));
61
+ }
51
62
  const { withPk, withoutPk } = splitByPk(field, relation.pk);
52
63
  const connectOrCreate = withPk.map(item => ({
53
64
  where: { [relation.pk]: item[relation.pk] },
@@ -61,7 +72,7 @@ function parseToManyRelation(field, relation) {
61
72
  update: omitKey(item, relation.pk),
62
73
  }));
63
74
  const create = { create: withoutPk, connectOrCreate };
64
- if (relation.restriction === "add") {
75
+ if (updateStrategy === "add") {
65
76
  return {
66
77
  create,
67
78
  update: relation.mode === "mtm" ? { create: withoutPk, connectOrCreate } : { create: withoutPk, upsert },
@@ -80,9 +91,12 @@ function parseToManyRelation(field, relation) {
80
91
  },
81
92
  };
82
93
  }
83
- export function parsePrismaWriteData(obj, pkName, relations, omitPkInUpdate = false) {
84
- const create = {};
85
- const update = {};
94
+ export function parsePrismaWriteData(obj, pkName, relations, omitPkInUpdate = false, allowOmitPkWhenNeeded = false) {
95
+ let create = {};
96
+ let update = {};
97
+ /** Relation fields that hold their FK in this entity, and those FK fields. */
98
+ const fkHereRelations = [];
99
+ const keysToOmit = [];
86
100
  for (const [key, field] of Object.entries(obj)) {
87
101
  if (field === undefined)
88
102
  continue;
@@ -93,7 +107,13 @@ export function parsePrismaWriteData(obj, pkName, relations, omitPkInUpdate = fa
93
107
  update[key] = field;
94
108
  continue;
95
109
  }
110
+ if (relation === "ignore")
111
+ continue;
96
112
  if (relation.mode === "oto" || relation.mode === "mto") {
113
+ if (relation.fkHere !== undefined) {
114
+ fkHereRelations.push(key);
115
+ keysToOmit.push(relation.fkHere);
116
+ }
97
117
  const parsed = parseToOneRelation(field, relation);
98
118
  if (parsed.create !== undefined)
99
119
  create[key] = parsed.create;
@@ -105,5 +125,24 @@ export function parsePrismaWriteData(obj, pkName, relations, omitPkInUpdate = fa
105
125
  create[key] = parsed.create;
106
126
  update[key] = parsed.update;
107
127
  }
128
+ if (fkHereRelations.length) {
129
+ if (obj[pkName] !== undefined) {
130
+ if (!allowOmitPkWhenNeeded) {
131
+ const fields = fkHereRelations.map(name => `'${name}'`).join(", ");
132
+ throw new VSRepoAdapterError(`Cannot send the primary key '${pkName}' together with the relation field(s) ${fields}: ` +
133
+ `they hold their foreign key in this same entity, and Prisma rejects the primary key ` +
134
+ `in a nested write of that kind ("Unknown argument"). ` +
135
+ `Either remove '${pkName}' from the payload, or set 'allowOmitPk: true' (in the adapter ` +
136
+ `config, or globally through 'setGlobalConfig') so the adapter drops it. Note that, with ` +
137
+ `'allowOmitPk', a record that doesn't exist yet is created with a database-generated ` +
138
+ `'${pkName}' instead of the one you sent.`, AdapterErrorCode.INVALID_DATA, null);
139
+ }
140
+ keysToOmit.push(pkName);
141
+ }
142
+ for (const key of keysToOmit) {
143
+ create = omitKey(create, key);
144
+ update = omitKey(update, key);
145
+ }
146
+ }
108
147
  return { create, update };
109
148
  }
@@ -1,6 +1,7 @@
1
1
  import { AdapterMethodOptions, AdapterQueryOptions, CountResult, DeepPartial, NumericKeys, RestrictAdapterMethodOptions, SimpleAdapterMethodOptions, VSRepoAdapter, VSRepoTransactionOptions, VSRepoWhere, WithIgnoreConflicts } from "vsrepo";
2
2
  import { Prisma7AdapterConfig } from "./types/adapter-config.type.js";
3
3
  import { Prisma7ClientLike } from "./types/prisma7-client-like.type.js";
4
+ import { Prisma7GlobalConfig } from "./types/prisma7-global-config.type.js";
4
5
  /**
5
6
  * `VSRepoAdapter` implementation for Prisma 7.
6
7
  *
@@ -15,7 +16,16 @@ export declare class VSRepoPrisma7Adapter<T, K extends Prisma7ClientLike = Prism
15
16
  private readonly relations?;
16
17
  private readonly logger;
17
18
  private readonly provider;
19
+ /** Whether the primary key may be dropped from a write payload when Prisma can't take it. */
20
+ private readonly allowOmitPk?;
21
+ private static globalConfig;
18
22
  constructor(prisma: K, config: Prisma7AdapterConfig<T, K>);
23
+ /**
24
+ * Sets defaults (`provider`, `logLevel`, `allowOmitPk`) for every adapter
25
+ * created **after** this call. It replaces the previous global config, and
26
+ * the config passed to each adapter's constructor takes precedence.
27
+ */
28
+ static setGlobalConfig(globalConfig: Prisma7GlobalConfig): void;
19
29
  private getPrismaRepository;
20
30
  /** Resolves the "read" part of a Prisma arg: select/include/orderBy/pagination. */
21
31
  private resolveReadArg;
@@ -89,6 +99,8 @@ export declare class VSRepoPrisma7Adapter<T, K extends Prisma7ClientLike = Prism
89
99
  /** Runs `fn` inside a native transaction of the underlying ORM/database. */
90
100
  runInTransaction<R>(fn: (tx: any) => Promise<R>, options?: VSRepoTransactionOptions): Promise<R>;
91
101
  private execMethod;
102
+ /** Runs `parsePrismaWriteData` with this adapter's `pkName`, `relations` and `allowOmitPk`. */
103
+ private parseData;
92
104
  /** Fetches a single record matching `where`. */
93
105
  findOne(where?: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T | null>;
94
106
  /** Fetches a single record matching `where`, throwing if none is found. */
@@ -24,6 +24,9 @@ export class VSRepoPrisma7Adapter extends VSRepoAdapter {
24
24
  relations;
25
25
  logger;
26
26
  provider;
27
+ /** Whether the primary key may be dropped from a write payload when Prisma can't take it. */
28
+ allowOmitPk;
29
+ static globalConfig = {};
27
30
  constructor(prisma, config) {
28
31
  super();
29
32
  this.prisma = prisma;
@@ -31,9 +34,18 @@ export class VSRepoPrisma7Adapter extends VSRepoAdapter {
31
34
  this.modelName = config.modelName;
32
35
  this.pkName = config.pkName;
33
36
  this.relations = config.relations;
34
- this.provider = resolveProvider(prisma, config.provider);
35
- this.logger = new VSLogger(config.logLevel ?? VSLogLevel.WARN, this.constructor.name + "Logger");
36
- this.logger.logInfo(`${this.constructor.name} initialized for table '${this.modelName}' (pkName: '${this.pkName}'${this.relations ? `, relations: [${Object.keys(this.relations).join(", ")}]` : ""}, provider: ${this.provider ? `'${this.provider}'` : "<not detected>"})`);
37
+ this.provider = resolveProvider(prisma, config.provider ?? VSRepoPrisma7Adapter.globalConfig.provider);
38
+ this.logger = new VSLogger(config.logLevel ?? VSRepoPrisma7Adapter.globalConfig.logLevel ?? VSLogLevel.WARN, this.constructor.name + "Logger");
39
+ this.allowOmitPk = config.allowOmitPk ?? VSRepoPrisma7Adapter.globalConfig.allowOmitPk;
40
+ this.logger.logInfo(`${this.constructor.name} initialized for table '${this.modelName}' (pkName: '${this.pkName}'${this.relations ? `, relations: [${Object.keys(this.relations).join(", ")}]` : ""}, provider: ${this.provider ? `'${this.provider}'` : "<not detected>"}${this.allowOmitPk ? ", allowOmitPk: true" : ""})`);
41
+ }
42
+ /**
43
+ * Sets defaults (`provider`, `logLevel`, `allowOmitPk`) for every adapter
44
+ * created **after** this call. It replaces the previous global config, and
45
+ * the config passed to each adapter's constructor takes precedence.
46
+ */
47
+ static setGlobalConfig(globalConfig) {
48
+ this.globalConfig = globalConfig;
37
49
  }
38
50
  getPrismaRepository(db) {
39
51
  return db ? db[this.modelName] : this.prisma[this.modelName];
@@ -240,6 +252,10 @@ export class VSRepoPrisma7Adapter extends VSRepoAdapter {
240
252
  throw mapPrismaError(error, methodName);
241
253
  }
242
254
  }
255
+ /** Runs `parsePrismaWriteData` with this adapter's `pkName`, `relations` and `allowOmitPk`. */
256
+ parseData(obj, omitPkInUpdate) {
257
+ return parsePrismaWriteData(obj, this.pkName, this.relations, omitPkInUpdate, this.allowOmitPk);
258
+ }
243
259
  /** Fetches a single record matching `where`. */
244
260
  async findOne(where, options) {
245
261
  const arg = { ...this.resolveReadArg(options), where: this.parseWhere(where) };
@@ -261,7 +277,7 @@ export class VSRepoPrisma7Adapter extends VSRepoAdapter {
261
277
  const pkValue = objAny[this.pkName];
262
278
  const readArg = this.resolveReadArg({ select: options?.select, relations: options?.relations });
263
279
  const repo = this.getPrismaRepository(options?.db);
264
- const { create, update } = parsePrismaWriteData(objAny, this.pkName, this.relations, true);
280
+ const { create, update } = this.parseData(objAny, true);
265
281
  if (pkValue === undefined) {
266
282
  const arg = { ...readArg, data: create };
267
283
  return this.execMethod(() => repo.create(arg), "save (create)", arg);
@@ -362,7 +378,7 @@ export class VSRepoPrisma7Adapter extends VSRepoAdapter {
362
378
  }
363
379
  /** Updates a single record matching `where`. */
364
380
  async update(where, obj, options) {
365
- const { update } = parsePrismaWriteData(obj, this.pkName, this.relations);
381
+ const { update } = this.parseData(obj);
366
382
  const arg = {
367
383
  ...this.resolveReadArg({ select: options?.select, relations: options?.relations }),
368
384
  where: this.parseWhere(where),
@@ -445,7 +461,7 @@ export class VSRepoPrisma7Adapter extends VSRepoAdapter {
445
461
  }
446
462
  /** Creates a single record. */
447
463
  async create(obj, options) {
448
- const { create } = parsePrismaWriteData(obj, this.pkName, this.relations);
464
+ const { create } = this.parseData(obj);
449
465
  const arg = {
450
466
  ...this.resolveReadArg({ select: options?.select, relations: options?.relations }),
451
467
  data: create,
@@ -531,8 +547,8 @@ export class VSRepoPrisma7Adapter extends VSRepoAdapter {
531
547
  // }
532
548
  /** Creates a record if none matches `where`, otherwise updates it. */
533
549
  async upsert(where, create, update, options) {
534
- const parsedCreate = parsePrismaWriteData(create, this.pkName, this.relations).create;
535
- const parsedUpdate = parsePrismaWriteData(update, this.pkName, this.relations).update;
550
+ const parsedCreate = this.parseData(create).create;
551
+ const parsedUpdate = this.parseData(update).update;
536
552
  const arg = {
537
553
  ...this.resolveReadArg({ select: options?.select, relations: options?.relations }),
538
554
  where: this.parseWhere(where),
@@ -30,4 +30,20 @@ export interface Prisma7AdapterConfig<T = any, K extends Prisma7ClientLike = Pri
30
30
  provider?: PrismaProvider;
31
31
  /** Minimum log level for the adapter's internal `VSLogger`. @default VSLogLevel.WARN */
32
32
  logLevel?: VSLogLevel;
33
+ /**
34
+ * Lets the adapter drop the primary key from a write payload when it can't
35
+ * be sent. That happens when the payload has a relation that holds its
36
+ * foreign key in this same entity (`fkHere`, e.g. `Address.user`): Prisma
37
+ * doesn't accept the primary key in that kind of nested write. When `false`,
38
+ * such a payload throws `INVALID_DATA`.
39
+ *
40
+ * **Careful:** with this on, `save` with a primary key that doesn't exist
41
+ * yet creates the record with a database-generated key, not the one you
42
+ * sent. Only enable it if you really need it and if the database (not your
43
+ * application) generates the ids. Falls back to the global config
44
+ * (`setGlobalConfig`) when omitted.
45
+ *
46
+ * @default false
47
+ */
48
+ allowOmitPk?: boolean;
33
49
  }
@@ -1,16 +1,22 @@
1
1
  import type { RelationKeys } from "vsrepo";
2
2
  import { Relation } from "./relation.type.js";
3
3
  /**
4
- * Relation configuration for entity `T`, used by the `create`/`update`
5
- * parsers to resolve relation fields according to the v1 behavior (see
6
- * `Relation`).
4
+ * Relation configuration for entity `T`, used by the write parsers to resolve
5
+ * relation fields into Prisma nested writes (see `Relation`).
7
6
  *
8
- * Keyed by the relation fields of `T` (`RelationKeys<T>`). Without this
9
- * configuration (adapter built without `relations`), relation fields are
10
- * passed through to Prisma as-is, with no special resolution.
7
+ * Keyed by the relation fields of `T` (`RelationKeys<T>`). Each value is either:
8
+ *
9
+ * - a `Relation` config, whose options depend on its `mode`; or
10
+ * - `"ignore"`, which leaves the field out of every write (`create`, `update`,
11
+ * `save`...). Use it for a relation you load but don't want to persist
12
+ * through this entity. Since the relation object is dropped, a scalar FK in
13
+ * the payload (e.g. `userId`) is sent as is, together with the primary key.
14
+ *
15
+ * Without this configuration (adapter built without `relations`), relation
16
+ * fields are passed through to Prisma as-is, with no special resolution.
11
17
  *
12
18
  * @publicApi
13
19
  */
14
20
  export type AdapterRelations<T> = Partial<{
15
- [P in RelationKeys<T>]: Relation<NonNullable<T[P]> extends Array<infer U> ? U : NonNullable<T[P]>>;
21
+ [P in RelationKeys<T>]: "ignore" | Relation<NonNullable<T[P]> extends Array<infer U> ? U : NonNullable<T[P]>, T>;
16
22
  }>;
@@ -0,0 +1,17 @@
1
+ import { VSLogLevel } from "vsrepo";
2
+ import { PrismaProvider } from "./prisma-provider.type.js";
3
+ /**
4
+ * Defaults applied to every adapter instance, set through
5
+ * `VSRepoPrisma7Adapter.setGlobalConfig`. A field set in an adapter's own
6
+ * config wins over the global one.
7
+ *
8
+ * @publicApi
9
+ */
10
+ export type Prisma7GlobalConfig = {
11
+ /** Default `provider` (see `Prisma7AdapterConfig.provider`). */
12
+ provider?: PrismaProvider;
13
+ /** Default `logLevel` (see `Prisma7AdapterConfig.logLevel`). */
14
+ logLevel?: VSLogLevel;
15
+ /** Default `allowOmitPk` (see `Prisma7AdapterConfig.allowOmitPk`). @default false */
16
+ allowOmitPk?: boolean;
17
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,35 +1,123 @@
1
1
  /**
2
- * Configuration of a single relation field.
2
+ * Cardinality of a relation from the point of view of the entity that owns the
3
+ * field: `oto` = one-to-one, `mto` = many-to-one, `otm` = one-to-many and
4
+ * `mtm` = many-to-many.
3
5
  *
4
6
  * @publicApi
5
7
  */
6
- export interface Relation<T = any> {
8
+ export type RelationMode = "oto" | "mto" | "otm" | "mtm";
9
+ /**
10
+ * How a to-one relation (`oto`/`mto`) is written on update when the related
11
+ * object has its `pk`. Pick it through `Relation.onUpdate`.
12
+ *
13
+ * - `"connect"` (default) — only connects the record. It never creates nor
14
+ * overwrites the related record, so re-sending the one that is already
15
+ * connected is a no-op and switching to another record works. Fails with
16
+ * Prisma's `P2025` when the record doesn't exist.
17
+ * - `"connectOrCreate"` — connects the record, creating it when missing.
18
+ * - `"upsert"` — updates the related record with the fields you sent (everything
19
+ * but its `pk`), creating it when missing.
20
+ *
21
+ * Without the related `pk` there is nothing to connect to: the record is
22
+ * created (`"upsert"` still sends its fields as the `update`).
23
+ *
24
+ * @publicApi
25
+ */
26
+ export type ToOneStrategy = "connect" | "connectOrCreate" | "upsert";
27
+ /**
28
+ * How a to-many relation (`otm`/`mtm`) is written on update. Pick it through
29
+ * `Relation.onUpdate`.
30
+ *
31
+ * - `"add"` (default) — only creates/connects/upserts the items you send.
32
+ * Whatever else is already related is left untouched.
33
+ * - `"set"` — also removes (`otm`: `deleteMany`) or disconnects (`mtm`: `set`)
34
+ * every related item that wasn't sent.
35
+ *
36
+ * @publicApi
37
+ */
38
+ export type ToManyStrategy = "add" | "set";
39
+ /**
40
+ * What sending `null` to a to-one relation does on update. Pick it through
41
+ * `Relation.onDisconnect`.
42
+ *
43
+ * - `"disconnect"` (default) — detaches the related record and keeps it.
44
+ * Needs the relation (its FK) to be optional.
45
+ * - `"delete"` — deletes the related record. It is always opt-in. On an `mto`
46
+ * the related record is shared with other rows, so deleting it affects all of them.
47
+ *
48
+ * @publicApi
49
+ */
50
+ export type DisconnectStrategy = "disconnect" | "delete";
51
+ /** Options shared by every relation mode. */
52
+ type RelationBase<T, M extends RelationMode> = {
7
53
  /**
8
54
  * Cardinality of the relation from the point of view of the entity
9
- * that owns the field (`oto` = one-to-one, `mto` = many-to-one,
10
- * `otm` = one-to-many, `mtm` = many-to-many).
55
+ * that owns the field. It decides which of the other options are available.
11
56
  */
12
- mode: "otm" | "mtm" | "mto" | "oto";
13
- /**
14
- * How `save`/`update`/`upsert` handle to-many relations
15
- * (`otm`/`mtm`) and to-one relations pointing to an already-existing record
16
- * (matched by `pk`) — `"add"` only creates/connects the items that were
17
- * sent (upsert per item), `"set"` also removes/disconnects whatever wasn't
18
- * sent.
19
- */
20
- restriction: "set" | "add";
57
+ mode: M;
21
58
  /**
22
59
  * Name of the field used as the identifier of the related record,
23
60
  * used to decide between `create` (no pk in the payload) and
24
- * `connectOrCreate`/`upsert` (pk present).
61
+ * connecting to / upserting an existing record (pk present).
62
+ */
63
+ pk: keyof T & string;
64
+ /**
65
+ * Name of the scalar foreign key that lives in the **related** entity —
66
+ * e.g. `userId` in `User.address`, where `Address` holds the FK. The
67
+ * adapter strips it from the related payload(s) before building the
68
+ * nested write, since the relation already sets it.
69
+ */
70
+ fkThere?: keyof T & string;
71
+ };
72
+ /** Options of the `oto` and `mto` relations. */
73
+ type ToOneOptions<K> = {
74
+ /**
75
+ * Name of the scalar foreign key that lives in **this** entity (the one
76
+ * that owns the relation field) — e.g. `userId` in `Address.user`. Set it
77
+ * on the owning side of the relation.
78
+ *
79
+ * Prisma doesn't accept the scalar FK next to the relation object, so when
80
+ * the relation is in the payload the adapter drops this field from
81
+ * `create` and `update`. For the same reason it also can't keep the
82
+ * entity's primary key: if the payload has one, the write throws
83
+ * `INVALID_DATA` unless `allowOmitPk` is enabled (see
84
+ * `Prisma7AdapterConfig.allowOmitPk`).
85
+ */
86
+ fkHere?: keyof K & string;
87
+ /**
88
+ * How the related record is written on update when the payload has its `pk`.
89
+ * @default "connect"
90
+ */
91
+ onUpdate?: ToOneStrategy;
92
+ /**
93
+ * What sending `null` does on update.
94
+ * @default "disconnect"
25
95
  */
26
- pk: keyof T;
96
+ onDisconnect?: DisconnectStrategy;
97
+ };
98
+ /** Options of the `otm` and `mtm` relations. */
99
+ type ToManyOptions = {
27
100
  /**
28
- * For `oto`/`mto` relations, whether the field accepts being set
29
- * to `null`. When `true`, sending `null` on update resolves to `delete`
30
- * (`oto` + `restriction: "set"`) or `disconnect` (`oto` + `restriction:
31
- * "add"`, and `mto`). When `false`/omitted, sending `null` for a to-one
32
- * relation throws a `VSRepoAdapterError` (code `INVALID_DATA`).
101
+ * How the related items are written on update.
102
+ * @default "add"
33
103
  */
34
- nullable?: boolean;
35
- }
104
+ onUpdate?: ToManyStrategy;
105
+ };
106
+ /**
107
+ * Configuration of a single relation field:
108
+ *
109
+ * - `oto` and `mto`: `fkHere`, `fkThere`, `onUpdate` ({@link ToOneStrategy}) and
110
+ * `onDisconnect` ({@link DisconnectStrategy}).
111
+ * - `otm` and `mtm`: `fkThere` and `onUpdate` ({@link ToManyStrategy}).
112
+ *
113
+ * Set a relation to `"ignore"` in `AdapterRelations` to leave it out of every
114
+ * write (see `AdapterRelations`).
115
+ *
116
+ * @template T Type of the related entity.
117
+ * @template K Type of the entity that owns the relation field.
118
+ * @template M Narrows the config to some of the modes (all of them by default).
119
+ *
120
+ * @publicApi
121
+ */
122
+ export type Relation<T = any, K = any, M extends RelationMode = RelationMode> = M extends "oto" | "mto" ? RelationBase<T, M> & ToOneOptions<K> : M extends "otm" | "mtm" ? RelationBase<T, M> & ToManyOptions : never;
123
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vsrepo/prisma7-adapter",
3
- "version": "2.0.0-dev",
3
+ "version": "2.0.0-dev.1",
4
4
  "author": {
5
5
  "email": "joaodev.azevedo@outlook.com",
6
6
  "url": "https://github.com/jaobrabo123",
@@ -15,7 +15,7 @@
15
15
  "@prisma/adapter-better-sqlite3": "^7.10.1",
16
16
  "@prisma/adapter-mariadb": "^7.10.1",
17
17
  "@prisma/adapter-mssql": "^7.10.1",
18
- "@prisma/adapter-pg": "^7.10.0",
18
+ "@prisma/adapter-pg": "^7.10.1",
19
19
  "@types/better-sqlite3": "^9.6.0",
20
20
  "@types/mssql": "^12.3.0",
21
21
  "@types/node": "^26.4.0",
@@ -26,14 +26,14 @@
26
26
  "oxlint-tsgolint": "^7.0.2005",
27
27
  "pg": "^8.23.0",
28
28
  "prettier": "^3.9.10",
29
- "prisma": "^7.10.0",
29
+ "prisma": "^7.10.1",
30
30
  "tsx": "^4.23.12",
31
31
  "typescript": "^7.0.2",
32
32
  "vitest": "^5.0.5"
33
33
  },
34
34
  "peerDependencies": {
35
- "@prisma/client": "^7.10.0",
36
- "vsrepo": "^3.0.0-dev.2"
35
+ "@prisma/client": "^7.10.1",
36
+ "vsrepo": "^3.0.0-dev.3"
37
37
  },
38
38
  "exports": {
39
39
  ".": {
@@ -78,8 +78,8 @@
78
78
  "lint:fix": "oxlint --fix src/ test/",
79
79
  "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
80
80
  "format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
81
- "format:docs": "prettier --write \"docs/**/*.md\" \"./*.md\"",
82
- "format:docs:check": "prettier --check \"docs/**/*.md\" \"./*.md\"",
81
+ "format:docs": "prettier --write \"./*.md\"",
82
+ "format:docs:check": "prettier --check \"./*.md\"",
83
83
  "test": "vitest run",
84
84
  "test:watch": "vitest",
85
85
  "test:cov": "vitest run --coverage",