ts-prorm-orm 1.2.3 → 2.1.0

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 (204) hide show
  1. package/CHANGELOG.md +331 -1
  2. package/README.md +32 -24
  3. package/dist/compliance/data-classifier.d.ts +6 -0
  4. package/dist/compliance/data-classifier.js +6 -0
  5. package/dist/compliance/data-lineage.d.ts +4 -0
  6. package/dist/compliance/data-lineage.js +4 -0
  7. package/dist/compliance/data-masker.d.ts +4 -0
  8. package/dist/compliance/data-masker.js +4 -0
  9. package/dist/compliance/index.d.ts +4 -0
  10. package/dist/compliance/index.js +15 -1
  11. package/dist/compliance/pseudonymization.d.ts +4 -0
  12. package/dist/compliance/pseudonymization.js +4 -0
  13. package/dist/compliance/query-firewall.d.ts +9 -9
  14. package/dist/compliance/query-firewall.js +9 -9
  15. package/dist/compliance/rate-limiter.d.ts +4 -0
  16. package/dist/compliance/rate-limiter.js +4 -0
  17. package/dist/compliance/row-level-security.d.ts +2 -0
  18. package/dist/compliance/row-level-security.js +2 -0
  19. package/dist/compliance/security-decorator.d.ts +8 -0
  20. package/dist/compliance/security-decorator.js +8 -0
  21. package/dist/compliance/session-isolation.d.ts +4 -0
  22. package/dist/compliance/session-isolation.js +4 -0
  23. package/dist/compliance/worm-storage.d.ts +4 -0
  24. package/dist/compliance/worm-storage.js +4 -0
  25. package/dist/connection-manager.js +13 -1
  26. package/dist/core/expressions.d.ts +58 -0
  27. package/dist/core/expressions.js +83 -0
  28. package/dist/core/hooks-manager.d.ts +179 -0
  29. package/dist/core/hooks-manager.js +291 -0
  30. package/dist/core/types.d.ts +235 -0
  31. package/dist/core/types.js +9 -0
  32. package/dist/decorators/audit.d.ts +3 -1
  33. package/dist/decorators/audit.js +3 -1
  34. package/dist/decorators/check.d.ts +15 -15
  35. package/dist/decorators/check.js +15 -15
  36. package/dist/decorators/collate.d.ts +16 -0
  37. package/dist/decorators/collate.js +16 -0
  38. package/dist/decorators/comment.d.ts +3 -1
  39. package/dist/decorators/comment.js +3 -1
  40. package/dist/decorators/database-settings.d.ts +6 -0
  41. package/dist/decorators/database-settings.js +6 -0
  42. package/dist/decorators/default.d.ts +2 -0
  43. package/dist/decorators/default.js +2 -0
  44. package/dist/decorators/encryption.d.ts +7 -1
  45. package/dist/decorators/encryption.js +7 -1
  46. package/dist/decorators/engine.d.ts +4 -0
  47. package/dist/decorators/engine.js +4 -0
  48. package/dist/decorators/fk-constraints.d.ts +32 -32
  49. package/dist/decorators/fk-constraints.js +32 -32
  50. package/dist/decorators/foreign-table.d.ts +1 -1
  51. package/dist/decorators/generated.d.ts +8 -0
  52. package/dist/decorators/generated.js +8 -0
  53. package/dist/decorators/hstore.d.ts +6 -0
  54. package/dist/decorators/hstore.js +6 -0
  55. package/dist/decorators/index.d.ts +2 -0
  56. package/dist/decorators/index.js +11 -1
  57. package/dist/decorators/json-column.d.ts +2 -0
  58. package/dist/decorators/json-column.js +2 -0
  59. package/dist/decorators/jsonb.d.ts +6 -0
  60. package/dist/decorators/jsonb.js +6 -0
  61. package/dist/decorators/permissions.d.ts +12 -0
  62. package/dist/decorators/permissions.js +12 -0
  63. package/dist/decorators/procedure.d.ts +4 -2
  64. package/dist/decorators/procedure.js +4 -2
  65. package/dist/decorators/query-options.d.ts +24 -0
  66. package/dist/decorators/query-options.js +24 -0
  67. package/dist/decorators/range.d.ts +8 -0
  68. package/dist/decorators/range.js +8 -0
  69. package/dist/decorators/set-column.d.ts +2 -0
  70. package/dist/decorators/set-column.js +2 -0
  71. package/dist/decorators/spatial.d.ts +2 -0
  72. package/dist/decorators/spatial.js +2 -0
  73. package/dist/decorators/storage.d.ts +24 -0
  74. package/dist/decorators/storage.js +24 -0
  75. package/dist/decorators/timezone.d.ts +7 -7
  76. package/dist/decorators/timezone.js +7 -7
  77. package/dist/decorators/trigger.d.ts +3 -1
  78. package/dist/decorators/trigger.js +3 -1
  79. package/dist/decorators/uuid.d.ts +6 -0
  80. package/dist/decorators/uuid.js +6 -0
  81. package/dist/decorators/view.d.ts +7 -1
  82. package/dist/decorators/view.js +7 -1
  83. package/dist/diagrams/chen-diagram.d.ts +15 -12
  84. package/dist/diagrams/chen-diagram.js +76 -85
  85. package/dist/diagrams/class-diagram.d.ts +9 -8
  86. package/dist/diagrams/class-diagram.js +60 -82
  87. package/dist/diagrams/core/index.d.ts +13 -0
  88. package/dist/diagrams/core/index.js +33 -0
  89. package/dist/diagrams/core/layout.d.ts +104 -0
  90. package/dist/diagrams/core/layout.js +223 -0
  91. package/dist/diagrams/{svg-dom.d.ts → core/svg.d.ts} +8 -20
  92. package/dist/diagrams/{svg-dom.js → core/svg.js} +21 -29
  93. package/dist/diagrams/core/theme.d.ts +84 -0
  94. package/dist/diagrams/core/theme.js +62 -0
  95. package/dist/diagrams/dependency-diagram.d.ts +15 -14
  96. package/dist/diagrams/dependency-diagram.js +71 -105
  97. package/dist/diagrams/er-diagram.d.ts +13 -26
  98. package/dist/diagrams/er-diagram.js +180 -259
  99. package/dist/diagrams/flow-diagram.d.ts +16 -11
  100. package/dist/diagrams/flow-diagram.js +96 -91
  101. package/dist/diagrams/gantt-diagram.d.ts +10 -5
  102. package/dist/diagrams/gantt-diagram.js +77 -103
  103. package/dist/diagrams/index-diagram.d.ts +10 -10
  104. package/dist/diagrams/index-diagram.js +106 -116
  105. package/dist/diagrams/index.d.ts +6 -9
  106. package/dist/diagrams/index.js +9 -24
  107. package/dist/diagrams/migration-diagram.d.ts +8 -4
  108. package/dist/diagrams/migration-diagram.js +189 -161
  109. package/dist/diagrams/model-diagram.d.ts +34 -34
  110. package/dist/diagrams/model-diagram.js +106 -485
  111. package/dist/diagrams/package-diagram.d.ts +9 -6
  112. package/dist/diagrams/package-diagram.js +64 -101
  113. package/dist/diagrams/relational-diagram.d.ts +12 -10
  114. package/dist/diagrams/relational-diagram.js +87 -114
  115. package/dist/diagrams/schemadoc-diagram.d.ts +8 -8
  116. package/dist/diagrams/schemadoc-diagram.js +71 -93
  117. package/dist/diagrams/sequence-diagram.d.ts +10 -10
  118. package/dist/diagrams/sequence-diagram.js +64 -89
  119. package/dist/diagrams/state-diagram.d.ts +10 -9
  120. package/dist/diagrams/state-diagram.js +69 -92
  121. package/dist/diagrams/tree-diagram.d.ts +11 -5
  122. package/dist/diagrams/tree-diagram.js +41 -65
  123. package/dist/dialects/clickhouse/index.js +15 -0
  124. package/dist/dialects/cockroachdb/index.d.ts +1 -1
  125. package/dist/dialects/cockroachdb/index.js +32 -63
  126. package/dist/dialects/db2/index.js +23 -8
  127. package/dist/dialects/dialect.d.ts +141 -5
  128. package/dist/dialects/duckdb/index.js +9 -2
  129. package/dist/dialects/hana/index.js +22 -5
  130. package/dist/dialects/lock-clause-helper.d.ts +167 -0
  131. package/dist/dialects/lock-clause-helper.js +316 -0
  132. package/dist/dialects/mariadb/index.d.ts +7 -4
  133. package/dist/dialects/mariadb/index.js +36 -60
  134. package/dist/dialects/mssql/index.js +34 -3
  135. package/dist/dialects/mysql/index.d.ts +1 -1
  136. package/dist/dialects/mysql/index.js +17 -45
  137. package/dist/dialects/oracle/index.d.ts +14 -3
  138. package/dist/dialects/oracle/index.js +66 -36
  139. package/dist/dialects/order-expression-helper.d.ts +72 -0
  140. package/dist/dialects/order-expression-helper.js +154 -0
  141. package/dist/dialects/partial-index.d.ts +52 -0
  142. package/dist/dialects/partial-index.js +251 -0
  143. package/dist/dialects/postgres/index.d.ts +1 -1
  144. package/dist/dialects/postgres/index.js +43 -68
  145. package/dist/dialects/redshift/index.js +9 -2
  146. package/dist/dialects/snowflake/index.js +17 -0
  147. package/dist/dialects/spanner/index.js +7 -2
  148. package/dist/dialects/sqlite/driver.d.ts +55 -0
  149. package/dist/dialects/sqlite/driver.js +102 -0
  150. package/dist/dialects/sqlite/index.d.ts +1 -1
  151. package/dist/dialects/sqlite/index.js +49 -27
  152. package/dist/external-fields/decorator.d.ts +2 -0
  153. package/dist/external-fields/decorator.js +2 -0
  154. package/dist/graph/base-graph-dialect.d.ts +24 -3
  155. package/dist/graph/base-graph-dialect.js +43 -2
  156. package/dist/graph/dgraph/index.js +6 -0
  157. package/dist/graph/gremlin/index.d.ts +6 -0
  158. package/dist/graph/gremlin/index.js +12 -1
  159. package/dist/graph/index.d.ts +1 -1
  160. package/dist/graph/neo4j/index.d.ts +2 -0
  161. package/dist/graph/neo4j/index.js +6 -1
  162. package/dist/graph/types.d.ts +12 -1
  163. package/dist/index.d.ts +12 -3
  164. package/dist/index.js +53 -7
  165. package/dist/logging/index.d.ts +10 -0
  166. package/dist/logging/index.js +23 -0
  167. package/dist/logging/query-logging.d.ts +82 -0
  168. package/dist/logging/query-logging.js +102 -0
  169. package/dist/models/associations.d.ts +38 -0
  170. package/dist/models/associations.js +16 -0
  171. package/dist/models/decorators.d.ts +55 -19
  172. package/dist/models/decorators.js +95 -19
  173. package/dist/models/eager-load.d.ts +99 -0
  174. package/dist/models/eager-load.js +348 -5
  175. package/dist/models/indexes.d.ts +3 -2
  176. package/dist/models/indexes.js +7 -1
  177. package/dist/models/model.js +69 -43
  178. package/dist/prorm.d.ts +175 -409
  179. package/dist/prorm.js +1132 -553
  180. package/dist/query-builders/order-limit-builder.js +12 -10
  181. package/dist/query-builders/sql-compiler.d.ts +10 -3
  182. package/dist/query-builders/sql-compiler.js +14 -43
  183. package/dist/query-interface.d.ts +2 -1
  184. package/dist/schema-objects.d.ts +42 -0
  185. package/dist/schema-objects.js +28 -0
  186. package/dist/sql-constants.d.ts +44 -0
  187. package/dist/sql-constants.js +138 -1
  188. package/dist/types/index.d.ts +387 -17
  189. package/dist/types/index.js +10 -15
  190. package/dist/types/query-types.d.ts +26 -0
  191. package/dist/types/query-types.js +30 -0
  192. package/package.json +39 -8
  193. package/dist/decorators/belongs-to-many.js +0 -115
  194. package/dist/decorators/belongs-to.js +0 -115
  195. package/dist/decorators/has-many.js +0 -127
  196. package/dist/decorators/has-one.js +0 -116
  197. package/dist/diagrams/palette.d.ts +0 -138
  198. package/dist/diagrams/palette.js +0 -194
  199. package/dist/hooks/hooks-manager.d.ts +0 -189
  200. package/dist/hooks/hooks-manager.js +0 -350
  201. package/dist/hooks/index.d.ts +0 -8
  202. package/dist/hooks/index.js +0 -37
  203. /package/dist/{logging.d.ts → logging/logger.d.ts} +0 -0
  204. /package/dist/{logging.js → logging/logger.js} +0 -0
@@ -74,6 +74,7 @@ const prorm_1 = require("../../prorm");
74
74
  const index_1 = require("../../errors/index");
75
75
  const index_2 = require("../../utils/index");
76
76
  const operators_1 = require("../../operators");
77
+ const order_expression_helper_1 = require("../order-expression-helper");
77
78
  const DEFAULT_RETRY_OPTIONS = {
78
79
  max: 3,
79
80
  timeout: 1000,
@@ -1564,11 +1565,17 @@ class RedshiftDialect {
1564
1565
  return { sql: buildCondition(where), values };
1565
1566
  }
1566
1567
  buildOrderClause(order, _options) {
1567
- const orderArray = order;
1568
- if (!orderArray || !Array.isArray(orderArray) || orderArray.length === 0)
1568
+ const orderArray = (0, order_expression_helper_1.normalizeOrderItems)(order);
1569
+ if (orderArray.length === 0)
1569
1570
  return '';
1570
1571
  const orderParts = [];
1571
1572
  for (const item of orderArray) {
1573
+ // Order helpers: asc('name') / desc('name') / random()
1574
+ const orderExpr = (0, order_expression_helper_1.renderOrderExpressionItem)(this, item);
1575
+ if (orderExpr !== null) {
1576
+ orderParts.push(orderExpr);
1577
+ continue;
1578
+ }
1572
1579
  if (Array.isArray(item)) {
1573
1580
  const field = typeof item[0] === 'string' ? this.escapeId(item[0]) : item[0];
1574
1581
  const direction = item[1] ? ` ${item[1]}` : '';
@@ -46,6 +46,7 @@ function loadSnowflake() {
46
46
  const types_1 = require("../../types");
47
47
  const query_stream_helper_1 = require("../query-stream-helper");
48
48
  const prorm_1 = require("../../prorm");
49
+ const order_expression_helper_1 = require("../order-expression-helper");
49
50
  /**
50
51
  * Default retry options for connection/query errors
51
52
  */
@@ -1090,6 +1091,12 @@ class SnowflakeDialect {
1090
1091
  return '';
1091
1092
  const orderParts = [];
1092
1093
  const processOrder = (orderItem) => {
1094
+ // Order helpers: asc('name') / desc('name') / random()
1095
+ const orderExpr = (0, order_expression_helper_1.renderOrderExpressionItem)(this, orderItem);
1096
+ if (orderExpr !== null) {
1097
+ orderParts.push(orderExpr);
1098
+ return;
1099
+ }
1093
1100
  if (typeof orderItem === 'string') {
1094
1101
  const parts = orderItem.split(' ');
1095
1102
  if (parts.length === 1) {
@@ -1099,6 +1106,16 @@ class SnowflakeDialect {
1099
1106
  orderParts.push(`${this.escapeId(parts[0])} ${parts[1].toUpperCase()}`);
1100
1107
  }
1101
1108
  }
1109
+ else if (Array.isArray(orderItem)) {
1110
+ // Tuple form — `['name', 'DESC']` / `['name']`, the elements of the
1111
+ // primary documented `[['name', 'DESC'], ['id', 'ASC']]` shape. An
1112
+ // array is also an object, so without this branch each tuple fell
1113
+ // through to the map branch below and its *indices* were emitted as
1114
+ // column names (`ORDER BY "0" NAME, "1" DESC`).
1115
+ const [field, direction] = orderItem;
1116
+ const column = typeof field === 'string' ? this.escapeId(field) : String(field);
1117
+ orderParts.push(direction ? `${column} ${String(direction).toUpperCase()}` : column);
1118
+ }
1102
1119
  else if (typeof orderItem === 'object' && orderItem !== null) {
1103
1120
  for (const [key, value] of Object.entries(orderItem)) {
1104
1121
  if (key === '$raw') {
@@ -106,6 +106,7 @@ const { Spanner } = require('@google-cloud/spanner');
106
106
  const types_1 = require("../../types");
107
107
  const query_stream_helper_1 = require("../query-stream-helper");
108
108
  const prorm_1 = require("../../prorm");
109
+ const order_expression_helper_1 = require("../order-expression-helper");
109
110
  /**
110
111
  * A Spanner read-write transaction, bridging the driver's callback-based
111
112
  * `database.runTransaction()` API to the imperative
@@ -1490,10 +1491,14 @@ class SpannerDialect {
1490
1491
  return { sql, values };
1491
1492
  }
1492
1493
  buildOrderClause(order) {
1493
- const orderArray = order;
1494
- if (!orderArray || !Array.isArray(orderArray) || orderArray.length === 0)
1494
+ const orderArray = (0, order_expression_helper_1.normalizeOrderItems)(order);
1495
+ if (orderArray.length === 0)
1495
1496
  return '';
1496
1497
  const parts = orderArray.map((item) => {
1498
+ // Order helpers: asc('name') / desc('name') / random()
1499
+ const orderExpr = (0, order_expression_helper_1.renderOrderExpressionItem)(this, item);
1500
+ if (orderExpr !== null)
1501
+ return orderExpr;
1497
1502
  if (Array.isArray(item)) {
1498
1503
  const field = typeof item[0] === 'string' ? this.escapeId(item[0]) : item[0];
1499
1504
  const direction = item[1] ? ` ${item[1]}` : '';
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Runtime-appropriate SQLite driver.
3
+ *
4
+ * Node uses `better-sqlite3`, a native addon. Bun ships its own SQLite as the
5
+ * built-in `bun:sqlite`, which is faster there and needs no native build step —
6
+ * and under Bun the `better-sqlite3` addon may not be installable at all.
7
+ *
8
+ * The two APIs were designed to look alike, so the dialect can talk to either
9
+ * one unchanged. They differ in exactly one place: better-sqlite3 has
10
+ * `db.pragma()`, and bun:sqlite does not. This module adds it, so the dialect
11
+ * has a single shape to code against and no `if (isBun)` branches leak into the
12
+ * SQL layer.
13
+ *
14
+ * The driver is loaded lazily on first connect, so importing the ORM never
15
+ * dlopens a native binding or touches a `bun:` module on Node.
16
+ */
17
+ /** The slice of better-sqlite3's Statement the dialect relies on. */
18
+ export interface SqliteStatement {
19
+ all(...params: unknown[]): unknown[];
20
+ get(...params: unknown[]): unknown;
21
+ run(...params: unknown[]): {
22
+ changes: number | bigint;
23
+ lastInsertRowid: number | bigint;
24
+ };
25
+ iterate(...params: unknown[]): IterableIterator<unknown>;
26
+ }
27
+ /** The slice of better-sqlite3's Database the dialect relies on. */
28
+ export interface SqliteDatabase {
29
+ prepare(sql: string): SqliteStatement;
30
+ exec(sql: string): unknown;
31
+ pragma(source: string, options?: {
32
+ simple?: boolean;
33
+ }): unknown;
34
+ close(): void;
35
+ }
36
+ export interface SqliteDriverOptions {
37
+ readonly?: boolean;
38
+ fileMustExist?: boolean;
39
+ timeout?: number;
40
+ verbose?: ((message?: unknown, ...args: unknown[]) => void) | undefined;
41
+ }
42
+ /** True when running under Bun. */
43
+ export declare function isBun(): boolean;
44
+ type DatabaseCtor = new (filename: string, options?: SqliteDriverOptions) => SqliteDatabase;
45
+ /**
46
+ * Resolve the SQLite driver for the current runtime.
47
+ *
48
+ * Under Bun this prefers `bun:sqlite` but falls back to `better-sqlite3` if it
49
+ * is installed and the built-in cannot be loaded, so an existing Bun project
50
+ * that already depends on better-sqlite3 keeps working.
51
+ */
52
+ export declare function loadSqliteDriver(): DatabaseCtor;
53
+ /** Test seam: forget the resolved driver. */
54
+ export declare function resetSqliteDriver(): void;
55
+ export {};
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ /**
3
+ * Runtime-appropriate SQLite driver.
4
+ *
5
+ * Node uses `better-sqlite3`, a native addon. Bun ships its own SQLite as the
6
+ * built-in `bun:sqlite`, which is faster there and needs no native build step —
7
+ * and under Bun the `better-sqlite3` addon may not be installable at all.
8
+ *
9
+ * The two APIs were designed to look alike, so the dialect can talk to either
10
+ * one unchanged. They differ in exactly one place: better-sqlite3 has
11
+ * `db.pragma()`, and bun:sqlite does not. This module adds it, so the dialect
12
+ * has a single shape to code against and no `if (isBun)` branches leak into the
13
+ * SQL layer.
14
+ *
15
+ * The driver is loaded lazily on first connect, so importing the ORM never
16
+ * dlopens a native binding or touches a `bun:` module on Node.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.isBun = isBun;
20
+ exports.loadSqliteDriver = loadSqliteDriver;
21
+ exports.resetSqliteDriver = resetSqliteDriver;
22
+ /** True when running under Bun. */
23
+ function isBun() {
24
+ return typeof process !== 'undefined' && typeof process.versions?.bun === 'string';
25
+ }
26
+ /**
27
+ * Give a bun:sqlite Database the `pragma()` method better-sqlite3 has.
28
+ *
29
+ * better-sqlite3's contract: `pragma('foreign_keys = ON')` sets and returns the
30
+ * resulting rows; `pragma('user_version', { simple: true })` returns the first
31
+ * column of the first row. `PRAGMA name = value` returns no rows, so a `simple`
32
+ * read of an assignment yields undefined in both drivers.
33
+ */
34
+ function withPragma(db) {
35
+ const wrapped = db;
36
+ if (typeof db.pragma === 'function')
37
+ return wrapped;
38
+ wrapped.pragma = (source, options) => {
39
+ const rows = db.prepare(`PRAGMA ${source}`).all();
40
+ if (!options?.simple)
41
+ return rows;
42
+ const first = rows[0];
43
+ return first ? Object.values(first)[0] : undefined;
44
+ };
45
+ return wrapped;
46
+ }
47
+ let cached = null;
48
+ /**
49
+ * Resolve the SQLite driver for the current runtime.
50
+ *
51
+ * Under Bun this prefers `bun:sqlite` but falls back to `better-sqlite3` if it
52
+ * is installed and the built-in cannot be loaded, so an existing Bun project
53
+ * that already depends on better-sqlite3 keeps working.
54
+ */
55
+ function loadSqliteDriver() {
56
+ if (cached)
57
+ return cached;
58
+ const attempts = [];
59
+ if (isBun()) {
60
+ attempts.push({
61
+ name: 'bun:sqlite',
62
+ load: () => {
63
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
64
+ const { Database } = require('bun:sqlite');
65
+ // bun:sqlite ignores better-sqlite3's `verbose`/`timeout`; pass through
66
+ // only what it understands so an unknown option can't throw.
67
+ return class BunDatabase {
68
+ constructor(filename, options) {
69
+ return withPragma(new Database(filename, {
70
+ readonly: options?.readonly ?? false,
71
+ create: !(options?.fileMustExist ?? false),
72
+ }));
73
+ }
74
+ };
75
+ },
76
+ });
77
+ }
78
+ attempts.push({
79
+ name: 'better-sqlite3',
80
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
81
+ load: () => require('better-sqlite3'),
82
+ });
83
+ const failures = [];
84
+ for (const attempt of attempts) {
85
+ try {
86
+ cached = attempt.load();
87
+ return cached;
88
+ }
89
+ catch (err) {
90
+ failures.push(`${attempt.name}: ${err instanceof Error ? err.message : String(err)}`);
91
+ }
92
+ }
93
+ throw new Error('No SQLite driver could be loaded for the SQLite dialect. Tried ' +
94
+ attempts.map((a) => a.name).join(', ') +
95
+ '. On Node install better-sqlite3 (`npm install better-sqlite3`); on Bun the built-in ' +
96
+ '`bun:sqlite` is used and needs no install. Underlying errors — ' +
97
+ failures.join(' | '));
98
+ }
99
+ /** Test seam: forget the resolved driver. */
100
+ function resetSqliteDriver() {
101
+ cached = null;
102
+ }
@@ -768,7 +768,7 @@ export declare class SQLiteDialect implements Dialect {
768
768
  type?: string;
769
769
  using?: string;
770
770
  fields: string[];
771
- where?: WhereOptions;
771
+ where?: WhereOptions | string;
772
772
  expression?: string;
773
773
  }): Promise<void>;
774
774
  /**
@@ -6,27 +6,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.SQLiteTransaction = exports.SQLiteDialect = void 0;
7
7
  exports.createSQLiteDialect = createSQLiteDialect;
8
8
  const operators_1 = require("../../operators");
9
- // Lazily-loaded `better-sqlite3` driver. This native addon is only loaded the
10
- // first time a connection is opened, so importing this ORM never dlopens the
11
- // better-sqlite3 native binding.
12
- let betterSqlite3Ctor = null;
13
- function loadBetterSqlite3() {
14
- if (!betterSqlite3Ctor) {
15
- try {
16
- betterSqlite3Ctor = require('better-sqlite3');
17
- }
18
- catch (err) {
19
- throw new Error("The 'better-sqlite3' package is required to use the SQLite dialect but could not be loaded. " +
20
- 'Install it with `npm install better-sqlite3`. Original error: ' +
21
- (err instanceof Error ? err.message : String(err)));
22
- }
23
- }
24
- return betterSqlite3Ctor;
25
- }
9
+ const partial_index_1 = require("../partial-index");
10
+ // The SQLite driver is resolved per runtime and loaded lazily on first connect:
11
+ // `better-sqlite3` on Node, the built-in `bun:sqlite` on Bun. See
12
+ // ./driver.ts importing this ORM never dlopens a native binding, and no
13
+ // runtime branch leaks past that module.
14
+ const driver_1 = require("./driver");
26
15
  const stream_1 = require("stream");
27
16
  const prorm_1 = require("../../prorm");
28
17
  const operators_2 = require("../../operators");
29
18
  const sqlite_advanced_1 = require("../../sqlite-advanced");
19
+ const order_expression_helper_1 = require("../order-expression-helper");
30
20
  /**
31
21
  * SQLite dialect class that implements the Dialect interface
32
22
  */
@@ -54,7 +44,7 @@ class SQLiteDialect {
54
44
  timeout: this.config.timeout || 5000,
55
45
  verbose: this.config.verbose || undefined,
56
46
  };
57
- this.connection = new (loadBetterSqlite3())(this.config.storage, options);
47
+ this.connection = new ((0, driver_1.loadSqliteDriver)())(this.config.storage, options);
58
48
  this._isConnected = true;
59
49
  // Enable foreign keys by default
60
50
  this.connection.pragma('foreign_keys = ON');
@@ -160,8 +150,15 @@ class SQLiteDialect {
160
150
  }
161
151
  const sqlUpper = sql.trim().toUpperCase();
162
152
  // EXPLAIN / EXPLAIN QUERY PLAN and WITH (CTE) statements also return rows.
153
+ //
154
+ // `PRAGMA name` is a query and returns a row; `PRAGMA name = value` is an
155
+ // assignment and returns nothing, and better-sqlite3 throws "This
156
+ // statement does not return data. Use run() instead" if you call .all()
157
+ // on it. Every PRAGMA was treated as a reader, so the assignment form -
158
+ // which is how disableForeignKeyChecks(), enableForeignKeyChecks() and
159
+ // setIsolationLevel() are implemented on SQLite - failed on every call.
163
160
  const isSelect = sqlUpper.startsWith('SELECT') ||
164
- sqlUpper.startsWith('PRAGMA') ||
161
+ (sqlUpper.startsWith('PRAGMA') && !sqlUpper.includes('=')) ||
165
162
  sqlUpper.startsWith('EXPLAIN') ||
166
163
  sqlUpper.startsWith('WITH');
167
164
  const stmt = this.connection.prepare(sql);
@@ -706,6 +703,16 @@ class SQLiteDialect {
706
703
  if (options?.initialAutoIncrement) {
707
704
  console.warn(`SQLite: initialAutoIncrement option is not supported in CREATE TABLE`);
708
705
  }
706
+ // Create the unique keys collected above.
707
+ //
708
+ // SQLite has no `ALTER TABLE ... ADD CONSTRAINT`, so a unique key that is
709
+ // not part of the CREATE TABLE text has to become a `CREATE UNIQUE INDEX`
710
+ // instead - which enforces exactly the same rule. This list was built and
711
+ // then never used, so `createTable(..., { uniqueKeys })` produced no SQL at
712
+ // all and the constraint the caller declared was never enforced.
713
+ for (const uk of uniqueKeysToCreate) {
714
+ await this.addIndex(tableName, uk.name, uk.fields, { unique: true });
715
+ }
709
716
  // Create indexes after table creation
710
717
  if (options?.indexes) {
711
718
  for (const index of options.indexes) {
@@ -1849,10 +1856,16 @@ class SQLiteDialect {
1849
1856
  else {
1850
1857
  sql += ` (${fields.map((f) => this.escapeId(f)).join(', ')})`;
1851
1858
  }
1852
- // Add partial index WHERE clause (SQLite 3.8.0+)
1859
+ // Add partial index WHERE clause (SQLite 3.8.0+). The ordinary WHERE
1860
+ // builder is deliberately not used here: it emits bound placeholders, and
1861
+ // this DDL is executed without a value list, so SQLite rejected it with
1862
+ // "parameters prohibited in partial index WHERE clauses". The predicate is
1863
+ // compiled with its values inlined as escaped literals instead.
1853
1864
  if (options?.where) {
1854
- const whereClause = this.buildWhereClause(options.where);
1855
- sql += ` WHERE ${whereClause.sql}`;
1865
+ const predicate = (0, partial_index_1.buildPartialIndexPredicate)(options.where, this.name, this);
1866
+ if (predicate) {
1867
+ sql += ` WHERE ${predicate}`;
1868
+ }
1856
1869
  }
1857
1870
  await this.query(sql);
1858
1871
  }
@@ -1892,9 +1905,12 @@ class SQLiteDialect {
1892
1905
  if (indexDef.using) {
1893
1906
  sql += ` USING ${indexDef.using}`;
1894
1907
  }
1895
- if (indexDef.where && Object.keys(indexDef.where).length > 0) {
1896
- const whereClause = this.buildWhereClause(indexDef.where);
1897
- sql += ` WHERE ${whereClause.sql}`;
1908
+ // Partial index predicate - inlined literals, not placeholders. See addIndex.
1909
+ if (indexDef.where) {
1910
+ const predicate = (0, partial_index_1.buildPartialIndexPredicate)(indexDef.where, this.name, this);
1911
+ if (predicate) {
1912
+ sql += ` WHERE ${predicate}`;
1913
+ }
1898
1914
  }
1899
1915
  await this.query(sql);
1900
1916
  }
@@ -2352,12 +2368,18 @@ class SQLiteDialect {
2352
2368
  * Build an ORDER BY clause
2353
2369
  */
2354
2370
  buildOrderClause(order, options) {
2355
- const orderArray = order;
2356
- if (!orderArray || !Array.isArray(orderArray) || orderArray.length === 0) {
2371
+ const orderArray = (0, order_expression_helper_1.normalizeOrderItems)(order);
2372
+ if (orderArray.length === 0) {
2357
2373
  return '';
2358
2374
  }
2359
2375
  const orderParts = [];
2360
2376
  for (const item of orderArray) {
2377
+ // Order helpers: asc('name') / desc('name') / random()
2378
+ const orderExpr = (0, order_expression_helper_1.renderOrderExpressionItem)(this, item);
2379
+ if (orderExpr !== null) {
2380
+ orderParts.push(orderExpr);
2381
+ continue;
2382
+ }
2361
2383
  if (Array.isArray(item)) {
2362
2384
  const field = typeof item[0] === 'string' ? this.escapeId(item[0]) : item[0];
2363
2385
  const direction = item[1] ? ` ${item[1]}` : '';
@@ -9,6 +9,7 @@
9
9
  *
10
10
  * prorm.registerStore('assets', s3Store, { defaultBucket: 'avatars' });
11
11
  *
12
+ * ```ts
12
13
  * @Table()
13
14
  * class User extends Model {
14
15
  * @Column(DataTypes.STRING) declare name: string;
@@ -21,6 +22,7 @@
21
22
  * await user.loadAvatar(); // GET, populates user.avatar
22
23
  * user.avatar = newBytes;
23
24
  * await user.save(); // PUT, then persists the key column
25
+ * ```
24
26
  *
25
27
  * The key column (`avatarKey` by default) is registered automatically, so it
26
28
  * does not need its own `@Column`.
@@ -10,6 +10,7 @@
10
10
  *
11
11
  * prorm.registerStore('assets', s3Store, { defaultBucket: 'avatars' });
12
12
  *
13
+ * ```ts
13
14
  * @Table()
14
15
  * class User extends Model {
15
16
  * @Column(DataTypes.STRING) declare name: string;
@@ -22,6 +23,7 @@
22
23
  * await user.loadAvatar(); // GET, populates user.avatar
23
24
  * user.avatar = newBytes;
24
25
  * await user.save(); // PUT, then persists the key column
26
+ * ```
25
27
  *
26
28
  * The key column (`avatarKey` by default) is registered automatically, so it
27
29
  * does not need its own `@Column`.
@@ -25,7 +25,7 @@
25
25
  import { Readable } from 'stream';
26
26
  import { BaseDialect, type ColumnDefinition, type ConstraintDefinition, type DropConstraintOptions, type DropIndexOptions, type DropSchemaOptions, type DropTableOptions, type DropViewOptions, type IndexDefinition, type IndexOptions, type InsertOptions, type TableDescription, type TableOptions, type UpdateOptions, type DeleteOptions, type SelectOptions, type UpsertQueryOptions, type ViewOptions, type BuildOptions } from '../dialects/dialect';
27
27
  import type { DataType, Order, QueryOptions, QueryResult, StreamOptions, Transaction, TransactionOptions, WhereOptions, MaterializedViewOptions, RefreshOptions, DropMaterializedViewOptions, StoredProcedureOptions, DropStoredProcedureOptions, ExecuteStoredProcedureOptions, TriggerOptions, DropTriggerOptions, SequenceOptions, DropSequenceOptions, PolicyOptions, DropPolicyOptions, CreatePartitionOptions, AttachPartitionOptions, DetachPartitionOptions } from '../types';
28
- import { ParamBag, type GraphConnectionOptions, type GraphPredicate, type GraphStatement, type GraphTraversalSpec, type GraphTraversalStep, type NodeMatchSpec, type NodeModelDefinition, type EdgeModelDefinition } from './types';
28
+ import { ParamBag, type GraphConnectionOptions, type GraphPredicate, type GraphStatement, type GraphTraversalSpec, type GraphTraversalStep, type GraphOrderTerm, type NodeMatchSpec, type NodeModelDefinition, type EdgeModelDefinition } from './types';
29
29
  /** Context passed to {@link BaseGraphDialect.renderPredicate}. */
30
30
  export interface WhereRenderContext {
31
31
  /** Variable the predicate's properties are addressed through (e.g. `n`). */
@@ -110,8 +110,29 @@ export declare abstract class BaseGraphDialect extends BaseDialect {
110
110
  protected run(stmt: GraphStatement, options?: QueryOptions): Promise<QueryResult>;
111
111
  /** Positional param array for the SQL-shaped `{ sql, values }` contract. */
112
112
  protected paramValues(stmt: GraphStatement): unknown[];
113
- /** Tolerant `Order` -> `[field, dir][]` normalizer. */
114
- protected normalizeOrder(order?: Order): Array<[string, 'ASC' | 'DESC']>;
113
+ /**
114
+ * The engine-native term that shuffles results, or `null` when this graph
115
+ * engine has no random ordering at all.
116
+ *
117
+ * Cypher has `rand()` and Gremlin has `order().by(shuffle)`; Dgraph DQL's
118
+ * `orderasc`/`orderdesc` only take a predicate, so it keeps the `null`
119
+ * default and {@link requireRandomOrderTerm} raises the typed capability
120
+ * error instead of emitting something that would silently not shuffle.
121
+ */
122
+ protected randomOrderTerm(): string | null;
123
+ /** {@link randomOrderTerm}, raising `GraphCapabilityError` when unsupported. */
124
+ protected requireRandomOrderTerm(): string;
125
+ /**
126
+ * Tolerant `Order` -> `[field, dir][]` normalizer.
127
+ *
128
+ * Also understands the `asc()` / `desc()` / `random()` order helpers from
129
+ * `src/operators.ts`. They arrive as plain `OrderExpression` objects, so
130
+ * without an explicit branch they fell through the `$col`/`column` check
131
+ * below and were dropped silently — the helpers simply did nothing on
132
+ * every graph dialect. `random()` becomes a `'RANDOM'` term with no field,
133
+ * which each `compile*` translates (or refuses) in its own language.
134
+ */
135
+ protected normalizeOrder(order?: Order): GraphOrderTerm[];
115
136
  /** Map ORM `include` entries into graph traversal steps. */
116
137
  protected mapIncludes(include?: any[]): GraphTraversalStep[];
117
138
  buildWhereClause(where: WhereOptions, _options?: BuildOptions): {
@@ -28,6 +28,7 @@ exports.BaseGraphDialect = void 0;
28
28
  const stream_1 = require("stream");
29
29
  const dialect_1 = require("../dialects/dialect");
30
30
  const types_1 = require("./types");
31
+ const operators_1 = require("../operators");
31
32
  class BaseGraphDialect extends dialect_1.BaseDialect {
32
33
  constructor(options = {}) {
33
34
  super();
@@ -101,7 +102,36 @@ class BaseGraphDialect extends dialect_1.BaseDialect {
101
102
  paramValues(stmt) {
102
103
  return Object.values(stmt.params);
103
104
  }
104
- /** Tolerant `Order` -> `[field, dir][]` normalizer. */
105
+ /**
106
+ * The engine-native term that shuffles results, or `null` when this graph
107
+ * engine has no random ordering at all.
108
+ *
109
+ * Cypher has `rand()` and Gremlin has `order().by(shuffle)`; Dgraph DQL's
110
+ * `orderasc`/`orderdesc` only take a predicate, so it keeps the `null`
111
+ * default and {@link requireRandomOrderTerm} raises the typed capability
112
+ * error instead of emitting something that would silently not shuffle.
113
+ */
114
+ randomOrderTerm() {
115
+ return null;
116
+ }
117
+ /** {@link randomOrderTerm}, raising `GraphCapabilityError` when unsupported. */
118
+ requireRandomOrderTerm() {
119
+ const term = this.randomOrderTerm();
120
+ if (term === null) {
121
+ throw new types_1.GraphCapabilityError('random ordering', this.name);
122
+ }
123
+ return term;
124
+ }
125
+ /**
126
+ * Tolerant `Order` -> `[field, dir][]` normalizer.
127
+ *
128
+ * Also understands the `asc()` / `desc()` / `random()` order helpers from
129
+ * `src/operators.ts`. They arrive as plain `OrderExpression` objects, so
130
+ * without an explicit branch they fell through the `$col`/`column` check
131
+ * below and were dropped silently — the helpers simply did nothing on
132
+ * every graph dialect. `random()` becomes a `'RANDOM'` term with no field,
133
+ * which each `compile*` translates (or refuses) in its own language.
134
+ */
105
135
  normalizeOrder(order) {
106
136
  if (!order)
107
137
  return [];
@@ -111,6 +141,15 @@ class BaseGraphDialect extends dialect_1.BaseDialect {
111
141
  if (typeof item === 'string') {
112
142
  out.push([item, 'ASC']);
113
143
  }
144
+ else if ((0, operators_1.isOrderExpression)(item)) {
145
+ const dir = String(item.direction || 'ASC').toUpperCase();
146
+ if (dir === 'RANDOM') {
147
+ out.push(['', 'RANDOM']);
148
+ }
149
+ else {
150
+ out.push([item.field, dir === 'DESC' ? 'DESC' : 'ASC']);
151
+ }
152
+ }
114
153
  else if (Array.isArray(item)) {
115
154
  const rawField = item[0];
116
155
  const field = String(rawField && rawField.$col ? rawField.$col : rawField);
@@ -159,7 +198,9 @@ class BaseGraphDialect extends dialect_1.BaseDialect {
159
198
  }
160
199
  buildOrderClause(order, _options) {
161
200
  return this.normalizeOrder(order)
162
- .map(([field, dir]) => `${this.defaultNodeVar}.${(0, types_1.safeIdent)(field)} ${dir}`)
201
+ .map(([field, dir]) => dir === 'RANDOM'
202
+ ? this.requireRandomOrderTerm()
203
+ : `${this.defaultNodeVar}.${(0, types_1.safeIdent)(field)} ${dir}`)
163
204
  .join(', ');
164
205
  }
165
206
  buildLimitOffset(limit, offset) {
@@ -404,6 +404,12 @@ class DgraphGraphDialect extends base_graph_dialect_1.BaseGraphDialect {
404
404
  const filter = this.renderDql((0, types_2.normalizeWhere)(spec.where), params);
405
405
  const funcArgs = [`func: type(${label})`];
406
406
  const order = spec.order || [];
407
+ // DQL's `orderasc`/`orderdesc` only take a predicate name — Dgraph has no
408
+ // random ordering at all, so `random()` raises the typed capability error
409
+ // instead of quietly ordering by whatever else was asked for.
410
+ if (order.some(([, d]) => d === 'RANDOM')) {
411
+ this.requireRandomOrderTerm();
412
+ }
407
413
  if (order.length) {
408
414
  const [f, d] = order[0];
409
415
  funcArgs.push(`${d === 'DESC' ? 'orderdesc' : 'orderasc'}: ${(0, types_2.safeIdent)(f)}`);
@@ -28,6 +28,12 @@ export declare class GremlinGraphDialect extends BaseGraphDialect {
28
28
  readonly library = "gremlin";
29
29
  private client;
30
30
  constructor(options?: GraphConnectionOptions);
31
+ /**
32
+ * TinkerPop shuffles with `order().by(shuffle)` — `shuffle` is a
33
+ * comparator token, not a property name, so it is emitted as a bare
34
+ * `.by(shuffle)` step (never quoted like a property key).
35
+ */
36
+ protected randomOrderTerm(): string;
31
37
  protected get defaultNodeVar(): string;
32
38
  connect(): Promise<void>;
33
39
  disconnect(): Promise<void>;
@@ -36,6 +36,14 @@ class GremlinGraphDialect extends base_graph_dialect_1.BaseGraphDialect {
36
36
  this.client = null;
37
37
  this.dialectName = 'gremlin';
38
38
  }
39
+ /**
40
+ * TinkerPop shuffles with `order().by(shuffle)` — `shuffle` is a
41
+ * comparator token, not a property name, so it is emitted as a bare
42
+ * `.by(shuffle)` step (never quoted like a property key).
43
+ */
44
+ randomOrderTerm() {
45
+ return 'shuffle';
46
+ }
39
47
  get defaultNodeVar() {
40
48
  return 'it';
41
49
  }
@@ -220,7 +228,10 @@ class GremlinGraphDialect extends base_graph_dialect_1.BaseGraphDialect {
220
228
  if (order.length) {
221
229
  text += '.order()';
222
230
  for (const [f, d] of order) {
223
- text += `.by(${gremlinStr(f)}, ${d === 'DESC' ? 'desc' : 'asc'})`;
231
+ text +=
232
+ d === 'RANDOM'
233
+ ? `.by(${this.requireRandomOrderTerm()})`
234
+ : `.by(${gremlinStr(f)}, ${d === 'DESC' ? 'desc' : 'asc'})`;
224
235
  }
225
236
  }
226
237
  const offset = spec.offset !== undefined && spec.offset !== null ? Number(spec.offset) : 0;
@@ -28,7 +28,7 @@ export { Neo4jGraphDialect } from './neo4j';
28
28
  export { GremlinGraphDialect } from './gremlin';
29
29
  export { DgraphGraphDialect } from './dgraph';
30
30
  export { GraphCapabilityError, ParamBag, normalizeWhere, deriveAssociationEdge, defaultEdgeLabel, safeIdent, } from './types';
31
- export type { GraphConnectionOptions, GraphStatement, GraphPredicate, CanonOp, GraphAssociationType, GraphAssociationSpec, GraphPropertyDefinition, NodeModelDefinition, EdgeModelDefinition, GraphTraversalDirection, GraphTraversalStep, GraphTraversalSpec, NodeMatchSpec, } from './types';
31
+ export type { GraphConnectionOptions, GraphStatement, GraphPredicate, CanonOp, GraphAssociationType, GraphAssociationSpec, GraphPropertyDefinition, NodeModelDefinition, EdgeModelDefinition, GraphTraversalDirection, GraphTraversalStep, GraphTraversalSpec, GraphOrderDirection, GraphOrderTerm, NodeMatchSpec, } from './types';
32
32
  /** The graph dialects keyed by the name they should register under. */
33
33
  export declare const GRAPH_DIALECTS: {
34
34
  readonly neo4j: typeof Neo4jGraphDialect;
@@ -22,6 +22,8 @@ export declare class Neo4jGraphDialect extends BaseGraphDialect {
22
22
  private readonly txns;
23
23
  constructor(options?: GraphConnectionOptions);
24
24
  protected get defaultNodeVar(): string;
25
+ /** Cypher shuffles with the built-in `rand()` function. */
26
+ protected randomOrderTerm(): string;
25
27
  connect(): Promise<void>;
26
28
  disconnect(): Promise<void>;
27
29
  private requireDriver;
@@ -44,6 +44,10 @@ class Neo4jGraphDialect extends base_graph_dialect_1.BaseGraphDialect {
44
44
  get defaultNodeVar() {
45
45
  return 'n';
46
46
  }
47
+ /** Cypher shuffles with the built-in `rand()` function. */
48
+ randomOrderTerm() {
49
+ return 'rand()';
50
+ }
47
51
  // -------------------------------------------------------------------
48
52
  // Connection lifecycle
49
53
  // -------------------------------------------------------------------
@@ -293,7 +297,8 @@ class Neo4jGraphDialect extends base_graph_dialect_1.BaseGraphDialect {
293
297
  text += `\nRETURN ${distinct}${projection}${includeReturns.length ? ', ' + includeReturns.join(', ') : ''}`;
294
298
  const order = spec.order || [];
295
299
  if (order.length) {
296
- text += `\nORDER BY ${order.map(([f, d]) => `${v}.${(0, types_2.safeIdent)(f)} ${d}`).join(', ')}`;
300
+ const terms = order.map(([f, d]) => d === 'RANDOM' ? this.requireRandomOrderTerm() : `${v}.${(0, types_2.safeIdent)(f)} ${d}`);
301
+ text += `\nORDER BY ${terms.join(', ')}`;
297
302
  }
298
303
  if (spec.offset !== undefined && spec.offset !== null && String(spec.offset) !== '') {
299
304
  text += `\nSKIP ${Number(spec.offset)}`;