ts-prorm-orm 1.2.2 → 2.0.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 (129) hide show
  1. package/CHANGELOG.md +209 -0
  2. package/README.md +32 -24
  3. package/dist/compliance/index.d.ts +2 -0
  4. package/dist/compliance/index.js +13 -1
  5. package/dist/connection-manager.js +13 -1
  6. package/dist/core/expressions.d.ts +58 -0
  7. package/dist/core/expressions.js +83 -0
  8. package/dist/core/hooks-manager.d.ts +179 -0
  9. package/dist/core/hooks-manager.js +291 -0
  10. package/dist/core/types.d.ts +235 -0
  11. package/dist/core/types.js +9 -0
  12. package/dist/decorators/index.d.ts +2 -0
  13. package/dist/decorators/index.js +11 -1
  14. package/dist/diagrams/chen-diagram.d.ts +15 -12
  15. package/dist/diagrams/chen-diagram.js +76 -85
  16. package/dist/diagrams/class-diagram.d.ts +9 -8
  17. package/dist/diagrams/class-diagram.js +60 -82
  18. package/dist/diagrams/core/index.d.ts +13 -0
  19. package/dist/diagrams/core/index.js +33 -0
  20. package/dist/diagrams/core/layout.d.ts +104 -0
  21. package/dist/diagrams/core/layout.js +223 -0
  22. package/dist/diagrams/{svg-dom.d.ts → core/svg.d.ts} +8 -20
  23. package/dist/diagrams/{svg-dom.js → core/svg.js} +21 -29
  24. package/dist/diagrams/core/theme.d.ts +84 -0
  25. package/dist/diagrams/core/theme.js +62 -0
  26. package/dist/diagrams/dependency-diagram.d.ts +15 -14
  27. package/dist/diagrams/dependency-diagram.js +71 -105
  28. package/dist/diagrams/er-diagram.d.ts +13 -26
  29. package/dist/diagrams/er-diagram.js +180 -259
  30. package/dist/diagrams/flow-diagram.d.ts +16 -11
  31. package/dist/diagrams/flow-diagram.js +96 -91
  32. package/dist/diagrams/gantt-diagram.d.ts +10 -5
  33. package/dist/diagrams/gantt-diagram.js +77 -103
  34. package/dist/diagrams/index-diagram.d.ts +10 -10
  35. package/dist/diagrams/index-diagram.js +106 -116
  36. package/dist/diagrams/index.d.ts +6 -9
  37. package/dist/diagrams/index.js +9 -24
  38. package/dist/diagrams/migration-diagram.d.ts +8 -4
  39. package/dist/diagrams/migration-diagram.js +189 -161
  40. package/dist/diagrams/model-diagram.d.ts +34 -34
  41. package/dist/diagrams/model-diagram.js +106 -485
  42. package/dist/diagrams/package-diagram.d.ts +9 -6
  43. package/dist/diagrams/package-diagram.js +64 -101
  44. package/dist/diagrams/relational-diagram.d.ts +12 -10
  45. package/dist/diagrams/relational-diagram.js +87 -114
  46. package/dist/diagrams/schemadoc-diagram.d.ts +8 -8
  47. package/dist/diagrams/schemadoc-diagram.js +71 -93
  48. package/dist/diagrams/sequence-diagram.d.ts +10 -10
  49. package/dist/diagrams/sequence-diagram.js +64 -89
  50. package/dist/diagrams/state-diagram.d.ts +10 -9
  51. package/dist/diagrams/state-diagram.js +69 -92
  52. package/dist/diagrams/tree-diagram.d.ts +11 -5
  53. package/dist/diagrams/tree-diagram.js +41 -65
  54. package/dist/dialects/clickhouse/index.js +15 -0
  55. package/dist/dialects/cockroachdb/index.d.ts +1 -1
  56. package/dist/dialects/cockroachdb/index.js +32 -63
  57. package/dist/dialects/db2/index.js +23 -8
  58. package/dist/dialects/dialect.d.ts +29 -5
  59. package/dist/dialects/duckdb/index.js +9 -2
  60. package/dist/dialects/hana/index.js +22 -5
  61. package/dist/dialects/lock-clause-helper.d.ts +167 -0
  62. package/dist/dialects/lock-clause-helper.js +316 -0
  63. package/dist/dialects/mariadb/index.d.ts +7 -4
  64. package/dist/dialects/mariadb/index.js +36 -60
  65. package/dist/dialects/mssql/index.js +34 -3
  66. package/dist/dialects/mysql/index.d.ts +1 -1
  67. package/dist/dialects/mysql/index.js +17 -45
  68. package/dist/dialects/oracle/index.d.ts +14 -3
  69. package/dist/dialects/oracle/index.js +66 -36
  70. package/dist/dialects/order-expression-helper.d.ts +72 -0
  71. package/dist/dialects/order-expression-helper.js +154 -0
  72. package/dist/dialects/partial-index.d.ts +52 -0
  73. package/dist/dialects/partial-index.js +251 -0
  74. package/dist/dialects/postgres/index.d.ts +1 -1
  75. package/dist/dialects/postgres/index.js +43 -68
  76. package/dist/dialects/redshift/index.js +9 -2
  77. package/dist/dialects/snowflake/index.js +17 -0
  78. package/dist/dialects/spanner/index.js +7 -2
  79. package/dist/dialects/sqlite/driver.d.ts +55 -0
  80. package/dist/dialects/sqlite/driver.js +102 -0
  81. package/dist/dialects/sqlite/index.d.ts +1 -1
  82. package/dist/dialects/sqlite/index.js +49 -27
  83. package/dist/graph/base-graph-dialect.d.ts +24 -3
  84. package/dist/graph/base-graph-dialect.js +43 -2
  85. package/dist/graph/dgraph/index.js +6 -0
  86. package/dist/graph/gremlin/index.d.ts +6 -0
  87. package/dist/graph/gremlin/index.js +12 -1
  88. package/dist/graph/index.d.ts +1 -1
  89. package/dist/graph/neo4j/index.d.ts +2 -0
  90. package/dist/graph/neo4j/index.js +6 -1
  91. package/dist/graph/types.d.ts +12 -1
  92. package/dist/index.d.ts +13 -4
  93. package/dist/index.js +54 -7
  94. package/dist/logging/index.d.ts +10 -0
  95. package/dist/logging/index.js +23 -0
  96. package/dist/logging/query-logging.d.ts +82 -0
  97. package/dist/logging/query-logging.js +102 -0
  98. package/dist/models/decorators.d.ts +39 -3
  99. package/dist/models/decorators.js +74 -0
  100. package/dist/models/eager-load.d.ts +99 -0
  101. package/dist/models/eager-load.js +348 -5
  102. package/dist/models/indexes.d.ts +3 -2
  103. package/dist/models/indexes.js +7 -1
  104. package/dist/models/model.js +69 -43
  105. package/dist/prorm.d.ts +175 -409
  106. package/dist/prorm.js +1142 -557
  107. package/dist/query-builders/order-limit-builder.js +12 -10
  108. package/dist/query-builders/sql-compiler.d.ts +10 -3
  109. package/dist/query-builders/sql-compiler.js +14 -43
  110. package/dist/query-interface.d.ts +2 -1
  111. package/dist/sql-constants.d.ts +44 -0
  112. package/dist/sql-constants.js +138 -1
  113. package/dist/types/index.d.ts +53 -17
  114. package/dist/types/index.js +10 -15
  115. package/dist/types/query-types.d.ts +26 -0
  116. package/dist/types/query-types.js +30 -0
  117. package/package.json +32 -5
  118. package/dist/decorators/belongs-to-many.js +0 -115
  119. package/dist/decorators/belongs-to.js +0 -115
  120. package/dist/decorators/has-many.js +0 -127
  121. package/dist/decorators/has-one.js +0 -116
  122. package/dist/diagrams/palette.d.ts +0 -138
  123. package/dist/diagrams/palette.js +0 -194
  124. package/dist/hooks/hooks-manager.d.ts +0 -189
  125. package/dist/hooks/hooks-manager.js +0 -350
  126. package/dist/hooks/index.d.ts +0 -8
  127. package/dist/hooks/index.js +0 -37
  128. /package/dist/{logging.d.ts → logging/logger.d.ts} +0 -0
  129. /package/dist/{logging.js → logging/logger.js} +0 -0
@@ -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]}` : '';
@@ -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)}`;
@@ -142,6 +142,17 @@ export interface GraphTraversalSpec {
142
142
  targetWhere?: WhereOptions;
143
143
  limit?: number;
144
144
  }
145
+ /**
146
+ * Direction of one normalized order term.
147
+ *
148
+ * `'RANDOM'` comes from the `random()` order helper (`src/operators.ts`) and
149
+ * carries no field — the engines that can shuffle express it as a whole term
150
+ * of their own (Cypher `rand()`, Gremlin `order().by(shuffle)`), and the ones
151
+ * that cannot raise a {@link GraphCapabilityError}.
152
+ */
153
+ export type GraphOrderDirection = 'ASC' | 'DESC' | 'RANDOM';
154
+ /** One normalized order term: the property to sort on and its direction. */
155
+ export type GraphOrderTerm = [string, GraphOrderDirection];
145
156
  /** Options for a node find/match. */
146
157
  export interface NodeMatchSpec {
147
158
  label: string;
@@ -150,7 +161,7 @@ export interface NodeMatchSpec {
150
161
  include?: string[];
151
162
  exclude?: string[];
152
163
  };
153
- order?: Array<[string, 'ASC' | 'DESC']> | string[];
164
+ order?: GraphOrderTerm[] | string[];
154
165
  limit?: number | string;
155
166
  offset?: number | string;
156
167
  /** Associations to co-fetch as graph walks. */
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ export { ConnectionManager, createConnectionManager, NamedConnectionOptions } fr
8
8
  export { DataTypes, AbstractDataType } from './models/data-types';
9
9
  export { CreationOptional, NonAttribute, ForeignKey, InferAttributes, InferCreationAttributes, PartialBy, RequiredBy, ModelStatic, ModelOptions, } from './models/typescript-types';
10
10
  export { Model } from './models';
11
- export { Table, Attribute, Column, AllowNull, PrimaryKey, AutoIncrement, NotNull, Default, Unique, Comment, getModelMetadata, getAttributeMetadata, getModelAttributes, clearMetadata, HasOneOptions, HasManyOptions, BelongsToOptions, BelongsToManyOptions, HasOne, HasMany, BelongsTo, BelongsToMany, } from './models/decorators';
11
+ export { Table, AbstractModel, isAbstractModel, getInheritedAttributeMetadata, Attribute, Column, AllowNull, PrimaryKey, AutoIncrement, NotNull, Default, Unique, Comment, getModelMetadata, getAttributeMetadata, getModelAttributes, clearMetadata, HasOneOptions, HasManyOptions, BelongsToOptions, BelongsToManyOptions, HasOne, HasMany, BelongsTo, BelongsToMany, } from './models/decorators';
12
12
  export * from './compliance';
13
13
  export * from './extensions';
14
14
  export declare const STRING: ((...args: any[]) => import("./models").STRING) & {
@@ -163,7 +163,7 @@ export declare const GEOGRAPHY: ((...args: any[]) => import("./models").GEOGRAPH
163
163
  };
164
164
  export { Op } from './models/operators';
165
165
  export type { Operator } from './models/operators';
166
- export { Op as Operators, Operators as OpAliases, getOperatorString, operatorToWhereKey, where, and, or, not, eq, ne, gt, gte, lt, lte, like, notLike, iLike, notILike, startsWith, notStartsWith, endsWith, notEndsWith, substring, notSubstring, match, regexp, notRegexp, iRegexp, notIRegexp, in as in, inOp, notIn, between, notBetween, isNull, isNotNull, contains, overlap, asc, desc, random, isOrderExpression, } from './operators';
166
+ export { Op as Operators, Operators as OpAliases, getOperatorString, operatorToWhereKey, normalizeOperatorKeys, where, and, or, not, eq, ne, gt, gte, lt, lte, like, notLike, iLike, notILike, startsWith, notStartsWith, endsWith, notEndsWith, substring, notSubstring, match, regexp, notRegexp, iRegexp, notIRegexp, in as in, inOp, notIn, between, notBetween, isNull, isNotNull, contains, overlap, asc, desc, random, isOrderExpression, } from './operators';
167
167
  export type { OperatorSymbol, WhereConditionOptions, OrderExpression } from './operators';
168
168
  export * from './operators/index';
169
169
  export { Transaction } from './types';
@@ -172,6 +172,8 @@ export { ReplicaManager } from './replica-manager';
172
172
  export type { ReplicaStatus, ReplicaConnectionConfig, LagDetectionConfig, ReplicationOptions, RoutingStrategy, } from './replica-manager';
173
173
  export { Dialect, BaseDialect, DialectRegistry } from './dialects/dialect';
174
174
  export { BaseGraphDialect, Neo4jGraphDialect, GremlinGraphDialect, DgraphGraphDialect, GRAPH_DIALECTS, registerGraphDialects, } from './graph';
175
+ export { GraphCapabilityError, ParamBag, normalizeWhere, deriveAssociationEdge, defaultEdgeLabel, safeIdent, } from './graph';
176
+ export type { GraphConnectionOptions, GraphStatement, GraphPredicate, CanonOp, GraphAssociationType, GraphAssociationSpec, GraphPropertyDefinition, NodeModelDefinition, EdgeModelDefinition, GraphTraversalDirection, GraphTraversalStep, GraphTraversalSpec, NodeMatchSpec, WhereRenderContext, EdgeCreateSpec, NodeConstraintKind, DialectRegistryLike, } from './graph';
175
177
  export type { DialectOptions, ColumnDefinition, TableOptions, DropTableOptions, TableDescription, IndexOptions, BuildOptions, InsertOptions, UpdateOptions as DialectUpdateOptions, DeleteOptions, SelectOptions, CTEOption, CreateExtensionOptions, DropExtensionOptions, ExtensionInfo, } from './dialects/dialect';
176
178
  export { SQLiteDialect } from './dialects/sqlite';
177
179
  export { OracleDialect, createOracleDialect } from './dialects/oracle';
@@ -210,11 +212,18 @@ export { UserManager, PRIVILEGE_LEVELS } from './user-management';
210
212
  export type { PrivilegeType, PrivilegeScope, CreateUserOptions, AlterUserOptions, GrantOptions, RevokeOptions, RoleOptions, UserInfo, PrivilegeInfo, } from './user-management';
211
213
  export { SQLiteAdvanced, createSQLiteAdvanced } from './sqlite-advanced';
212
214
  export type { TriggerTiming, TriggerEvent, FTS5Tokenizer, GeneratedStorageType, ConflictAlgorithm, } from './sqlite-advanced';
213
- export { SQL, MYSQL, MARIADB, POSTGRES, SQLITE, getConstantsForDialect, IsolationLevelEnum, IsolationLevelValue, } from './sql-constants';
214
- export type { SQLConstants, MySQLConstants, PostgresConstants, SQLiteConstants, IsolationLevel, ForeignKeyChecks, UniqueKeyChecks, Autocommit, Cache, SqlMode, PragmaSettings, ConstraintDeferral, SearchPath, } from './sql-constants';
215
+ export { SQL, MYSQL, MARIADB, POSTGRES, SQLITE, getConstantsForDialect, getForeignKeyChecksSQL, UnsupportedForeignKeyChecksError, IsolationLevelEnum, IsolationLevelValue, } from './sql-constants';
216
+ export type { ForeignKeyChecksMode, SQLConstants, MySQLConstants, PostgresConstants, SQLiteConstants, IsolationLevel, ForeignKeyChecks, UniqueKeyChecks, Autocommit, Cache, SqlMode, PragmaSettings, ConstraintDeferral, SearchPath, } from './sql-constants';
215
217
  export * from './nosql';
216
218
  export { count, countDistinct, avg, min, max, stringAgg, arrayAgg, CaseBuilder, SimpleCaseBuilder, caseWhen, caseOf, dateTrunc, dateAdd, dateSub, dateDiff, currentDate, currentTimestamp, fullTextMatch, fullTextRank, jsonExtract, jsonKeys, jsonTypeOf, round, ceil, floor, power, sqrt, abs, sign, mod, greatest, least, concat, upper, lower, length, replace, lpad, rpad, split, WindowFunctionBuilder, rowNumber, rank, denseRank, percentRank, cumeDist, ntile, lag, lead, firstValue, lastValue, nthValue, sumOver, avgOver, countOver, minOver, maxOver, windowFn, NullsOrder, } from './query-builders/functions';
217
219
  export { random as sqlRandom, truncate as sqlTruncate, substring as sqlSubstring, trim as sqlTrim, ltrim as sqlLtrim, rtrim as sqlRtrim, jsonContains as sqlJsonContains, jsonHasKey as sqlJsonHasKey, formatDate as sqlFormatDate, now as sqlNow, repeat as sqlRepeat, reverse as sqlReverse, sum as sqlSum, } from './query-builders/functions';
220
+ export { AbstractCacheManager, RedisClusterCache, createRedisClusterCache } from './cache';
221
+ export type { CacheBackend, L2CacheOptions, CacheKeyOptions, CacheStats, CacheBackendFactory, RedisClusterOptions, RedisClusterNodeConfig, } from './cache';
222
+ export type { CacheEntry as CacheManagerEntry, CacheManagerOptions as CacheManagerConfig, L1CacheOptions as CacheManagerL1Options, RedisClusterCacheOptions as RedisClusterCacheConfig, RedisClusterNode as RedisClusterCacheNode, } from './cache';
223
+ export { AuditLogger, setAuditLogger, getAuditLogger, addAuditHistoryToModel, addAuditHistoryToInstance, } from './audit';
224
+ export type { AuditLog, AuditLoggerOptions } from './audit';
225
+ export { convertPrismaSchema, parsePrismaSchema, resolveRelations } from './prisma-migrate';
226
+ export type { ConversionResult, PrismaSchema, PrismaModel, PrismaEnum, PrismaField, PrormRelation, } from './prisma-migrate';
218
227
  import { Prorm } from './prorm';
219
228
  import { Transaction } from './types';
220
229
  declare const ORM: {