@nextlyhq/adapter-drizzle 0.0.2-alpha.66 → 0.0.2-alpha.68

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-Cs3Jl9Fb.d.cts → adapter-bUAaPzjV.d.cts} +219 -2
  2. package/dist/{adapter-CHlx_Taa.d.ts → adapter-iJ5hbUvL.d.ts} +219 -2
  3. package/dist/index.cjs +299 -28
  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 +300 -29
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/{migration-CgoxgWOL.d.ts → migration-BqHebSwM.d.ts} +40 -3
  10. package/dist/{migration-Ce0hkgr_.d.cts → migration-Bu0WLdX4.d.cts} +40 -3
  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,5 +1,5 @@
1
1
  import { a as SqlParam, S as SupportedDialect } from './core-CVO7WYDj.js';
2
- import { SQL } from 'drizzle-orm';
2
+ import { AnyRelations, SQL } from 'drizzle-orm';
3
3
 
4
4
  /**
5
5
  * Query building type definitions for database-agnostic queries.
@@ -35,7 +35,7 @@ import { SQL } from 'drizzle-orm';
35
35
  *
36
36
  * @public
37
37
  */
38
- declare const WHERE_OPERATORS: readonly ["=", "!=", "<", ">", "<=", ">=", "IN", "NOT IN", "LIKE", "ILIKE", "IS NULL", "IS NOT NULL", "BETWEEN", "NOT BETWEEN", "CONTAINS", "OVERLAPS"];
38
+ declare const WHERE_OPERATORS: readonly ["=", "!=", "<", ">", "<=", ">=", "IN", "NOT IN", "LIKE", "ILIKE", "IS NULL", "IS NOT NULL", "BETWEEN", "NOT BETWEEN", "CONTAINS", "ICONTAINS", "OVERLAPS"];
39
39
  /**
40
40
  * Every WHERE clause operator this package declares. Derived from
41
41
  * {@link WHERE_OPERATORS}, and carrying the same caveat: a value of this type
@@ -266,7 +266,16 @@ interface DeleteOptions {
266
266
  interface UpsertOptions {
267
267
  /** Columns that define uniqueness for conflict detection */
268
268
  conflictColumns: string[];
269
- /** Columns to update if conflict occurs (default: all provided columns) */
269
+ /**
270
+ * Columns to update if conflict occurs (default: all provided columns).
271
+ *
272
+ * Empty means "insert, or keep the row that stands". The kept row is read
273
+ * back after the statement, so on PostgreSQL and SQLite a row another
274
+ * writer deletes between the two cannot be returned, and the call resolves
275
+ * to `null`. Whether THIS call created the row is told by the id it
276
+ * returns: send a fresh id, and only a call whose own insert ran gets it
277
+ * back — a read-back can only return another writer's row.
278
+ */
270
279
  updateColumns?: string[];
271
280
  /** Columns to return after upsert (use "*" for all columns) */
272
281
  returning?: string[] | "*";
@@ -334,6 +343,21 @@ interface TransactionContext {
334
343
  * @returns Array of result rows
335
344
  */
336
345
  execute<T = unknown>(sql: string, params?: SqlParam[]): Promise<T[]>;
346
+ /**
347
+ * An instance bound to the SAME transaction client with the relational
348
+ * query API (`db.query.*`) enabled — the transaction's counterpart of
349
+ * `getDrizzle(relations)`.
350
+ *
351
+ * The `getDrizzle()` instance has an empty `query` namespace, so a
352
+ * relational read inside the transaction needs this one; the pooled
353
+ * `getDrizzle(relations)` would read on a different connection and miss the
354
+ * transaction's uncommitted writes. Memoized per relations object, as
355
+ * `getDrizzle` is, so repeated calls with an unchanged config share one
356
+ * instance.
357
+ *
358
+ * @param relations - drizzle v1 relations config (defineRelations output)
359
+ */
360
+ drizzleWithRelations<T = unknown>(relations: AnyRelations): T;
337
361
  /**
338
362
  * Run a Drizzle-built statement within the transaction, for its effect.
339
363
  *
@@ -669,6 +693,19 @@ interface DatabaseCapabilities {
669
693
  * - SQLite: No limit (practically unlimited)
670
694
  */
671
695
  maxIdentifierLength: number;
696
+ /**
697
+ * Whether the server accepts `SELECT ... FOR SHARE`.
698
+ *
699
+ * @remarks
700
+ * Reported by the MySQL adapter once it has connected and read the server's
701
+ * version: MySQL 8, Aurora MySQL and Vitess/PlanetScale accept it, MariaDB
702
+ * and TiDB reject it as a syntax error. PostgreSQL always accepts it and
703
+ * SQLite has no row locks, so their adapters leave it unset. Unset means
704
+ * not known; a caller then takes a lock every server accepts.
705
+ *
706
+ * @experimental
707
+ */
708
+ sharedRowLock?: boolean;
672
709
  }
673
710
  /**
674
711
  * Connection pool statistics.
@@ -1,5 +1,5 @@
1
1
  import { a as SqlParam, S as SupportedDialect } from './core-CVO7WYDj.cjs';
2
- import { SQL } from 'drizzle-orm';
2
+ import { AnyRelations, SQL } from 'drizzle-orm';
3
3
 
4
4
  /**
5
5
  * Query building type definitions for database-agnostic queries.
@@ -35,7 +35,7 @@ import { SQL } from 'drizzle-orm';
35
35
  *
36
36
  * @public
37
37
  */
38
- declare const WHERE_OPERATORS: readonly ["=", "!=", "<", ">", "<=", ">=", "IN", "NOT IN", "LIKE", "ILIKE", "IS NULL", "IS NOT NULL", "BETWEEN", "NOT BETWEEN", "CONTAINS", "OVERLAPS"];
38
+ declare const WHERE_OPERATORS: readonly ["=", "!=", "<", ">", "<=", ">=", "IN", "NOT IN", "LIKE", "ILIKE", "IS NULL", "IS NOT NULL", "BETWEEN", "NOT BETWEEN", "CONTAINS", "ICONTAINS", "OVERLAPS"];
39
39
  /**
40
40
  * Every WHERE clause operator this package declares. Derived from
41
41
  * {@link WHERE_OPERATORS}, and carrying the same caveat: a value of this type
@@ -266,7 +266,16 @@ interface DeleteOptions {
266
266
  interface UpsertOptions {
267
267
  /** Columns that define uniqueness for conflict detection */
268
268
  conflictColumns: string[];
269
- /** Columns to update if conflict occurs (default: all provided columns) */
269
+ /**
270
+ * Columns to update if conflict occurs (default: all provided columns).
271
+ *
272
+ * Empty means "insert, or keep the row that stands". The kept row is read
273
+ * back after the statement, so on PostgreSQL and SQLite a row another
274
+ * writer deletes between the two cannot be returned, and the call resolves
275
+ * to `null`. Whether THIS call created the row is told by the id it
276
+ * returns: send a fresh id, and only a call whose own insert ran gets it
277
+ * back — a read-back can only return another writer's row.
278
+ */
270
279
  updateColumns?: string[];
271
280
  /** Columns to return after upsert (use "*" for all columns) */
272
281
  returning?: string[] | "*";
@@ -334,6 +343,21 @@ interface TransactionContext {
334
343
  * @returns Array of result rows
335
344
  */
336
345
  execute<T = unknown>(sql: string, params?: SqlParam[]): Promise<T[]>;
346
+ /**
347
+ * An instance bound to the SAME transaction client with the relational
348
+ * query API (`db.query.*`) enabled — the transaction's counterpart of
349
+ * `getDrizzle(relations)`.
350
+ *
351
+ * The `getDrizzle()` instance has an empty `query` namespace, so a
352
+ * relational read inside the transaction needs this one; the pooled
353
+ * `getDrizzle(relations)` would read on a different connection and miss the
354
+ * transaction's uncommitted writes. Memoized per relations object, as
355
+ * `getDrizzle` is, so repeated calls with an unchanged config share one
356
+ * instance.
357
+ *
358
+ * @param relations - drizzle v1 relations config (defineRelations output)
359
+ */
360
+ drizzleWithRelations<T = unknown>(relations: AnyRelations): T;
337
361
  /**
338
362
  * Run a Drizzle-built statement within the transaction, for its effect.
339
363
  *
@@ -669,6 +693,19 @@ interface DatabaseCapabilities {
669
693
  * - SQLite: No limit (practically unlimited)
670
694
  */
671
695
  maxIdentifierLength: number;
696
+ /**
697
+ * Whether the server accepts `SELECT ... FOR SHARE`.
698
+ *
699
+ * @remarks
700
+ * Reported by the MySQL adapter once it has connected and read the server's
701
+ * version: MySQL 8, Aurora MySQL and Vitess/PlanetScale accept it, MariaDB
702
+ * and TiDB reject it as a syntax error. PostgreSQL always accepts it and
703
+ * SQLite has no row locks, so their adapters leave it unset. Unset means
704
+ * not known; a caller then takes a lock every server accepts.
705
+ *
706
+ * @experimental
707
+ */
708
+ sharedRowLock?: boolean;
672
709
  }
673
710
  /**
674
711
  * Connection pool statistics.
@@ -1,6 +1,6 @@
1
- import { D as DrizzleAdapter } from './adapter-Cs3Jl9Fb.cjs';
2
- import { M as MigrationRecord, a as Migration, b as MigrationStatus, c as MigrationOptions } from './migration-Ce0hkgr_.cjs';
3
- export { d as MigrationResult } from './migration-Ce0hkgr_.cjs';
1
+ import { D as DrizzleAdapter } from './adapter-bUAaPzjV.cjs';
2
+ import { M as MigrationRecord, a as Migration, b as MigrationStatus, c as MigrationOptions } from './migration-Bu0WLdX4.cjs';
3
+ export { d as MigrationResult } from './migration-Bu0WLdX4.cjs';
4
4
  import 'drizzle-orm';
5
5
  import './core-CVO7WYDj.cjs';
6
6
  import './schema-BDn8WfSL.cjs';
@@ -1,6 +1,6 @@
1
- import { D as DrizzleAdapter } from './adapter-CHlx_Taa.js';
2
- import { M as MigrationRecord, a as Migration, b as MigrationStatus, c as MigrationOptions } from './migration-CgoxgWOL.js';
3
- export { d as MigrationResult } from './migration-CgoxgWOL.js';
1
+ import { D as DrizzleAdapter } from './adapter-iJ5hbUvL.js';
2
+ import { M as MigrationRecord, a as Migration, b as MigrationStatus, c as MigrationOptions } from './migration-BqHebSwM.js';
3
+ export { d as MigrationResult } from './migration-BqHebSwM.js';
4
4
  import 'drizzle-orm';
5
5
  import './core-CVO7WYDj.js';
6
6
  import './schema-BIQ0YQZ_.js';
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ // src/schema-name.ts
4
+ var IDENTIFIER = /^[a-z_][a-z0-9_]{0,62}$/;
5
+ function isValidSchemaName(name) {
6
+ return IDENTIFIER.test(name) && !name.startsWith("pg_");
7
+ }
8
+ function assertSchemaName(name) {
9
+ if (!isValidSchemaName(name)) {
10
+ throw new Error(
11
+ `Invalid PostgreSQL schema name "${name}". Use lower-case letters, digits and underscores, starting with a letter or underscore (max 63 characters), and not beginning with "pg_".`
12
+ );
13
+ }
14
+ return name;
15
+ }
16
+
17
+ exports.assertSchemaName = assertSchemaName;
18
+ exports.isValidSchemaName = isValidSchemaName;
19
+ //# sourceMappingURL=schema-name.cjs.map
20
+ //# sourceMappingURL=schema-name.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/schema-name.ts"],"names":[],"mappings":";;;AAoBA,IAAM,UAAA,GAAa,yBAAA;AAGZ,SAAS,kBAAkB,IAAA,EAAuB;AAEvD,EAAA,OAAO,WAAW,IAAA,CAAK,IAAI,KAAK,CAAC,IAAA,CAAK,WAAW,KAAK,CAAA;AACxD;AAUO,SAAS,iBAAiB,IAAA,EAAsB;AACrD,EAAA,IAAI,CAAC,iBAAA,CAAkB,IAAI,CAAA,EAAG;AAC5B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,mCAAmC,IAAI,CAAA,0IAAA;AAAA,KACzC;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT","file":"schema-name.cjs","sourcesContent":["/**\n * The one rule for a PostgreSQL schema name.\n *\n * Lives in the adapter package because both sides need it and neither may\n * import the other: `nextly` validates the configured value at boot so the\n * error names the setting, and the Postgres adapter validates again at the\n * point of interpolation, because that is where a bad value becomes SQL.\n *\n * @module schema-name\n * @since 1.0.0\n */\n\n/**\n * A plain, lower-case identifier.\n *\n * Checked rather than quoted because the value is interpolated into\n * `search_path` and `CREATE SCHEMA`, where a quoted-but-hostile name is still\n * a name somebody else chose. Refusing the shapes that need quoting costs\n * nothing real and removes the question entirely.\n */\nconst IDENTIFIER = /^[a-z_][a-z0-9_]{0,62}$/;\n\n/** Whether this is a name the adapter will interpolate. */\nexport function isValidSchemaName(name: string): boolean {\n // `pg_` is PostgreSQL's reserved prefix for system catalogs.\n return IDENTIFIER.test(name) && !name.startsWith(\"pg_\");\n}\n\n/**\n * Return the name, or throw rather than interpolate something unchecked.\n *\n * The adapter throws a plain Error: it has no access to the config path that\n * produced the value, and `nextly` already refuses the same shapes at boot\n * with a message that names `db.postgres.schema`. This is the backstop for a\n * caller that constructed the adapter directly.\n */\nexport function assertSchemaName(name: string): string {\n if (!isValidSchemaName(name)) {\n throw new Error(\n `Invalid PostgreSQL schema name \"${name}\". Use lower-case letters, digits and underscores, starting with a letter or underscore (max 63 characters), and not beginning with \"pg_\".`\n );\n }\n return name;\n}\n"]}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The one rule for a PostgreSQL schema name.
3
+ *
4
+ * Lives in the adapter package because both sides need it and neither may
5
+ * import the other: `nextly` validates the configured value at boot so the
6
+ * error names the setting, and the Postgres adapter validates again at the
7
+ * point of interpolation, because that is where a bad value becomes SQL.
8
+ *
9
+ * @module schema-name
10
+ * @since 1.0.0
11
+ */
12
+ /** Whether this is a name the adapter will interpolate. */
13
+ declare function isValidSchemaName(name: string): boolean;
14
+ /**
15
+ * Return the name, or throw rather than interpolate something unchecked.
16
+ *
17
+ * The adapter throws a plain Error: it has no access to the config path that
18
+ * produced the value, and `nextly` already refuses the same shapes at boot
19
+ * with a message that names `db.postgres.schema`. This is the backstop for a
20
+ * caller that constructed the adapter directly.
21
+ */
22
+ declare function assertSchemaName(name: string): string;
23
+
24
+ export { assertSchemaName, isValidSchemaName };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The one rule for a PostgreSQL schema name.
3
+ *
4
+ * Lives in the adapter package because both sides need it and neither may
5
+ * import the other: `nextly` validates the configured value at boot so the
6
+ * error names the setting, and the Postgres adapter validates again at the
7
+ * point of interpolation, because that is where a bad value becomes SQL.
8
+ *
9
+ * @module schema-name
10
+ * @since 1.0.0
11
+ */
12
+ /** Whether this is a name the adapter will interpolate. */
13
+ declare function isValidSchemaName(name: string): boolean;
14
+ /**
15
+ * Return the name, or throw rather than interpolate something unchecked.
16
+ *
17
+ * The adapter throws a plain Error: it has no access to the config path that
18
+ * produced the value, and `nextly` already refuses the same shapes at boot
19
+ * with a message that names `db.postgres.schema`. This is the backstop for a
20
+ * caller that constructed the adapter directly.
21
+ */
22
+ declare function assertSchemaName(name: string): string;
23
+
24
+ export { assertSchemaName, isValidSchemaName };
@@ -0,0 +1,17 @@
1
+ // src/schema-name.ts
2
+ var IDENTIFIER = /^[a-z_][a-z0-9_]{0,62}$/;
3
+ function isValidSchemaName(name) {
4
+ return IDENTIFIER.test(name) && !name.startsWith("pg_");
5
+ }
6
+ function assertSchemaName(name) {
7
+ if (!isValidSchemaName(name)) {
8
+ throw new Error(
9
+ `Invalid PostgreSQL schema name "${name}". Use lower-case letters, digits and underscores, starting with a letter or underscore (max 63 characters), and not beginning with "pg_".`
10
+ );
11
+ }
12
+ return name;
13
+ }
14
+
15
+ export { assertSchemaName, isValidSchemaName };
16
+ //# sourceMappingURL=schema-name.mjs.map
17
+ //# sourceMappingURL=schema-name.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/schema-name.ts"],"names":[],"mappings":";AAoBA,IAAM,UAAA,GAAa,yBAAA;AAGZ,SAAS,kBAAkB,IAAA,EAAuB;AAEvD,EAAA,OAAO,WAAW,IAAA,CAAK,IAAI,KAAK,CAAC,IAAA,CAAK,WAAW,KAAK,CAAA;AACxD;AAUO,SAAS,iBAAiB,IAAA,EAAsB;AACrD,EAAA,IAAI,CAAC,iBAAA,CAAkB,IAAI,CAAA,EAAG;AAC5B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,mCAAmC,IAAI,CAAA,0IAAA;AAAA,KACzC;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT","file":"schema-name.mjs","sourcesContent":["/**\n * The one rule for a PostgreSQL schema name.\n *\n * Lives in the adapter package because both sides need it and neither may\n * import the other: `nextly` validates the configured value at boot so the\n * error names the setting, and the Postgres adapter validates again at the\n * point of interpolation, because that is where a bad value becomes SQL.\n *\n * @module schema-name\n * @since 1.0.0\n */\n\n/**\n * A plain, lower-case identifier.\n *\n * Checked rather than quoted because the value is interpolated into\n * `search_path` and `CREATE SCHEMA`, where a quoted-but-hostile name is still\n * a name somebody else chose. Refusing the shapes that need quoting costs\n * nothing real and removes the question entirely.\n */\nconst IDENTIFIER = /^[a-z_][a-z0-9_]{0,62}$/;\n\n/** Whether this is a name the adapter will interpolate. */\nexport function isValidSchemaName(name: string): boolean {\n // `pg_` is PostgreSQL's reserved prefix for system catalogs.\n return IDENTIFIER.test(name) && !name.startsWith(\"pg_\");\n}\n\n/**\n * Return the name, or throw rather than interpolate something unchecked.\n *\n * The adapter throws a plain Error: it has no access to the config path that\n * produced the value, and `nextly` already refuses the same shapes at boot\n * with a message that names `db.postgres.schema`. This is the backstop for a\n * caller that constructed the adapter directly.\n */\nexport function assertSchemaName(name: string): string {\n if (!isValidSchemaName(name)) {\n throw new Error(\n `Invalid PostgreSQL schema name \"${name}\". Use lower-case letters, digits and underscores, starting with a letter or underscore (max 63 characters), and not beginning with \"pg_\".`\n );\n }\n return name;\n}\n"]}
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ var drizzleOrm = require('drizzle-orm');
4
+
5
+ // src/text-match.ts
6
+ function containsPattern(value) {
7
+ return `%${value.replace(/[!%_]/g, (character) => `!${character}`)}%`;
8
+ }
9
+ function caseInsensitiveContains(column, value) {
10
+ return drizzleOrm.sql`lower(${column}) like lower(${containsPattern(value)}) escape '!'`;
11
+ }
12
+
13
+ exports.caseInsensitiveContains = caseInsensitiveContains;
14
+ exports.containsPattern = containsPattern;
15
+ //# sourceMappingURL=text-match.cjs.map
16
+ //# sourceMappingURL=text-match.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/text-match.ts"],"names":["sql"],"mappings":";;;;;AAyBO,SAAS,gBAAgB,KAAA,EAAuB;AACrD,EAAA,OAAO,CAAA,CAAA,EAAI,MAAM,OAAA,CAAQ,QAAA,EAAU,eAAa,CAAA,CAAA,EAAI,SAAS,EAAE,CAAC,CAAA,CAAA,CAAA;AAClE;AAgBO,SAAS,uBAAA,CACd,QACA,KAAA,EACK;AACL,EAAA,OAAOA,cAAA,CAAA,MAAA,EAAY,MAAM,CAAA,aAAA,EAAgB,eAAA,CAAgB,KAAK,CAAC,CAAA,YAAA,CAAA;AACjE","file":"text-match.cjs","sourcesContent":["/**\n * Case-insensitive, literal substring matching: the one rule for \"does this text contain that,\n * ignoring case\" on every dialect.\n *\n * The where builder's `ICONTAINS` compiles through it, and so does any caller that builds its own\n * SQL against a column, such as a collection's search, so the rule cannot be spelled two ways.\n *\n * @module text-match\n */\nimport { sql, type SQL, type SQLWrapper } from \"drizzle-orm\";\n\n/**\n * Wraps a value in `%…%` for a substring match, escaping the LIKE metacharacters inside it so\n * the value matches literally.\n *\n * `!` is the escape character rather than the more usual backslash, and it has to be, because\n * this builder emits one statement for every dialect. SQLite gives LIKE no default escape\n * character at all, so a backslash there is just a backslash; declaring `ESCAPE '\\'` instead\n * runs into MySQL, where the backslash also escapes inside the string literal and the clause\n * would have to be spelled differently per dialect. `ESCAPE '!'` parses identically on\n * PostgreSQL, MySQL and SQLite, and needs no per-dialect branch to stay correct.\n *\n * The escape character is escaped FIRST by including it in the character class, so a literal\n * `!` in the value cannot be produced by escaping something else afterwards.\n */\nexport function containsPattern(value: string): string {\n return `%${value.replace(/[!%_]/g, character => `!${character}`)}%`;\n}\n\n/**\n * `column` contains `value`, without regard to case, on PostgreSQL, MySQL and SQLite, even where\n * the column's collation is case-sensitive: both sides lower-cased, `value` matched literally\n * (its `%` and `_` are characters to find, not wildcards).\n *\n * Which letters fold is the database's own `lower()` under the column's collation: MySQL by its\n * collation's Unicode version, PostgreSQL's non-ASCII letters too under a linguistic collation,\n * and ASCII letters only on SQLite and under PostgreSQL's `C` or `POSIX`.\n *\n * @experimental\n * @param column - The column, or any SQL expression yielding text\n * @param value - The text to find, as the person typed it\n * @returns The condition\n */\nexport function caseInsensitiveContains(\n column: SQLWrapper,\n value: string\n): SQL {\n return sql`lower(${column}) like lower(${containsPattern(value)}) escape '!'`;\n}\n"]}
@@ -0,0 +1,44 @@
1
+ import { SQLWrapper, SQL } from 'drizzle-orm';
2
+
3
+ /**
4
+ * Case-insensitive, literal substring matching: the one rule for "does this text contain that,
5
+ * ignoring case" on every dialect.
6
+ *
7
+ * The where builder's `ICONTAINS` compiles through it, and so does any caller that builds its own
8
+ * SQL against a column, such as a collection's search, so the rule cannot be spelled two ways.
9
+ *
10
+ * @module text-match
11
+ */
12
+
13
+ /**
14
+ * Wraps a value in `%…%` for a substring match, escaping the LIKE metacharacters inside it so
15
+ * the value matches literally.
16
+ *
17
+ * `!` is the escape character rather than the more usual backslash, and it has to be, because
18
+ * this builder emits one statement for every dialect. SQLite gives LIKE no default escape
19
+ * character at all, so a backslash there is just a backslash; declaring `ESCAPE '\'` instead
20
+ * runs into MySQL, where the backslash also escapes inside the string literal and the clause
21
+ * would have to be spelled differently per dialect. `ESCAPE '!'` parses identically on
22
+ * PostgreSQL, MySQL and SQLite, and needs no per-dialect branch to stay correct.
23
+ *
24
+ * The escape character is escaped FIRST by including it in the character class, so a literal
25
+ * `!` in the value cannot be produced by escaping something else afterwards.
26
+ */
27
+ declare function containsPattern(value: string): string;
28
+ /**
29
+ * `column` contains `value`, without regard to case, on PostgreSQL, MySQL and SQLite, even where
30
+ * the column's collation is case-sensitive: both sides lower-cased, `value` matched literally
31
+ * (its `%` and `_` are characters to find, not wildcards).
32
+ *
33
+ * Which letters fold is the database's own `lower()` under the column's collation: MySQL by its
34
+ * collation's Unicode version, PostgreSQL's non-ASCII letters too under a linguistic collation,
35
+ * and ASCII letters only on SQLite and under PostgreSQL's `C` or `POSIX`.
36
+ *
37
+ * @experimental
38
+ * @param column - The column, or any SQL expression yielding text
39
+ * @param value - The text to find, as the person typed it
40
+ * @returns The condition
41
+ */
42
+ declare function caseInsensitiveContains(column: SQLWrapper, value: string): SQL;
43
+
44
+ export { caseInsensitiveContains, containsPattern };
@@ -0,0 +1,44 @@
1
+ import { SQLWrapper, SQL } from 'drizzle-orm';
2
+
3
+ /**
4
+ * Case-insensitive, literal substring matching: the one rule for "does this text contain that,
5
+ * ignoring case" on every dialect.
6
+ *
7
+ * The where builder's `ICONTAINS` compiles through it, and so does any caller that builds its own
8
+ * SQL against a column, such as a collection's search, so the rule cannot be spelled two ways.
9
+ *
10
+ * @module text-match
11
+ */
12
+
13
+ /**
14
+ * Wraps a value in `%…%` for a substring match, escaping the LIKE metacharacters inside it so
15
+ * the value matches literally.
16
+ *
17
+ * `!` is the escape character rather than the more usual backslash, and it has to be, because
18
+ * this builder emits one statement for every dialect. SQLite gives LIKE no default escape
19
+ * character at all, so a backslash there is just a backslash; declaring `ESCAPE '\'` instead
20
+ * runs into MySQL, where the backslash also escapes inside the string literal and the clause
21
+ * would have to be spelled differently per dialect. `ESCAPE '!'` parses identically on
22
+ * PostgreSQL, MySQL and SQLite, and needs no per-dialect branch to stay correct.
23
+ *
24
+ * The escape character is escaped FIRST by including it in the character class, so a literal
25
+ * `!` in the value cannot be produced by escaping something else afterwards.
26
+ */
27
+ declare function containsPattern(value: string): string;
28
+ /**
29
+ * `column` contains `value`, without regard to case, on PostgreSQL, MySQL and SQLite, even where
30
+ * the column's collation is case-sensitive: both sides lower-cased, `value` matched literally
31
+ * (its `%` and `_` are characters to find, not wildcards).
32
+ *
33
+ * Which letters fold is the database's own `lower()` under the column's collation: MySQL by its
34
+ * collation's Unicode version, PostgreSQL's non-ASCII letters too under a linguistic collation,
35
+ * and ASCII letters only on SQLite and under PostgreSQL's `C` or `POSIX`.
36
+ *
37
+ * @experimental
38
+ * @param column - The column, or any SQL expression yielding text
39
+ * @param value - The text to find, as the person typed it
40
+ * @returns The condition
41
+ */
42
+ declare function caseInsensitiveContains(column: SQLWrapper, value: string): SQL;
43
+
44
+ export { caseInsensitiveContains, containsPattern };
@@ -0,0 +1,13 @@
1
+ import { sql } from 'drizzle-orm';
2
+
3
+ // src/text-match.ts
4
+ function containsPattern(value) {
5
+ return `%${value.replace(/[!%_]/g, (character) => `!${character}`)}%`;
6
+ }
7
+ function caseInsensitiveContains(column, value) {
8
+ return sql`lower(${column}) like lower(${containsPattern(value)}) escape '!'`;
9
+ }
10
+
11
+ export { caseInsensitiveContains, containsPattern };
12
+ //# sourceMappingURL=text-match.mjs.map
13
+ //# sourceMappingURL=text-match.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/text-match.ts"],"names":[],"mappings":";;;AAyBO,SAAS,gBAAgB,KAAA,EAAuB;AACrD,EAAA,OAAO,CAAA,CAAA,EAAI,MAAM,OAAA,CAAQ,QAAA,EAAU,eAAa,CAAA,CAAA,EAAI,SAAS,EAAE,CAAC,CAAA,CAAA,CAAA;AAClE;AAgBO,SAAS,uBAAA,CACd,QACA,KAAA,EACK;AACL,EAAA,OAAO,GAAA,CAAA,MAAA,EAAY,MAAM,CAAA,aAAA,EAAgB,eAAA,CAAgB,KAAK,CAAC,CAAA,YAAA,CAAA;AACjE","file":"text-match.mjs","sourcesContent":["/**\n * Case-insensitive, literal substring matching: the one rule for \"does this text contain that,\n * ignoring case\" on every dialect.\n *\n * The where builder's `ICONTAINS` compiles through it, and so does any caller that builds its own\n * SQL against a column, such as a collection's search, so the rule cannot be spelled two ways.\n *\n * @module text-match\n */\nimport { sql, type SQL, type SQLWrapper } from \"drizzle-orm\";\n\n/**\n * Wraps a value in `%…%` for a substring match, escaping the LIKE metacharacters inside it so\n * the value matches literally.\n *\n * `!` is the escape character rather than the more usual backslash, and it has to be, because\n * this builder emits one statement for every dialect. SQLite gives LIKE no default escape\n * character at all, so a backslash there is just a backslash; declaring `ESCAPE '\\'` instead\n * runs into MySQL, where the backslash also escapes inside the string literal and the clause\n * would have to be spelled differently per dialect. `ESCAPE '!'` parses identically on\n * PostgreSQL, MySQL and SQLite, and needs no per-dialect branch to stay correct.\n *\n * The escape character is escaped FIRST by including it in the character class, so a literal\n * `!` in the value cannot be produced by escaping something else afterwards.\n */\nexport function containsPattern(value: string): string {\n return `%${value.replace(/[!%_]/g, character => `!${character}`)}%`;\n}\n\n/**\n * `column` contains `value`, without regard to case, on PostgreSQL, MySQL and SQLite, even where\n * the column's collation is case-sensitive: both sides lower-cased, `value` matched literally\n * (its `%` and `_` are characters to find, not wildcards).\n *\n * Which letters fold is the database's own `lower()` under the column's collation: MySQL by its\n * collation's Unicode version, PostgreSQL's non-ASCII letters too under a linguistic collation,\n * and ASCII letters only on SQLite and under PostgreSQL's `C` or `POSIX`.\n *\n * @experimental\n * @param column - The column, or any SQL expression yielding text\n * @param value - The text to find, as the person typed it\n * @returns The condition\n */\nexport function caseInsensitiveContains(\n column: SQLWrapper,\n value: string\n): SQL {\n return sql`lower(${column}) like lower(${containsPattern(value)}) escape '!'`;\n}\n"]}
@@ -23,6 +23,13 @@ var WHERE_OPERATORS = [
23
23
  // coerce, and there it searches the serialized text — which hits a key name as readily as a
24
24
  // value. Text columns only, and a search rather than a containment check.
25
25
  "CONTAINS",
26
+ // CONTAINS without regard to case: a substring match on a TEXT column with the value taken
27
+ // literally (`%` and `_` are characters to find, not wildcards), ignoring case on every
28
+ // dialect even where the column's collation is case-sensitive. Which letters fold is the
29
+ // database's `lower()` under the column's collation: the collation's Unicode version on
30
+ // MySQL; non-ASCII too under a linguistic PostgreSQL collation; ASCII letters only on
31
+ // SQLite and under PostgreSQL's `C` or `POSIX`.
32
+ "ICONTAINS",
26
33
  // Declared, never implemented — the builder throws `Unsupported operator: OVERLAPS`. Kept in
27
34
  // the union because removing it would be a breaking change to a published type; the refusal
28
35
  // is pinned by a test so implementing it has to come through here.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/query.ts","../../src/types/error.ts"],"names":[],"mappings":";;;AAoCO,IAAM,eAAA,GAAkB;AAAA,EAC7B,GAAA;AAAA,EACA,IAAA;AAAA,EACA,GAAA;AAAA,EACA,GAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,aAAA;AAAA,EACA,SAAA;AAAA,EACA,aAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAA;AAAA;AAAA;AAAA;AAAA,EAIA;AACF;;;ACyBO,SAAS,gBAAgB,KAAA,EAAwC;AACtE,EAAA,OACE,OAAO,UAAU,QAAA,IACjB,KAAA,KAAU,QACV,MAAA,IAAU,KAAA,IACV,OAAQ,KAAA,CAAwB,IAAA,KAAS,QAAA;AAE7C;AAYA,IAAM,uBAAA,GAAyC,MAAA,CAAO,GAAA,CAAI,oBAAoB,CAAA;AAkBvE,SAAS,mBAAmB,KAAA,EAAyB;AAC1D,EAAA,IACE,UAAU,IAAA,IACT,OAAO,UAAU,QAAA,IAAY,OAAO,UAAU,UAAA,EAC/C;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAQ,KAAA,CAAkC,uBAAuB,CAAA,KAAM,IAAA;AACzE;AA+CO,SAAS,oBACd,OAAA,EACe;AACf,EAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA;AACvC,EAAA,KAAA,CAAM,IAAA,GAAO,eAAA;AACb,EAAA,KAAA,CAAM,OAAO,OAAA,CAAQ,IAAA;AAErB,EAAA,IAAI,OAAA,CAAQ,IAAA,KAAS,MAAA,EAAW,KAAA,CAAM,OAAO,OAAA,CAAQ,IAAA;AACrD,EAAA,IAAI,OAAA,CAAQ,UAAA,KAAe,MAAA,EAAW,KAAA,CAAM,aAAa,OAAA,CAAQ,UAAA;AACjE,EAAA,IAAI,OAAA,CAAQ,KAAA,KAAU,MAAA,EAAW,KAAA,CAAM,QAAQ,OAAA,CAAQ,KAAA;AACvD,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,MAAA,EAAW,KAAA,CAAM,SAAS,OAAA,CAAQ,MAAA;AACzD,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,MAAA,EAAW,KAAA,CAAM,SAAS,OAAA,CAAQ,MAAA;AACzD,EAAA,IAAI,OAAA,CAAQ,IAAA,KAAS,MAAA,EAAW,KAAA,CAAM,OAAO,OAAA,CAAQ,IAAA;AACrD,EAAA,IAAI,OAAA,CAAQ,KAAA,KAAU,MAAA,EAAW,KAAA,CAAM,QAAQ,OAAA,CAAQ,KAAA;AAEvD,EAAA,OAAO,KAAA;AACT","file":"index.cjs","sourcesContent":["/**\n * Query building type definitions for database-agnostic queries.\n *\n * @packageDocumentation\n */\n\nimport type { SqlParam } from \"./core\";\n\n/**\n * Every WHERE clause operator this package DECLARES, as a value.\n *\n * @remarks\n * Declared, not guaranteed executable. Membership here means a `WhereCondition`\n * carrying the operator type-checks — it does NOT mean the adapter can run it.\n * `OVERLAPS` is declared and unimplemented, and throws at build time, so a\n * validator written against this list will admit input the query layer then\n * rejects. Validate against it to catch a misspelled operator; do not read\n * acceptance here as a capability.\n *\n * - Standard comparison: =, !=, <, >, <=, >=\n * - Set operations: IN, NOT IN\n * - Pattern matching: LIKE, ILIKE (case-insensitive, PostgreSQL/emulated)\n * - NULL checks: IS NULL, IS NOT NULL\n * - Range: BETWEEN, NOT BETWEEN\n * - Substring: CONTAINS — a LITERAL match on a TEXT column; see below\n * - Declared but NOT implemented: OVERLAPS, which throws\n *\n * This list is the source of truth and {@link WhereOperator} is derived from it,\n * rather than the two being written out separately. A guard that has to enumerate\n * the operators — a validator over caller input, or a test asserting the builder\n * handles or refuses each one — can only do that from a runtime value, and a\n * hand-kept copy of the union would agree with it on the day it was written and\n * silently stop agreeing the next time a member is added.\n *\n * @public\n */\nexport const WHERE_OPERATORS = [\n \"=\",\n \"!=\",\n \"<\",\n \">\",\n \"<=\",\n \">=\",\n \"IN\",\n \"NOT IN\",\n \"LIKE\",\n \"ILIKE\",\n \"IS NULL\",\n \"IS NOT NULL\",\n \"BETWEEN\",\n \"NOT BETWEEN\",\n // Substring match on a TEXT column, with the value taken literally. Despite the name it is\n // not JSON containment, and it is not safe to point at a JSON column: the builder emits a\n // bare `LIKE` with no cast, so on PostgreSQL a `json`/`jsonb` column has no matching operator\n // and the statement ERRORS (`operator does not exist: jsonb ~~ text`). MySQL and SQLite\n // coerce, and there it searches the serialized text — which hits a key name as readily as a\n // value. Text columns only, and a search rather than a containment check.\n \"CONTAINS\",\n // Declared, never implemented — the builder throws `Unsupported operator: OVERLAPS`. Kept in\n // the union because removing it would be a breaking change to a published type; the refusal\n // is pinned by a test so implementing it has to come through here.\n \"OVERLAPS\",\n] as const;\n\n/**\n * Every WHERE clause operator this package declares. Derived from\n * {@link WHERE_OPERATORS}, and carrying the same caveat: a value of this type\n * type-checks, which is not the same as the adapter being able to execute it.\n *\n * @public\n */\nexport type WhereOperator = (typeof WHERE_OPERATORS)[number];\n\n/**\n * Individual WHERE condition.\n *\n * @remarks\n * Represents a single condition in a WHERE clause. For IS NULL and IS NOT NULL\n * operators, the value field is optional.\n *\n * @public\n */\nexport interface WhereCondition {\n /** Column name to filter on */\n column: string;\n\n /** Comparison operator */\n op: WhereOperator;\n\n /** Value(s) to compare against (optional for IS NULL/IS NOT NULL) */\n value?: SqlParam | SqlParam[];\n\n /** Second value for BETWEEN operator */\n valueTo?: SqlParam;\n}\n\n/**\n * Complex WHERE clause with logical operators.\n *\n * @remarks\n * Supports nested conditions with AND, OR, and NOT logical operators.\n * Can be recursively nested for complex queries.\n *\n * @example\n * ```typescript\n * const where: WhereClause = {\n * and: [\n * { column: \"status\", op: \"=\", value: \"published\" },\n * {\n * or: [\n * { column: \"author\", op: \"=\", value: \"john\" },\n * { column: \"author\", op: \"=\", value: \"jane\" }\n * ]\n * }\n * ]\n * };\n * ```\n *\n * @public\n */\nexport interface WhereClause {\n /** All conditions must be true (AND) */\n and?: (WhereCondition | WhereClause)[];\n\n /** At least one condition must be true (OR) */\n or?: (WhereCondition | WhereClause)[];\n\n /** Negate a condition (NOT) */\n not?: WhereCondition | WhereClause;\n}\n\n/**\n * ORDER BY specification for query results.\n *\n * @remarks\n * Controls the sorting of query results. NULL handling varies by database\n * but can be explicitly controlled with the nulls field.\n *\n * @public\n */\nexport interface OrderBySpec {\n /** Column name to sort by */\n column: string;\n\n /** Sort direction (default: asc) */\n direction?: \"asc\" | \"desc\";\n\n /** NULL value ordering (database-specific defaults vary) */\n nulls?: \"first\" | \"last\";\n}\n\n/**\n * JOIN specification for table joins.\n *\n * @remarks\n * Supports different types of JOINs. Note that complex joins may require\n * dialect-specific handling.\n *\n * @public\n */\nexport interface JoinSpec {\n /** Type of join */\n type: \"inner\" | \"left\" | \"right\" | \"full\";\n\n /** Table name to join */\n table: string;\n\n /** Join condition */\n on: {\n /** Column from the left table */\n leftColumn: string;\n /** Column from the right table */\n rightColumn: string;\n };\n\n /** Optional alias for the joined table */\n alias?: string;\n}\n","/**\n * Database error type definitions.\n *\n * @packageDocumentation\n */\n\n/**\n * Database error classification.\n *\n * @remarks\n * Categorizes database errors for consistent error handling across adapters.\n * Each adapter translates database-specific error codes to these kinds.\n *\n * @public\n */\nexport type DatabaseErrorKind =\n | \"connection\" // Connection/network errors\n | \"query\" // Syntax or execution errors\n | \"constraint\" // Generic constraint violation\n | \"unique_violation\" // Unique constraint violation\n | \"foreign_key_violation\" // Foreign key constraint violation\n | \"check_violation\" // Check constraint violation\n | \"not_null_violation\" // NOT NULL constraint violation\n | \"deadlock\" // Transaction deadlock\n | \"timeout\" // Query or connection timeout\n | \"serialization_failure\" // Serializable transaction conflict\n | \"unsupported_version\" // F17: DB version below minimum or unparseable at connect\n | \"unknown\"; // Unclassified error\n\n/**\n * Enhanced database error interface.\n *\n * @remarks\n * Extends the standard Error interface with database-specific context.\n * Adapters should throw errors implementing this interface for consistent\n * error handling.\n *\n * @example\n * ```typescript\n * try {\n * await adapter.insert('users', { email: 'duplicate@example.com' });\n * } catch (error) {\n * if (isDatabaseError(error) && error.kind === 'unique_violation') {\n * console.log(`Duplicate ${error.column} in ${error.table}`);\n * }\n * }\n * ```\n *\n * @public\n */\nexport interface DatabaseError extends Error {\n /** Error classification */\n kind: DatabaseErrorKind;\n\n /** Database-specific error code (e.g., \"23505\" for PostgreSQL unique violation) */\n code?: string;\n\n /** Constraint name that was violated (if applicable) */\n constraint?: string;\n\n /** Table name involved in the error */\n table?: string;\n\n /** Column name involved in the error */\n column?: string;\n\n /** Detailed error description from the database */\n detail?: string;\n\n /** Hint for resolving the error */\n hint?: string;\n\n /** Original error from the database driver */\n cause?: Error;\n}\n\n/**\n * Type guard for DatabaseError.\n *\n * @remarks\n * Checks if an error is a DatabaseError with proper typing.\n *\n * @param error - Error to check\n * @returns True if error is a DatabaseError\n *\n * @public\n */\nexport function isDatabaseError(error: unknown): error is DatabaseError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"kind\" in error &&\n typeof (error as DatabaseError).kind === \"string\"\n );\n}\n\n/**\n * The brand every Nextly application error carries.\n *\n * Read through the global symbol registry rather than imported, because the\n * adapters must not depend on the package that defines the error: `Symbol.for`\n * resolves to the same symbol in every module instance, which is why the brand\n * exists in that form to begin with.\n *\n * @internal\n */\nconst APPLICATION_ERROR_BRAND: unique symbol = Symbol.for(\"nextly/NextlyError\");\n\n/**\n * Whether an error is the application's verdict rather than the database's\n * failure.\n *\n * Work running inside a transaction may throw to roll the write back — a\n * refused value, a permission denial — and such an error is not something the\n * driver produced. Classifying it as a database error replaces its code and its\n * payload with a generic one, so a caller that asked for a refusal is handed an\n * unexplained failure instead, and per-field validation detail is lost on the\n * way out.\n *\n * @param error - Error to check\n * @returns True if the error was raised by application code\n *\n * @public\n */\nexport function isApplicationError(error: unknown): boolean {\n if (\n error === null ||\n (typeof error !== \"object\" && typeof error !== \"function\")\n ) {\n return false;\n }\n return (error as Record<symbol, unknown>)[APPLICATION_ERROR_BRAND] === true;\n}\n\n/**\n * Database error constructor options.\n *\n * @public\n */\nexport interface DatabaseErrorOptions {\n /** Error classification */\n kind: DatabaseErrorKind;\n\n /** Error message */\n message: string;\n\n /** Database-specific error code */\n code?: string;\n\n /** Constraint name */\n constraint?: string;\n\n /** Table name */\n table?: string;\n\n /** Column name */\n column?: string;\n\n /** Detailed description */\n detail?: string;\n\n /** Resolution hint */\n hint?: string;\n\n /** Original error */\n cause?: Error;\n}\n\n/**\n * Create a DatabaseError instance.\n *\n * @remarks\n * Helper function to create properly structured DatabaseError objects.\n *\n * @param options - Error options\n * @returns DatabaseError instance\n *\n * @public\n */\nexport function createDatabaseError(\n options: DatabaseErrorOptions\n): DatabaseError {\n const error = new Error(options.message) as DatabaseError;\n error.name = \"DatabaseError\";\n error.kind = options.kind;\n\n if (options.code !== undefined) error.code = options.code;\n if (options.constraint !== undefined) error.constraint = options.constraint;\n if (options.table !== undefined) error.table = options.table;\n if (options.column !== undefined) error.column = options.column;\n if (options.detail !== undefined) error.detail = options.detail;\n if (options.hint !== undefined) error.hint = options.hint;\n if (options.cause !== undefined) error.cause = options.cause;\n\n return error;\n}\n"]}
1
+ {"version":3,"sources":["../../src/types/query.ts","../../src/types/error.ts"],"names":[],"mappings":";;;AAoCO,IAAM,eAAA,GAAkB;AAAA,EAC7B,GAAA;AAAA,EACA,IAAA;AAAA,EACA,GAAA;AAAA,EACA,GAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,aAAA;AAAA,EACA,SAAA;AAAA,EACA,aAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAA;AAAA;AAAA;AAAA;AAAA,EAIA;AACF;;;ACkBO,SAAS,gBAAgB,KAAA,EAAwC;AACtE,EAAA,OACE,OAAO,UAAU,QAAA,IACjB,KAAA,KAAU,QACV,MAAA,IAAU,KAAA,IACV,OAAQ,KAAA,CAAwB,IAAA,KAAS,QAAA;AAE7C;AAYA,IAAM,uBAAA,GAAyC,MAAA,CAAO,GAAA,CAAI,oBAAoB,CAAA;AAkBvE,SAAS,mBAAmB,KAAA,EAAyB;AAC1D,EAAA,IACE,UAAU,IAAA,IACT,OAAO,UAAU,QAAA,IAAY,OAAO,UAAU,UAAA,EAC/C;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAQ,KAAA,CAAkC,uBAAuB,CAAA,KAAM,IAAA;AACzE;AA+CO,SAAS,oBACd,OAAA,EACe;AACf,EAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA;AACvC,EAAA,KAAA,CAAM,IAAA,GAAO,eAAA;AACb,EAAA,KAAA,CAAM,OAAO,OAAA,CAAQ,IAAA;AAErB,EAAA,IAAI,OAAA,CAAQ,IAAA,KAAS,MAAA,EAAW,KAAA,CAAM,OAAO,OAAA,CAAQ,IAAA;AACrD,EAAA,IAAI,OAAA,CAAQ,UAAA,KAAe,MAAA,EAAW,KAAA,CAAM,aAAa,OAAA,CAAQ,UAAA;AACjE,EAAA,IAAI,OAAA,CAAQ,KAAA,KAAU,MAAA,EAAW,KAAA,CAAM,QAAQ,OAAA,CAAQ,KAAA;AACvD,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,MAAA,EAAW,KAAA,CAAM,SAAS,OAAA,CAAQ,MAAA;AACzD,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,MAAA,EAAW,KAAA,CAAM,SAAS,OAAA,CAAQ,MAAA;AACzD,EAAA,IAAI,OAAA,CAAQ,IAAA,KAAS,MAAA,EAAW,KAAA,CAAM,OAAO,OAAA,CAAQ,IAAA;AACrD,EAAA,IAAI,OAAA,CAAQ,KAAA,KAAU,MAAA,EAAW,KAAA,CAAM,QAAQ,OAAA,CAAQ,KAAA;AAEvD,EAAA,OAAO,KAAA;AACT","file":"index.cjs","sourcesContent":["/**\n * Query building type definitions for database-agnostic queries.\n *\n * @packageDocumentation\n */\n\nimport type { SqlParam } from \"./core\";\n\n/**\n * Every WHERE clause operator this package DECLARES, as a value.\n *\n * @remarks\n * Declared, not guaranteed executable. Membership here means a `WhereCondition`\n * carrying the operator type-checks — it does NOT mean the adapter can run it.\n * `OVERLAPS` is declared and unimplemented, and throws at build time, so a\n * validator written against this list will admit input the query layer then\n * rejects. Validate against it to catch a misspelled operator; do not read\n * acceptance here as a capability.\n *\n * - Standard comparison: =, !=, <, >, <=, >=\n * - Set operations: IN, NOT IN\n * - Pattern matching: LIKE, ILIKE (case-insensitive, PostgreSQL/emulated)\n * - NULL checks: IS NULL, IS NOT NULL\n * - Range: BETWEEN, NOT BETWEEN\n * - Substring: CONTAINS — a LITERAL match on a TEXT column; see below\n * - Declared but NOT implemented: OVERLAPS, which throws\n *\n * This list is the source of truth and {@link WhereOperator} is derived from it,\n * rather than the two being written out separately. A guard that has to enumerate\n * the operators — a validator over caller input, or a test asserting the builder\n * handles or refuses each one — can only do that from a runtime value, and a\n * hand-kept copy of the union would agree with it on the day it was written and\n * silently stop agreeing the next time a member is added.\n *\n * @public\n */\nexport const WHERE_OPERATORS = [\n \"=\",\n \"!=\",\n \"<\",\n \">\",\n \"<=\",\n \">=\",\n \"IN\",\n \"NOT IN\",\n \"LIKE\",\n \"ILIKE\",\n \"IS NULL\",\n \"IS NOT NULL\",\n \"BETWEEN\",\n \"NOT BETWEEN\",\n // Substring match on a TEXT column, with the value taken literally. Despite the name it is\n // not JSON containment, and it is not safe to point at a JSON column: the builder emits a\n // bare `LIKE` with no cast, so on PostgreSQL a `json`/`jsonb` column has no matching operator\n // and the statement ERRORS (`operator does not exist: jsonb ~~ text`). MySQL and SQLite\n // coerce, and there it searches the serialized text — which hits a key name as readily as a\n // value. Text columns only, and a search rather than a containment check.\n \"CONTAINS\",\n // CONTAINS without regard to case: a substring match on a TEXT column with the value taken\n // literally (`%` and `_` are characters to find, not wildcards), ignoring case on every\n // dialect even where the column's collation is case-sensitive. Which letters fold is the\n // database's `lower()` under the column's collation: the collation's Unicode version on\n // MySQL; non-ASCII too under a linguistic PostgreSQL collation; ASCII letters only on\n // SQLite and under PostgreSQL's `C` or `POSIX`.\n \"ICONTAINS\",\n // Declared, never implemented — the builder throws `Unsupported operator: OVERLAPS`. Kept in\n // the union because removing it would be a breaking change to a published type; the refusal\n // is pinned by a test so implementing it has to come through here.\n \"OVERLAPS\",\n] as const;\n\n/**\n * Every WHERE clause operator this package declares. Derived from\n * {@link WHERE_OPERATORS}, and carrying the same caveat: a value of this type\n * type-checks, which is not the same as the adapter being able to execute it.\n *\n * @public\n */\nexport type WhereOperator = (typeof WHERE_OPERATORS)[number];\n\n/**\n * Individual WHERE condition.\n *\n * @remarks\n * Represents a single condition in a WHERE clause. For IS NULL and IS NOT NULL\n * operators, the value field is optional.\n *\n * @public\n */\nexport interface WhereCondition {\n /** Column name to filter on */\n column: string;\n\n /** Comparison operator */\n op: WhereOperator;\n\n /** Value(s) to compare against (optional for IS NULL/IS NOT NULL) */\n value?: SqlParam | SqlParam[];\n\n /** Second value for BETWEEN operator */\n valueTo?: SqlParam;\n}\n\n/**\n * Complex WHERE clause with logical operators.\n *\n * @remarks\n * Supports nested conditions with AND, OR, and NOT logical operators.\n * Can be recursively nested for complex queries.\n *\n * @example\n * ```typescript\n * const where: WhereClause = {\n * and: [\n * { column: \"status\", op: \"=\", value: \"published\" },\n * {\n * or: [\n * { column: \"author\", op: \"=\", value: \"john\" },\n * { column: \"author\", op: \"=\", value: \"jane\" }\n * ]\n * }\n * ]\n * };\n * ```\n *\n * @public\n */\nexport interface WhereClause {\n /** All conditions must be true (AND) */\n and?: (WhereCondition | WhereClause)[];\n\n /** At least one condition must be true (OR) */\n or?: (WhereCondition | WhereClause)[];\n\n /** Negate a condition (NOT) */\n not?: WhereCondition | WhereClause;\n}\n\n/**\n * ORDER BY specification for query results.\n *\n * @remarks\n * Controls the sorting of query results. NULL handling varies by database\n * but can be explicitly controlled with the nulls field.\n *\n * @public\n */\nexport interface OrderBySpec {\n /** Column name to sort by */\n column: string;\n\n /** Sort direction (default: asc) */\n direction?: \"asc\" | \"desc\";\n\n /** NULL value ordering (database-specific defaults vary) */\n nulls?: \"first\" | \"last\";\n}\n\n/**\n * JOIN specification for table joins.\n *\n * @remarks\n * Supports different types of JOINs. Note that complex joins may require\n * dialect-specific handling.\n *\n * @public\n */\nexport interface JoinSpec {\n /** Type of join */\n type: \"inner\" | \"left\" | \"right\" | \"full\";\n\n /** Table name to join */\n table: string;\n\n /** Join condition */\n on: {\n /** Column from the left table */\n leftColumn: string;\n /** Column from the right table */\n rightColumn: string;\n };\n\n /** Optional alias for the joined table */\n alias?: string;\n}\n","/**\n * Database error type definitions.\n *\n * @packageDocumentation\n */\n\n/**\n * Database error classification.\n *\n * @remarks\n * Categorizes database errors for consistent error handling across adapters.\n * Each adapter translates database-specific error codes to these kinds.\n *\n * @public\n */\nexport type DatabaseErrorKind =\n | \"connection\" // Connection/network errors\n | \"query\" // Syntax or execution errors\n | \"constraint\" // Generic constraint violation\n | \"unique_violation\" // Unique constraint violation\n | \"foreign_key_violation\" // Foreign key constraint violation\n | \"check_violation\" // Check constraint violation\n | \"not_null_violation\" // NOT NULL constraint violation\n | \"deadlock\" // Transaction deadlock\n | \"timeout\" // Query or connection timeout\n | \"serialization_failure\" // Serializable transaction conflict\n | \"unsupported_version\" // F17: DB version below minimum or unparseable at connect\n | \"unknown\"; // Unclassified error\n\n/**\n * Enhanced database error interface.\n *\n * @remarks\n * Extends the standard Error interface with database-specific context.\n * Adapters should throw errors implementing this interface for consistent\n * error handling.\n *\n * @example\n * ```typescript\n * try {\n * await adapter.insert('users', { email: 'duplicate@example.com' });\n * } catch (error) {\n * if (isDatabaseError(error) && error.kind === 'unique_violation') {\n * console.log(`Duplicate ${error.column} in ${error.table}`);\n * }\n * }\n * ```\n *\n * @public\n */\nexport interface DatabaseError extends Error {\n /** Error classification */\n kind: DatabaseErrorKind;\n\n /** Database-specific error code (e.g., \"23505\" for PostgreSQL unique violation) */\n code?: string;\n\n /** Constraint name that was violated (if applicable) */\n constraint?: string;\n\n /** Table name involved in the error */\n table?: string;\n\n /** Column name involved in the error */\n column?: string;\n\n /** Detailed error description from the database */\n detail?: string;\n\n /** Hint for resolving the error */\n hint?: string;\n\n /** Original error from the database driver */\n cause?: Error;\n}\n\n/**\n * Type guard for DatabaseError.\n *\n * @remarks\n * Checks if an error is a DatabaseError with proper typing.\n *\n * @param error - Error to check\n * @returns True if error is a DatabaseError\n *\n * @public\n */\nexport function isDatabaseError(error: unknown): error is DatabaseError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"kind\" in error &&\n typeof (error as DatabaseError).kind === \"string\"\n );\n}\n\n/**\n * The brand every Nextly application error carries.\n *\n * Read through the global symbol registry rather than imported, because the\n * adapters must not depend on the package that defines the error: `Symbol.for`\n * resolves to the same symbol in every module instance, which is why the brand\n * exists in that form to begin with.\n *\n * @internal\n */\nconst APPLICATION_ERROR_BRAND: unique symbol = Symbol.for(\"nextly/NextlyError\");\n\n/**\n * Whether an error is the application's verdict rather than the database's\n * failure.\n *\n * Work running inside a transaction may throw to roll the write back — a\n * refused value, a permission denial — and such an error is not something the\n * driver produced. Classifying it as a database error replaces its code and its\n * payload with a generic one, so a caller that asked for a refusal is handed an\n * unexplained failure instead, and per-field validation detail is lost on the\n * way out.\n *\n * @param error - Error to check\n * @returns True if the error was raised by application code\n *\n * @public\n */\nexport function isApplicationError(error: unknown): boolean {\n if (\n error === null ||\n (typeof error !== \"object\" && typeof error !== \"function\")\n ) {\n return false;\n }\n return (error as Record<symbol, unknown>)[APPLICATION_ERROR_BRAND] === true;\n}\n\n/**\n * Database error constructor options.\n *\n * @public\n */\nexport interface DatabaseErrorOptions {\n /** Error classification */\n kind: DatabaseErrorKind;\n\n /** Error message */\n message: string;\n\n /** Database-specific error code */\n code?: string;\n\n /** Constraint name */\n constraint?: string;\n\n /** Table name */\n table?: string;\n\n /** Column name */\n column?: string;\n\n /** Detailed description */\n detail?: string;\n\n /** Resolution hint */\n hint?: string;\n\n /** Original error */\n cause?: Error;\n}\n\n/**\n * Create a DatabaseError instance.\n *\n * @remarks\n * Helper function to create properly structured DatabaseError objects.\n *\n * @param options - Error options\n * @returns DatabaseError instance\n *\n * @public\n */\nexport function createDatabaseError(\n options: DatabaseErrorOptions\n): DatabaseError {\n const error = new Error(options.message) as DatabaseError;\n error.name = \"DatabaseError\";\n error.kind = options.kind;\n\n if (options.code !== undefined) error.code = options.code;\n if (options.constraint !== undefined) error.constraint = options.constraint;\n if (options.table !== undefined) error.table = options.table;\n if (options.column !== undefined) error.column = options.column;\n if (options.detail !== undefined) error.detail = options.detail;\n if (options.hint !== undefined) error.hint = options.hint;\n if (options.cause !== undefined) error.cause = options.cause;\n\n return error;\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { a as SqlParam } from '../core-CVO7WYDj.cjs';
2
2
  export { J as JsonArray, b as JsonObject, c as JsonValue, S as SupportedDialect, T as TableResolver } from '../core-CVO7WYDj.cjs';
3
- export { C as CountOptions, f as DatabaseCapabilities, D as DeleteOptions, I as InsertOptions, J as JoinSpec, a as Migration, c as MigrationOptions, M as MigrationRecord, d as MigrationResult, b as MigrationStatus, O as OrderBySpec, P as PoolStats, S as SelectOptions, T as TransactionContext, h as TransactionIsolationLevel, e as TransactionOptions, g as UpdateOptions, U as UpsertOptions, i as WHERE_OPERATORS, W as WhereClause, j as WhereCondition, k as WhereOperator } from '../migration-Ce0hkgr_.cjs';
3
+ export { C as CountOptions, f as DatabaseCapabilities, D as DeleteOptions, I as InsertOptions, J as JoinSpec, a as Migration, c as MigrationOptions, M as MigrationRecord, d as MigrationResult, b as MigrationStatus, O as OrderBySpec, P as PoolStats, S as SelectOptions, T as TransactionContext, h as TransactionIsolationLevel, e as TransactionOptions, g as UpdateOptions, U as UpsertOptions, i as WHERE_OPERATORS, W as WhereClause, j as WhereCondition, k as WhereOperator } from '../migration-Bu0WLdX4.cjs';
4
4
  export { A as AlterTableOperation, a as AlterTableOptions, b as ColumnDefinition, C as CreateTableOptions, D as DropTableOptions, I as IndexDefinition, c as TableConstraint, T as TableDefinition } from '../schema-BDn8WfSL.cjs';
5
5
  export { a as DatabaseError, D as DatabaseErrorKind, b as DatabaseErrorOptions, c as createDatabaseError, i as isApplicationError, d as isDatabaseError } from '../error-BrdknH2s.cjs';
6
6
  import 'drizzle-orm';
@@ -130,7 +130,21 @@ interface BaseAdapterConfig {
130
130
  pool?: PoolConfig;
131
131
  /** Logger instance for queries and errors */
132
132
  logger?: AdapterLogger;
133
- /** Schema name (PostgreSQL) */
133
+ /**
134
+ * Schema name (PostgreSQL only).
135
+ *
136
+ * Applied as `search_path` in the pool's startup options, which is the
137
+ * pooled-safe way to set it: a `SET search_path` issued as a query belongs
138
+ * to whichever pooled connection happened to run it, so the next checkout
139
+ * would see the default again.
140
+ *
141
+ * The adapter creates the schema if it is missing, because `search_path`
142
+ * naming a schema that does not exist does not fail — it falls through, and
143
+ * the tables land somewhere else.
144
+ *
145
+ * Declared here since the first release and read by nothing until now, which
146
+ * is why setting it appeared to work and changed nothing.
147
+ */
134
148
  schema?: string;
135
149
  /** SSL/TLS configuration */
136
150
  ssl?: SslConfig | boolean;
@@ -1,6 +1,6 @@
1
1
  import { a as SqlParam } from '../core-CVO7WYDj.js';
2
2
  export { J as JsonArray, b as JsonObject, c as JsonValue, S as SupportedDialect, T as TableResolver } from '../core-CVO7WYDj.js';
3
- export { C as CountOptions, f as DatabaseCapabilities, D as DeleteOptions, I as InsertOptions, J as JoinSpec, a as Migration, c as MigrationOptions, M as MigrationRecord, d as MigrationResult, b as MigrationStatus, O as OrderBySpec, P as PoolStats, S as SelectOptions, T as TransactionContext, h as TransactionIsolationLevel, e as TransactionOptions, g as UpdateOptions, U as UpsertOptions, i as WHERE_OPERATORS, W as WhereClause, j as WhereCondition, k as WhereOperator } from '../migration-CgoxgWOL.js';
3
+ export { C as CountOptions, f as DatabaseCapabilities, D as DeleteOptions, I as InsertOptions, J as JoinSpec, a as Migration, c as MigrationOptions, M as MigrationRecord, d as MigrationResult, b as MigrationStatus, O as OrderBySpec, P as PoolStats, S as SelectOptions, T as TransactionContext, h as TransactionIsolationLevel, e as TransactionOptions, g as UpdateOptions, U as UpsertOptions, i as WHERE_OPERATORS, W as WhereClause, j as WhereCondition, k as WhereOperator } from '../migration-BqHebSwM.js';
4
4
  export { A as AlterTableOperation, a as AlterTableOptions, b as ColumnDefinition, C as CreateTableOptions, D as DropTableOptions, I as IndexDefinition, c as TableConstraint, T as TableDefinition } from '../schema-BIQ0YQZ_.js';
5
5
  export { a as DatabaseError, D as DatabaseErrorKind, b as DatabaseErrorOptions, c as createDatabaseError, i as isApplicationError, d as isDatabaseError } from '../error-BrdknH2s.js';
6
6
  import 'drizzle-orm';
@@ -130,7 +130,21 @@ interface BaseAdapterConfig {
130
130
  pool?: PoolConfig;
131
131
  /** Logger instance for queries and errors */
132
132
  logger?: AdapterLogger;
133
- /** Schema name (PostgreSQL) */
133
+ /**
134
+ * Schema name (PostgreSQL only).
135
+ *
136
+ * Applied as `search_path` in the pool's startup options, which is the
137
+ * pooled-safe way to set it: a `SET search_path` issued as a query belongs
138
+ * to whichever pooled connection happened to run it, so the next checkout
139
+ * would see the default again.
140
+ *
141
+ * The adapter creates the schema if it is missing, because `search_path`
142
+ * naming a schema that does not exist does not fail — it falls through, and
143
+ * the tables land somewhere else.
144
+ *
145
+ * Declared here since the first release and read by nothing until now, which
146
+ * is why setting it appeared to work and changed nothing.
147
+ */
134
148
  schema?: string;
135
149
  /** SSL/TLS configuration */
136
150
  ssl?: SslConfig | boolean;
@@ -21,6 +21,13 @@ var WHERE_OPERATORS = [
21
21
  // coerce, and there it searches the serialized text — which hits a key name as readily as a
22
22
  // value. Text columns only, and a search rather than a containment check.
23
23
  "CONTAINS",
24
+ // CONTAINS without regard to case: a substring match on a TEXT column with the value taken
25
+ // literally (`%` and `_` are characters to find, not wildcards), ignoring case on every
26
+ // dialect even where the column's collation is case-sensitive. Which letters fold is the
27
+ // database's `lower()` under the column's collation: the collation's Unicode version on
28
+ // MySQL; non-ASCII too under a linguistic PostgreSQL collation; ASCII letters only on
29
+ // SQLite and under PostgreSQL's `C` or `POSIX`.
30
+ "ICONTAINS",
24
31
  // Declared, never implemented — the builder throws `Unsupported operator: OVERLAPS`. Kept in
25
32
  // the union because removing it would be a breaking change to a published type; the refusal
26
33
  // is pinned by a test so implementing it has to come through here.