@nextlyhq/adapter-drizzle 0.0.2-alpha.65 → 0.0.2-alpha.67

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.
Files changed (37) hide show
  1. package/dist/{adapter-C6ENLDau.d.cts → adapter-bUAaPzjV.d.cts} +307 -4
  2. package/dist/{adapter-D4GM1VAZ.d.ts → adapter-iJ5hbUvL.d.ts} +307 -4
  3. package/dist/index.cjs +570 -36
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +2 -2
  6. package/dist/index.d.ts +2 -2
  7. package/dist/index.mjs +571 -37
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/{migration-R06fsTrz.d.ts → migration-BqHebSwM.d.ts} +65 -6
  10. package/dist/{migration-B6AmjCQ1.d.cts → migration-Bu0WLdX4.d.cts} +65 -6
  11. package/dist/migrations.d.cts +3 -3
  12. package/dist/migrations.d.ts +3 -3
  13. package/dist/schema-name.cjs +20 -0
  14. package/dist/schema-name.cjs.map +1 -0
  15. package/dist/schema-name.d.cts +24 -0
  16. package/dist/schema-name.d.ts +24 -0
  17. package/dist/schema-name.mjs +17 -0
  18. package/dist/schema-name.mjs.map +1 -0
  19. package/dist/text-match.cjs +16 -0
  20. package/dist/text-match.cjs.map +1 -0
  21. package/dist/text-match.d.cts +44 -0
  22. package/dist/text-match.d.ts +44 -0
  23. package/dist/text-match.mjs +13 -0
  24. package/dist/text-match.mjs.map +1 -0
  25. package/dist/types/index.cjs +7 -0
  26. package/dist/types/index.cjs.map +1 -1
  27. package/dist/types/index.d.cts +16 -2
  28. package/dist/types/index.d.ts +16 -2
  29. package/dist/types/index.mjs +7 -0
  30. package/dist/types/index.mjs.map +1 -1
  31. package/dist/version-check.cjs +10 -1
  32. package/dist/version-check.cjs.map +1 -1
  33. package/dist/version-check.d.cts +18 -2
  34. package/dist/version-check.d.ts +18 -2
  35. package/dist/version-check.mjs +10 -2
  36. package/dist/version-check.mjs.map +1 -1
  37. package/package.json +14 -4
@@ -1,9 +1,51 @@
1
1
  import { AnyRelations, SQL } from 'drizzle-orm';
2
- import { T as TransactionContext, S as SelectOptions, W as WhereClause, U as UpdateOptions, D as DeleteOptions, e as UpsertOptions, f as TransactionOptions, g as DatabaseCapabilities, P as PoolStats, C as CountOptions, I as InsertOptions, a as Migration, d as MigrationResult } from './migration-B6AmjCQ1.cjs';
2
+ import { T as TransactionContext, S as SelectOptions, W as WhereClause, D as DeleteOptions, U as UpsertOptions, e as TransactionOptions, f as DatabaseCapabilities, P as PoolStats, C as CountOptions, I as InsertOptions, g as UpdateOptions, a as Migration, d as MigrationResult } from './migration-Bu0WLdX4.cjs';
3
3
  import { S as SupportedDialect, a as SqlParam, T as TableResolver } from './core-CVO7WYDj.cjs';
4
4
  import { T as TableDefinition, C as CreateTableOptions, D as DropTableOptions, A as AlterTableOperation, a as AlterTableOptions } from './schema-BDn8WfSL.cjs';
5
5
  import { D as DatabaseErrorKind, a as DatabaseError } from './error-BrdknH2s.cjs';
6
6
 
7
+ /**
8
+ * A pooled adapter's Drizzle transactions, each on a connection the adapter
9
+ * checks out and returns itself.
10
+ *
11
+ * Drizzle's own `transaction()` on a pool checks a connection out, but does
12
+ * not return it as carefully as the adapter's `transaction()` does: it sends
13
+ * BEGIN outside its `try`, so a failed BEGIN never gives the connection back;
14
+ * and when its ROLLBACK fails it hands the connection to the pool as if
15
+ * nothing had happened, possibly still inside the transaction, and throws the
16
+ * ROLLBACK's error in place of the work's. Core services open their
17
+ * transactions through that handle, so it gets the same care here: Drizzle
18
+ * runs the transaction on a connection this module owns, and this module
19
+ * decides how the connection goes back.
20
+ *
21
+ * @module pinned-transaction
22
+ */
23
+ /**
24
+ * Drizzle's database handle, as far as running a transaction goes.
25
+ *
26
+ * The callback takes `unknown` and the options `never`, so every dialect's
27
+ * handle fits, whose callback receives its own transaction type and whose
28
+ * options are its own.
29
+ */
30
+ interface DrizzleTransactor {
31
+ transaction<T>(work: (tx: unknown) => Promise<T>, config?: never): Promise<T>;
32
+ }
33
+ /** One connection a pooled adapter checked out for one transaction. */
34
+ interface PinnedConnection {
35
+ /** Drizzle bound to this connection alone, with the handle's relations. */
36
+ drizzle: DrizzleTransactor;
37
+ /**
38
+ * Sends ROLLBACK on this connection. Harmless when no transaction is open
39
+ * on it: PostgreSQL answers with a warning, MySQL does nothing.
40
+ */
41
+ rollback(): Promise<unknown>;
42
+ /**
43
+ * Gives the connection back: to the pool, or, when `dirty`, closed and
44
+ * removed from it, because it may still be inside the transaction.
45
+ */
46
+ release(dirty: boolean): void;
47
+ }
48
+
7
49
  /**
8
50
  * Transaction CRUD forwarder helper for database adapters.
9
51
  *
@@ -21,15 +63,20 @@ import { D as DatabaseErrorKind, a as DatabaseError } from './error-BrdknH2s.cjs
21
63
  interface TransactionCrudDelegator {
22
64
  select<T = unknown>(table: string, options?: SelectOptions, executor?: unknown): Promise<T[]>;
23
65
  selectOne<T = unknown>(table: string, options?: SelectOptions, executor?: unknown): Promise<T | null>;
24
- update<T = unknown>(table: string, data: Record<string, unknown>, where: WhereClause, options?: UpdateOptions, executor?: unknown): Promise<T[]>;
25
66
  updateCount(table: string, data: Record<string, unknown>, where: WhereClause, executor?: unknown): Promise<number>;
26
67
  delete(table: string, where: WhereClause, options?: DeleteOptions, executor?: unknown): Promise<number>;
27
68
  upsert<T = unknown>(table: string, data: Record<string, unknown>, options: UpsertOptions, executor?: unknown): Promise<T>;
28
69
  }
29
70
  /**
30
71
  * Transaction context CRUD methods provided by the forwarder.
72
+ *
73
+ * `update` is not among them. The pooled `update` goes through the Drizzle
74
+ * query builder, which writes the columns the runtime model declares; a
75
+ * transaction's update must reach the columns the physical table has, and
76
+ * each adapter binds the base class's `transactionUpdate` beside its
77
+ * transactional `insert`.
31
78
  */
32
- type TransactionCrudForwarders = Pick<TransactionContext, "select" | "selectOne" | "update" | "updateCount" | "delete" | "upsert" | "getDrizzle">;
79
+ type TransactionCrudForwarders = Pick<TransactionContext, "select" | "selectOne" | "updateCount" | "delete" | "upsert" | "getDrizzle">;
33
80
 
34
81
  /**
35
82
  * Base database adapter abstract class.
@@ -112,6 +159,122 @@ declare abstract class DrizzleAdapter {
112
159
  * @throws The callback's own error, unchanged, when it carries that brand
113
160
  */
114
161
  abstract transaction<T>(callback: (ctx: TransactionContext) => Promise<T>, options?: TransactionOptions): Promise<T>;
162
+ /**
163
+ * Whether a `transaction()` call made from the current async context would
164
+ * join a transaction already open on this adapter, as a savepoint, rather
165
+ * than open one of its own.
166
+ *
167
+ * A caller about to do something no rollback can undo — removing a stored
168
+ * file, say — asks this first: work that joins an enclosing transaction is
169
+ * undone with it, while the effect it performs after its own savepoint
170
+ * releases is not.
171
+ *
172
+ * False here. Concrete rather than abstract so existing adapters keep
173
+ * working unchanged, and false is right for a pooled adapter: a call made
174
+ * inside another transaction's work opens its own transaction on its own
175
+ * connection, which commits independently.
176
+ *
177
+ * @returns True when the call would nest in an open transaction
178
+ */
179
+ inTransaction(): boolean;
180
+ /**
181
+ * The transaction each async flow is inside, kept per flow rather than per
182
+ * connection: on SQLite every request shares the one connection, and
183
+ * another request's open transaction says nothing about this one.
184
+ */
185
+ private readonly flowTransactions;
186
+ /**
187
+ * Whether the calling async flow is inside a transaction on this adapter
188
+ * that has not finished: its own, or one it was started from inside.
189
+ *
190
+ * A write that must outlive any rollback — a count of a failed attempt, the
191
+ * spend of a single-use secret — asks this before running in a transaction
192
+ * of its own. Made inside an open transaction on SQLite, it joins that
193
+ * transaction as a savepoint and is undone with it. On PostgreSQL and MySQL
194
+ * it would commit on a connection of its own, so refusing it there too
195
+ * keeps code that passes on one dialect from failing on another. Unlike
196
+ * {@link inTransaction}, which asks whether a call would nest and is always
197
+ * false on a pooled adapter, this answers alike on every dialect, and
198
+ * another flow's open transaction never answers true.
199
+ *
200
+ * Covers transactions opened through {@link transaction} and through the
201
+ * Drizzle handle's own `transaction` on the dialects whose handle takes
202
+ * async work. A dialect that keeps scopes of its own judges from those
203
+ * instead; an adapter that does neither answers false.
204
+ *
205
+ * @experimental
206
+ * @returns True while a transaction the calling flow is inside is open
207
+ */
208
+ transactionOpenInFlow(): boolean;
209
+ /**
210
+ * Run a whole transaction, from its BEGIN until its COMMIT or ROLLBACK has
211
+ * run, as the calling flow's open transaction, for
212
+ * {@link transactionOpenInFlow}. A dialect's `transaction` runs through
213
+ * this unless it judges the flow from scopes of its own.
214
+ *
215
+ * The transaction counts as open for its work and for anything the work
216
+ * starts, awaited or not, until it has finished. Something the work starts
217
+ * that outlives it then sees it closed, or the one enclosing it still open.
218
+ *
219
+ * @param run - The transaction, BEGIN to COMMIT or ROLLBACK
220
+ * @returns What `run` resolves to
221
+ */
222
+ protected runInFlowTransaction<T>(run: () => Promise<T>): Promise<T>;
223
+ /**
224
+ * Run each of a pool-bound Drizzle handle's transactions on a connection
225
+ * `checkout` hands it, and return that connection as the adapter's own
226
+ * `transaction()` does: closed rather than pooled when no ROLLBACK can be
227
+ * confirmed on it, and never leaked by a failed BEGIN (`pinTransactions`).
228
+ *
229
+ * For PostgreSQL's and MySQL's handles. Apply it before
230
+ * {@link trackFlowTransactions}, which wraps whatever `transaction` the
231
+ * handle has at that point.
232
+ *
233
+ * @param db - A Drizzle handle on this adapter's pool
234
+ * @param checkout - Checks out a connection for one transaction
235
+ * @returns The same handle, its `transaction` replaced
236
+ */
237
+ protected pinDrizzleTransactions<D extends DrizzleTransactor>(db: D, checkout: () => Promise<PinnedConnection>): D;
238
+ /**
239
+ * Make a Drizzle handle's own `transaction` count for
240
+ * {@link transactionOpenInFlow}, as the adapter's does.
241
+ *
242
+ * Core's services run their transactions through the handle on PostgreSQL
243
+ * and MySQL; without this, a call made inside one would be refused on
244
+ * SQLite, where they go through the adapter, and let through on the
245
+ * others. Not for SQLite's handle: its `transaction` takes only
246
+ * synchronous work, which no async flow can be inside.
247
+ *
248
+ * @param db - A Drizzle handle this adapter created
249
+ * @returns The same handle, its `transaction` tracked
250
+ */
251
+ protected trackFlowTransactions<D extends DrizzleTransactor>(db: D): D;
252
+ /**
253
+ * Run `effect` once the write made from the current async context has
254
+ * committed: an event, a hook, a cache flush, anything outside the database
255
+ * that must not happen for a change that is rolled back.
256
+ *
257
+ * A caller invokes this after its own transaction has resolved. Where that
258
+ * transaction was nested in an enclosing one, as a savepoint, the change is
259
+ * not durable yet, and an adapter that nests (see {@link inTransaction})
260
+ * holds `effect` until the outermost transaction commits, and drops it when
261
+ * that transaction, or the savepoint it was registered in, rolls back. A
262
+ * held effect runs after the commit, before the outermost `transaction()`
263
+ * call resolves, in registration order; one that then throws or rejects is
264
+ * handed to `onDeferredFailure` rather than failing a transaction that has
265
+ * committed.
266
+ *
267
+ * Here `effect` runs now and the returned promise settles with it, its
268
+ * failure included. Concrete rather than abstract, as `inTransaction` is,
269
+ * and right for a pooled adapter: each transaction has its own connection
270
+ * and has committed by the time its caller continues.
271
+ *
272
+ * @experimental
273
+ * @param effect - What to run once the change is durable
274
+ * @param onDeferredFailure - Receives the error of a held effect that fails
275
+ * @returns Settles once `effect` has run, or once it has been held
276
+ */
277
+ afterCommit(effect: () => unknown, _onDeferredFailure?: (error: unknown) => void): Promise<void>;
115
278
  /**
116
279
  * Get database capabilities.
117
280
  *
@@ -122,6 +285,23 @@ declare abstract class DrizzleAdapter {
122
285
  * @returns Database capability flags
123
286
  */
124
287
  abstract getCapabilities(): DatabaseCapabilities;
288
+ /**
289
+ * The schema this adapter's connections resolve unqualified names in.
290
+ *
291
+ * @remarks
292
+ * Read-only, and optional because only PostgreSQL has a schema namespace:
293
+ * MySQL's "schema" is its database and SQLite has one file. An adapter that
294
+ * sets no `search_path` of its own answers `undefined`, meaning the server's
295
+ * default applies.
296
+ *
297
+ * Exposed so the caller that built its own adapter can be held to the same
298
+ * schema the rest of the application assumes. The value lives in the
299
+ * adapter's config, and a mismatch is not an error anywhere below: every
300
+ * query succeeds, in a namespace nothing else is looking at.
301
+ *
302
+ * @returns The configured schema name, or `undefined` when none is set
303
+ */
304
+ getConfiguredSchema?(): string | undefined;
125
305
  /**
126
306
  * Get the raw Drizzle ORM instance for direct queries.
127
307
  *
@@ -633,7 +813,8 @@ declare abstract class DrizzleAdapter {
633
813
  * @remarks
634
814
  * Default implementation uses dialect-specific ON CONFLICT syntax.
635
815
  * PostgreSQL/SQLite: ON CONFLICT ... DO UPDATE
636
- * MySQL: ON DUPLICATE KEY UPDATE
816
+ * MySQL: the MySQL adapter overrides this, resolving the conflict by the
817
+ * conflict columns (see its `upsert`)
637
818
  *
638
819
  * @param table - Table name
639
820
  * @param data - Record data
@@ -806,6 +987,128 @@ declare abstract class DrizzleAdapter {
806
987
  * @protected
807
988
  */
808
989
  protected createTransactionForwarders(txDb: () => unknown): TransactionCrudForwarders;
990
+ /**
991
+ * The Drizzle handles one transaction hands out; see
992
+ * `transactionDrizzleHandles`. `build` makes an instance on the
993
+ * transaction's own connection, with the relations config when given one.
994
+ *
995
+ * @protected
996
+ */
997
+ protected transactionDrizzleHandles<TBare>(build: (relations?: AnyRelations) => TBare): {
998
+ bare: () => TBare;
999
+ withRelations: <T = unknown>(relations: AnyRelations) => T;
1000
+ };
1001
+ /**
1002
+ * A transaction context's `update`, for each adapter to bind.
1003
+ *
1004
+ * Not forwarded to the pooled `update` the way `select` and `delete` are:
1005
+ * that one goes through the Drizzle query builder, which writes the columns
1006
+ * the runtime MODEL declares, and a transaction's update must reach the
1007
+ * columns the physical TABLE has — the localization transition window
1008
+ * writes a column the model has already moved to a companion table that
1009
+ * does not exist yet. The INSERT half of every transaction context already
1010
+ * builds its own statement for that reason; `update-statement.ts` is the
1011
+ * UPDATE half, spelled once for the three adapters, and this runs it: on
1012
+ * the transaction executor, classified with the operation and table named
1013
+ * as the pooled `update` classifies its failures, and read back through
1014
+ * `select` on the same executor when the caller asked for rows.
1015
+ *
1016
+ * That read is by the rows' IDENTITY where the dialect can report it: on
1017
+ * PostgreSQL and SQLite the statement carries `RETURNING <primary key>`, and
1018
+ * the read-back asks for exactly those rows — so a row another transaction
1019
+ * adds under the same predicate meanwhile is not among them, and an update
1020
+ * whose own write falsifies its predicate still reads its rows back. MySQL
1021
+ * has no RETURNING, so there the read re-runs the predicate, as the pooled
1022
+ * `update` always has on that dialect; a table with no primary key in its
1023
+ * model reads back the same way.
1024
+ *
1025
+ * @param txDb - thunk returning the transaction-bound Drizzle instance
1026
+ * @param run - how this dialect runs a statement on that instance, and the
1027
+ * rows it returns when the statement carries RETURNING: better-sqlite3
1028
+ * answers synchronously, the pooled drivers do not
1029
+ * @param bindUnmodeled - how a value binds when the model declares no
1030
+ * column for it; a declared column binds through its own encoder
1031
+ * @returns the context's `update` method
1032
+ */
1033
+ protected transactionUpdate(txDb: () => unknown, run: (statement: SQL, returnsRows: boolean) => Promise<Record<string, unknown>[] | undefined> | Record<string, unknown>[] | undefined, bindUnmodeled: (value: unknown) => unknown): TransactionContext["update"];
1034
+ /**
1035
+ * The columns that identify a row of this table, under both spellings: the
1036
+ * SQL name RETURNING reports and the Drizzle property name the query
1037
+ * builder's WHERE is addressed by. Columns flagged primary first; failing
1038
+ * that, the table-level primary key the dialect's table config carries
1039
+ * (`primaryKey({ columns })` leaves each column's flag false), which each
1040
+ * adapter reads through its own dialect. Empty when the model declares
1041
+ * neither, and the read-back falls back to the caller's predicate.
1042
+ */
1043
+ protected identityColumns(tableObj: Record<string, unknown>): Array<{
1044
+ jsName: string;
1045
+ sqlName: string;
1046
+ }>;
1047
+ /**
1048
+ * How a value binds to a column the model does not declare, on a driver
1049
+ * that binds scalars, dates and binary natively: a structured value goes
1050
+ * as JSON text, since what node-postgres and mysql2 make of a bare object
1051
+ * or array is not JSON. For the adapters to hand `transactionUpdate`.
1052
+ */
1053
+ protected bindUnmodeledStructuredAsJson(value: unknown): unknown;
1054
+ /**
1055
+ * Refuse an upsert target every dialect would not answer alike: a conflict
1056
+ * column named twice, which SQLite rejects as no constraint's target and
1057
+ * MySQL would accept; and, when nothing is to be updated, a conflict column
1058
+ * left for the database to fill, since the row that stands is then read
1059
+ * back by a value the caller never gave. Shared with the dialects that
1060
+ * override `upsert`, so the refusals are one rule.
1061
+ */
1062
+ protected assertUpsertTarget(table: string, data: Record<string, unknown>, options: UpsertOptions, keepExisting: boolean): void;
1063
+ /**
1064
+ * The columns of a table-level `primaryKey({ columns })`, as the dialect's
1065
+ * table config reports them. The base class cannot read that config without
1066
+ * naming a dialect, so each adapter answers for its own; a dialect that does
1067
+ * not answer reports none.
1068
+ */
1069
+ protected compositePrimaryKey(_tableObj: Record<string, unknown>): object[];
1070
+ /** The registered table object, or the error every CRUD method throws without one. */
1071
+ private resolvedTableObject;
1072
+ /**
1073
+ * The statement `transactionUpdate` runs.
1074
+ *
1075
+ * @throws when nothing would be written — every key `undefined`, or none at
1076
+ * all. The query builder refused that too ("No values to set"), and a
1077
+ * patch that names nothing is a caller's mistake rather than a write of
1078
+ * nothing.
1079
+ */
1080
+ private buildTransactionUpdate;
1081
+ /**
1082
+ * Whether a transaction's `update` reads the rows it changed back: the
1083
+ * caller named columns, or `*`. An empty list, like no option at all, asks
1084
+ * for nothing and `update` answers `[]`, as it always has. The rows come
1085
+ * from a read of the update's own WHERE on its own transaction, so they are
1086
+ * the model's view of the row, decoded as every read is decoded — which is
1087
+ * what the query-builder update returned for them, and why the named list
1088
+ * selects nothing narrower.
1089
+ */
1090
+ private updateReturnsRows;
1091
+ /**
1092
+ * The driver's own error inside `error`: the first in its `cause` chain that
1093
+ * `isDriverError` recognises, or `error` itself when none does.
1094
+ *
1095
+ * A query that runs through Drizzle fails with Drizzle's `DrizzleQueryError`,
1096
+ * whose message is the SQL statement and which carries no driver code; the
1097
+ * driver's error, the only object that knows what actually went wrong, is
1098
+ * its `cause`. A dialect's {@link classifyError} classifies from what this
1099
+ * returns, so a failure reads the same whether or not Drizzle wrapped it.
1100
+ *
1101
+ * The walk is bounded, because an error chain can be made cyclic and a
1102
+ * classifier that can hang is worse than one that gives up. Falling back to
1103
+ * `error` keeps an error that carries no code anywhere classified as before.
1104
+ *
1105
+ * @param error - The error as it was caught
1106
+ * @param isDriverError - Whether a link in the chain is the driver's error
1107
+ * @returns The driver's error, or `error` when no link is
1108
+ */
1109
+ protected driverErrorIn<T extends {
1110
+ cause?: unknown;
1111
+ }>(error: unknown, isDriverError: (candidate: T) => boolean): T;
809
1112
  /**
810
1113
  * Classify an error into a DatabaseError.
811
1114
  *