@nextlyhq/adapter-drizzle 0.0.2-alpha.60 → 0.0.2-alpha.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,31 @@
2
2
 
3
3
  Internal Drizzle ORM utilities for Nextly's database adapters.
4
4
 
5
- > This package is part of Nextly's internals. It is installed automatically as a dependency of [`nextly`](../nextly). Choose [`@nextlyhq/adapter-postgres`](../adapter-postgres), [`@nextlyhq/adapter-mysql`](../adapter-mysql), or [`@nextlyhq/adapter-sqlite`](../adapter-sqlite) for your project.
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/@nextlyhq/adapter-drizzle"><img alt="npm" src="https://img.shields.io/npm/v/@nextlyhq%2Fadapter-drizzle?style=flat-square&label=npm&color=cb3837" /></a>
7
+ <a href="https://github.com/nextlyhq/nextly/blob/main/LICENSE.md"><img alt="License" src="https://img.shields.io/github/license/nextlyhq/nextly?style=flat-square&color=blue" /></a>
8
+ <a href="https://nextlyhq.com/docs"><img alt="Status" src="https://img.shields.io/badge/status-alpha-orange?style=flat-square" /></a>
9
+ </p>
10
+
11
+ > [!IMPORTANT]
12
+ > Nextly is in alpha. APIs may change before 1.0. Pin exact versions in production.
13
+
14
+ This package is part of Nextly's internals. It is installed automatically as a dependency of [`nextly`](../nextly). Choose [`@nextlyhq/adapter-postgres`](../adapter-postgres), [`@nextlyhq/adapter-mysql`](../adapter-mysql), or [`@nextlyhq/adapter-sqlite`](../adapter-sqlite) for your project.
15
+
16
+ ## Install
17
+
18
+ You do not install this directly. It arrives as a dependency of [`nextly`](../nextly)
19
+ and of each database adapter. Install the adapter for your database instead:
20
+
21
+ ```bash
22
+ pnpm add @nextlyhq/adapter-postgres pg
23
+ ```
24
+
25
+ ## Related packages
26
+
27
+ - [`@nextlyhq/adapter-postgres`](../adapter-postgres) — recommended for production
28
+ - [`@nextlyhq/adapter-mysql`](../adapter-mysql)
29
+ - [`@nextlyhq/adapter-sqlite`](../adapter-sqlite) — local demos
6
30
 
7
31
  ## License
8
32
 
@@ -1,9 +1,36 @@
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
3
  import { S as SupportedDialect, a as SqlParam, T as TableResolver } from './core-CVO7WYDj.cjs';
3
- import { T as TransactionContext, e as TransactionOptions, D as DatabaseCapabilities, P as PoolStats, S as SelectOptions, I as InsertOptions, W as WhereClause, U as UpdateOptions, f as DeleteOptions, g as UpsertOptions, a as Migration, d as MigrationResult } from './migration-BUc56kip.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
+ * Transaction CRUD forwarder helper for database adapters.
9
+ *
10
+ * @remarks
11
+ * Encapsulates the delegation pattern where a transaction context forwards its
12
+ * CRUD methods to the adapter's implementation while passing the transaction-bound
13
+ * Drizzle executor.
14
+ *
15
+ * @packageDocumentation
16
+ */
17
+
18
+ /**
19
+ * Interface representing an adapter that can execute CRUD operations with an optional executor.
20
+ */
21
+ interface TransactionCrudDelegator {
22
+ select<T = unknown>(table: string, options?: SelectOptions, executor?: unknown): Promise<T[]>;
23
+ 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
+ updateCount(table: string, data: Record<string, unknown>, where: WhereClause, executor?: unknown): Promise<number>;
26
+ delete(table: string, where: WhereClause, options?: DeleteOptions, executor?: unknown): Promise<number>;
27
+ upsert<T = unknown>(table: string, data: Record<string, unknown>, options: UpsertOptions, executor?: unknown): Promise<T>;
28
+ }
29
+ /**
30
+ * Transaction context CRUD methods provided by the forwarder.
31
+ */
32
+ type TransactionCrudForwarders = Pick<TransactionContext, "select" | "selectOne" | "update" | "updateCount" | "delete" | "upsert" | "getDrizzle">;
33
+
7
34
  /**
8
35
  * Base database adapter abstract class.
9
36
  *
@@ -293,6 +320,23 @@ declare abstract class DrizzleAdapter {
293
320
  * for `"*"` or when nothing resolves, so callers fall back to all columns.
294
321
  */
295
322
  protected buildColumnProjection(tableObj: unknown, names: string[] | "*" | undefined): Record<string, unknown> | undefined;
323
+ /**
324
+ * The requested column names split into what this table has and what it does not.
325
+ *
326
+ * One resolution, reported both ways, because two callers need different halves
327
+ * of the same answer: a projection drops what it cannot find, while a distinct
328
+ * count has to REFUSE it. Resolving twice would let the two disagree about what
329
+ * "found" means — the SQL-name alias below is exactly the kind of detail a
330
+ * second implementation gets wrong — and the count would then reject a column
331
+ * the projection happily uses.
332
+ *
333
+ * Both spellings resolve: a caller may name the Drizzle property or the SQL
334
+ * column, and either maps to the same projection key.
335
+ */
336
+ protected resolveColumns(tableObj: unknown, names: readonly string[]): {
337
+ projection: Record<string, unknown>;
338
+ unresolved: string[];
339
+ };
296
340
  /**
297
341
  * Check if the adapter is currently connected.
298
342
  *
@@ -426,6 +470,51 @@ declare abstract class DrizzleAdapter {
426
470
  * });
427
471
  * ```
428
472
  */
473
+ /** The registered table object, or a refusal naming what is missing. */
474
+ private requireTableObject;
475
+ /**
476
+ * The columns a distinct count groups by, or `undefined` for a row count.
477
+ *
478
+ * 🔴 EVERY named column must resolve, not merely one of them. A `distinctOn`
479
+ * naming no column this table has would fall through to a row count, and one
480
+ * naming a valid column beside a misspelled or since-removed column would
481
+ * count distinct over a NARROWER key than the caller asked for. Both answer a
482
+ * different question than the one asked, silently; the second is the worse of
483
+ * the two, because a subset key groups more rows together and so UNDERCOUNTS,
484
+ * which reads as a plausible number rather than as a fault. Refused here,
485
+ * where the mistake was made, rather than surfacing as a wrong figure.
486
+ */
487
+ private countProjection;
488
+ /**
489
+ * `COUNT(*)` over a `SELECT DISTINCT` subquery.
490
+ *
491
+ * Its own function because it is a genuinely different query from the plain
492
+ * count rather than a variation on one, and because building both inline made
493
+ * the public method a chain of decisions the complexity gate objected to
494
+ * before a reader would have.
495
+ */
496
+ private countDistinctRows;
497
+ /** `COUNT(*)` over the table itself. */
498
+ private countAllRows;
499
+ /**
500
+ * How many rows match, or how many DISTINCT combinations of some columns do.
501
+ *
502
+ * The data layer had no count at all: collection totals go through
503
+ * `countEntries`, an access-controlled path built for collection tables, and
504
+ * nothing could count a system table. A caller wanting one selected the rows
505
+ * and measured the array, which transfers every row to learn a number and
506
+ * cannot be bounded without making the number wrong.
507
+ *
508
+ * 🔴 `distinctOn` compiles to `COUNT(*)` over a `SELECT DISTINCT` SUBQUERY,
509
+ * never to `COUNT(DISTINCT a, b)`. The inline form is not portable and fails
510
+ * in the direction that is hardest to notice -- MySQL accepts it, PostgreSQL
511
+ * needs a row constructor, and SQLite rejects it outright with "wrong number
512
+ * of arguments to function count()" -- so a query written against one engine
513
+ * is a syntax error on another. The subquery is the single form all three
514
+ * accept, and building it here rather than at each call site is what keeps
515
+ * the answer identical per dialect.
516
+ */
517
+ count(table: string, options?: CountOptions, executor?: unknown): Promise<number>;
429
518
  selectOne<T = unknown>(table: string, options?: SelectOptions, executor?: unknown): Promise<T | null>;
430
519
  /**
431
520
  * Insert a single record into a table.
@@ -708,12 +797,35 @@ declare abstract class DrizzleAdapter {
708
797
  * @protected
709
798
  */
710
799
  protected createDatabaseError(kind: DatabaseErrorKind, message: string, cause?: Error): DatabaseError;
800
+ /**
801
+ * Helper to create transaction context CRUD forwarding methods.
802
+ *
803
+ * @param txDb - Thunk returning the transaction-bound Drizzle executor
804
+ * @returns Object providing forwarded CRUD and getDrizzle methods
805
+ *
806
+ * @protected
807
+ */
808
+ protected createTransactionForwarders(txDb: () => unknown): TransactionCrudForwarders;
809
+ /**
810
+ * Classify an error into a DatabaseError.
811
+ *
812
+ * @remarks
813
+ * Subclasses can override this method to add dialect-specific error code classification.
814
+ *
815
+ * @param error - Original error
816
+ * @param sql - SQL statement that caused the error (optional)
817
+ * @returns DatabaseError instance
818
+ *
819
+ * @protected
820
+ */
821
+ protected classifyError(error: unknown, sql?: string): DatabaseError;
711
822
  /**
712
823
  * Handle query errors and convert to DatabaseError.
713
824
  *
714
825
  * @remarks
715
826
  * Protected helper for consistent error handling across CRUD operations.
716
- * Subclasses can override to add dialect-specific error classification.
827
+ * Delegates to `classifyError` and attaches operation and table context if not present.
828
+ * Subclasses override `classifyError` to provide dialect-specific error code classification.
717
829
  *
718
830
  * @param error - Original error
719
831
  * @param operation - Operation that failed
@@ -725,4 +837,4 @@ declare abstract class DrizzleAdapter {
725
837
  protected handleQueryError(error: unknown, operation: string, table: string): DatabaseError;
726
838
  }
727
839
 
728
- export { DrizzleAdapter as D };
840
+ export { DrizzleAdapter as D, type TransactionCrudDelegator as T, type TransactionCrudForwarders as a };
@@ -1,9 +1,36 @@
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-R06fsTrz.js';
2
3
  import { S as SupportedDialect, a as SqlParam, T as TableResolver } from './core-CVO7WYDj.js';
3
- import { T as TransactionContext, e as TransactionOptions, D as DatabaseCapabilities, P as PoolStats, S as SelectOptions, I as InsertOptions, W as WhereClause, U as UpdateOptions, f as DeleteOptions, g as UpsertOptions, a as Migration, d as MigrationResult } from './migration-Bj84e15B.js';
4
4
  import { T as TableDefinition, C as CreateTableOptions, D as DropTableOptions, A as AlterTableOperation, a as AlterTableOptions } from './schema-BIQ0YQZ_.js';
5
5
  import { D as DatabaseErrorKind, a as DatabaseError } from './error-BrdknH2s.js';
6
6
 
7
+ /**
8
+ * Transaction CRUD forwarder helper for database adapters.
9
+ *
10
+ * @remarks
11
+ * Encapsulates the delegation pattern where a transaction context forwards its
12
+ * CRUD methods to the adapter's implementation while passing the transaction-bound
13
+ * Drizzle executor.
14
+ *
15
+ * @packageDocumentation
16
+ */
17
+
18
+ /**
19
+ * Interface representing an adapter that can execute CRUD operations with an optional executor.
20
+ */
21
+ interface TransactionCrudDelegator {
22
+ select<T = unknown>(table: string, options?: SelectOptions, executor?: unknown): Promise<T[]>;
23
+ 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
+ updateCount(table: string, data: Record<string, unknown>, where: WhereClause, executor?: unknown): Promise<number>;
26
+ delete(table: string, where: WhereClause, options?: DeleteOptions, executor?: unknown): Promise<number>;
27
+ upsert<T = unknown>(table: string, data: Record<string, unknown>, options: UpsertOptions, executor?: unknown): Promise<T>;
28
+ }
29
+ /**
30
+ * Transaction context CRUD methods provided by the forwarder.
31
+ */
32
+ type TransactionCrudForwarders = Pick<TransactionContext, "select" | "selectOne" | "update" | "updateCount" | "delete" | "upsert" | "getDrizzle">;
33
+
7
34
  /**
8
35
  * Base database adapter abstract class.
9
36
  *
@@ -293,6 +320,23 @@ declare abstract class DrizzleAdapter {
293
320
  * for `"*"` or when nothing resolves, so callers fall back to all columns.
294
321
  */
295
322
  protected buildColumnProjection(tableObj: unknown, names: string[] | "*" | undefined): Record<string, unknown> | undefined;
323
+ /**
324
+ * The requested column names split into what this table has and what it does not.
325
+ *
326
+ * One resolution, reported both ways, because two callers need different halves
327
+ * of the same answer: a projection drops what it cannot find, while a distinct
328
+ * count has to REFUSE it. Resolving twice would let the two disagree about what
329
+ * "found" means — the SQL-name alias below is exactly the kind of detail a
330
+ * second implementation gets wrong — and the count would then reject a column
331
+ * the projection happily uses.
332
+ *
333
+ * Both spellings resolve: a caller may name the Drizzle property or the SQL
334
+ * column, and either maps to the same projection key.
335
+ */
336
+ protected resolveColumns(tableObj: unknown, names: readonly string[]): {
337
+ projection: Record<string, unknown>;
338
+ unresolved: string[];
339
+ };
296
340
  /**
297
341
  * Check if the adapter is currently connected.
298
342
  *
@@ -426,6 +470,51 @@ declare abstract class DrizzleAdapter {
426
470
  * });
427
471
  * ```
428
472
  */
473
+ /** The registered table object, or a refusal naming what is missing. */
474
+ private requireTableObject;
475
+ /**
476
+ * The columns a distinct count groups by, or `undefined` for a row count.
477
+ *
478
+ * 🔴 EVERY named column must resolve, not merely one of them. A `distinctOn`
479
+ * naming no column this table has would fall through to a row count, and one
480
+ * naming a valid column beside a misspelled or since-removed column would
481
+ * count distinct over a NARROWER key than the caller asked for. Both answer a
482
+ * different question than the one asked, silently; the second is the worse of
483
+ * the two, because a subset key groups more rows together and so UNDERCOUNTS,
484
+ * which reads as a plausible number rather than as a fault. Refused here,
485
+ * where the mistake was made, rather than surfacing as a wrong figure.
486
+ */
487
+ private countProjection;
488
+ /**
489
+ * `COUNT(*)` over a `SELECT DISTINCT` subquery.
490
+ *
491
+ * Its own function because it is a genuinely different query from the plain
492
+ * count rather than a variation on one, and because building both inline made
493
+ * the public method a chain of decisions the complexity gate objected to
494
+ * before a reader would have.
495
+ */
496
+ private countDistinctRows;
497
+ /** `COUNT(*)` over the table itself. */
498
+ private countAllRows;
499
+ /**
500
+ * How many rows match, or how many DISTINCT combinations of some columns do.
501
+ *
502
+ * The data layer had no count at all: collection totals go through
503
+ * `countEntries`, an access-controlled path built for collection tables, and
504
+ * nothing could count a system table. A caller wanting one selected the rows
505
+ * and measured the array, which transfers every row to learn a number and
506
+ * cannot be bounded without making the number wrong.
507
+ *
508
+ * 🔴 `distinctOn` compiles to `COUNT(*)` over a `SELECT DISTINCT` SUBQUERY,
509
+ * never to `COUNT(DISTINCT a, b)`. The inline form is not portable and fails
510
+ * in the direction that is hardest to notice -- MySQL accepts it, PostgreSQL
511
+ * needs a row constructor, and SQLite rejects it outright with "wrong number
512
+ * of arguments to function count()" -- so a query written against one engine
513
+ * is a syntax error on another. The subquery is the single form all three
514
+ * accept, and building it here rather than at each call site is what keeps
515
+ * the answer identical per dialect.
516
+ */
517
+ count(table: string, options?: CountOptions, executor?: unknown): Promise<number>;
429
518
  selectOne<T = unknown>(table: string, options?: SelectOptions, executor?: unknown): Promise<T | null>;
430
519
  /**
431
520
  * Insert a single record into a table.
@@ -708,12 +797,35 @@ declare abstract class DrizzleAdapter {
708
797
  * @protected
709
798
  */
710
799
  protected createDatabaseError(kind: DatabaseErrorKind, message: string, cause?: Error): DatabaseError;
800
+ /**
801
+ * Helper to create transaction context CRUD forwarding methods.
802
+ *
803
+ * @param txDb - Thunk returning the transaction-bound Drizzle executor
804
+ * @returns Object providing forwarded CRUD and getDrizzle methods
805
+ *
806
+ * @protected
807
+ */
808
+ protected createTransactionForwarders(txDb: () => unknown): TransactionCrudForwarders;
809
+ /**
810
+ * Classify an error into a DatabaseError.
811
+ *
812
+ * @remarks
813
+ * Subclasses can override this method to add dialect-specific error code classification.
814
+ *
815
+ * @param error - Original error
816
+ * @param sql - SQL statement that caused the error (optional)
817
+ * @returns DatabaseError instance
818
+ *
819
+ * @protected
820
+ */
821
+ protected classifyError(error: unknown, sql?: string): DatabaseError;
711
822
  /**
712
823
  * Handle query errors and convert to DatabaseError.
713
824
  *
714
825
  * @remarks
715
826
  * Protected helper for consistent error handling across CRUD operations.
716
- * Subclasses can override to add dialect-specific error classification.
827
+ * Delegates to `classifyError` and attaches operation and table context if not present.
828
+ * Subclasses override `classifyError` to provide dialect-specific error code classification.
717
829
  *
718
830
  * @param error - Original error
719
831
  * @param operation - Operation that failed
@@ -725,4 +837,4 @@ declare abstract class DrizzleAdapter {
725
837
  protected handleQueryError(error: unknown, operation: string, table: string): DatabaseError;
726
838
  }
727
839
 
728
- export { DrizzleAdapter as D };
840
+ export { DrizzleAdapter as D, type TransactionCrudDelegator as T, type TransactionCrudForwarders as a };