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.
- package/CHANGELOG.md +331 -1
- package/README.md +32 -24
- package/dist/compliance/data-classifier.d.ts +6 -0
- package/dist/compliance/data-classifier.js +6 -0
- package/dist/compliance/data-lineage.d.ts +4 -0
- package/dist/compliance/data-lineage.js +4 -0
- package/dist/compliance/data-masker.d.ts +4 -0
- package/dist/compliance/data-masker.js +4 -0
- package/dist/compliance/index.d.ts +4 -0
- package/dist/compliance/index.js +15 -1
- package/dist/compliance/pseudonymization.d.ts +4 -0
- package/dist/compliance/pseudonymization.js +4 -0
- package/dist/compliance/query-firewall.d.ts +9 -9
- package/dist/compliance/query-firewall.js +9 -9
- package/dist/compliance/rate-limiter.d.ts +4 -0
- package/dist/compliance/rate-limiter.js +4 -0
- package/dist/compliance/row-level-security.d.ts +2 -0
- package/dist/compliance/row-level-security.js +2 -0
- package/dist/compliance/security-decorator.d.ts +8 -0
- package/dist/compliance/security-decorator.js +8 -0
- package/dist/compliance/session-isolation.d.ts +4 -0
- package/dist/compliance/session-isolation.js +4 -0
- package/dist/compliance/worm-storage.d.ts +4 -0
- package/dist/compliance/worm-storage.js +4 -0
- package/dist/connection-manager.js +13 -1
- package/dist/core/expressions.d.ts +58 -0
- package/dist/core/expressions.js +83 -0
- package/dist/core/hooks-manager.d.ts +179 -0
- package/dist/core/hooks-manager.js +291 -0
- package/dist/core/types.d.ts +235 -0
- package/dist/core/types.js +9 -0
- package/dist/decorators/audit.d.ts +3 -1
- package/dist/decorators/audit.js +3 -1
- package/dist/decorators/check.d.ts +15 -15
- package/dist/decorators/check.js +15 -15
- package/dist/decorators/collate.d.ts +16 -0
- package/dist/decorators/collate.js +16 -0
- package/dist/decorators/comment.d.ts +3 -1
- package/dist/decorators/comment.js +3 -1
- package/dist/decorators/database-settings.d.ts +6 -0
- package/dist/decorators/database-settings.js +6 -0
- package/dist/decorators/default.d.ts +2 -0
- package/dist/decorators/default.js +2 -0
- package/dist/decorators/encryption.d.ts +7 -1
- package/dist/decorators/encryption.js +7 -1
- package/dist/decorators/engine.d.ts +4 -0
- package/dist/decorators/engine.js +4 -0
- package/dist/decorators/fk-constraints.d.ts +32 -32
- package/dist/decorators/fk-constraints.js +32 -32
- package/dist/decorators/foreign-table.d.ts +1 -1
- package/dist/decorators/generated.d.ts +8 -0
- package/dist/decorators/generated.js +8 -0
- package/dist/decorators/hstore.d.ts +6 -0
- package/dist/decorators/hstore.js +6 -0
- package/dist/decorators/index.d.ts +2 -0
- package/dist/decorators/index.js +11 -1
- package/dist/decorators/json-column.d.ts +2 -0
- package/dist/decorators/json-column.js +2 -0
- package/dist/decorators/jsonb.d.ts +6 -0
- package/dist/decorators/jsonb.js +6 -0
- package/dist/decorators/permissions.d.ts +12 -0
- package/dist/decorators/permissions.js +12 -0
- package/dist/decorators/procedure.d.ts +4 -2
- package/dist/decorators/procedure.js +4 -2
- package/dist/decorators/query-options.d.ts +24 -0
- package/dist/decorators/query-options.js +24 -0
- package/dist/decorators/range.d.ts +8 -0
- package/dist/decorators/range.js +8 -0
- package/dist/decorators/set-column.d.ts +2 -0
- package/dist/decorators/set-column.js +2 -0
- package/dist/decorators/spatial.d.ts +2 -0
- package/dist/decorators/spatial.js +2 -0
- package/dist/decorators/storage.d.ts +24 -0
- package/dist/decorators/storage.js +24 -0
- package/dist/decorators/timezone.d.ts +7 -7
- package/dist/decorators/timezone.js +7 -7
- package/dist/decorators/trigger.d.ts +3 -1
- package/dist/decorators/trigger.js +3 -1
- package/dist/decorators/uuid.d.ts +6 -0
- package/dist/decorators/uuid.js +6 -0
- package/dist/decorators/view.d.ts +7 -1
- package/dist/decorators/view.js +7 -1
- package/dist/diagrams/chen-diagram.d.ts +15 -12
- package/dist/diagrams/chen-diagram.js +76 -85
- package/dist/diagrams/class-diagram.d.ts +9 -8
- package/dist/diagrams/class-diagram.js +60 -82
- package/dist/diagrams/core/index.d.ts +13 -0
- package/dist/diagrams/core/index.js +33 -0
- package/dist/diagrams/core/layout.d.ts +104 -0
- package/dist/diagrams/core/layout.js +223 -0
- package/dist/diagrams/{svg-dom.d.ts → core/svg.d.ts} +8 -20
- package/dist/diagrams/{svg-dom.js → core/svg.js} +21 -29
- package/dist/diagrams/core/theme.d.ts +84 -0
- package/dist/diagrams/core/theme.js +62 -0
- package/dist/diagrams/dependency-diagram.d.ts +15 -14
- package/dist/diagrams/dependency-diagram.js +71 -105
- package/dist/diagrams/er-diagram.d.ts +13 -26
- package/dist/diagrams/er-diagram.js +180 -259
- package/dist/diagrams/flow-diagram.d.ts +16 -11
- package/dist/diagrams/flow-diagram.js +96 -91
- package/dist/diagrams/gantt-diagram.d.ts +10 -5
- package/dist/diagrams/gantt-diagram.js +77 -103
- package/dist/diagrams/index-diagram.d.ts +10 -10
- package/dist/diagrams/index-diagram.js +106 -116
- package/dist/diagrams/index.d.ts +6 -9
- package/dist/diagrams/index.js +9 -24
- package/dist/diagrams/migration-diagram.d.ts +8 -4
- package/dist/diagrams/migration-diagram.js +189 -161
- package/dist/diagrams/model-diagram.d.ts +34 -34
- package/dist/diagrams/model-diagram.js +106 -485
- package/dist/diagrams/package-diagram.d.ts +9 -6
- package/dist/diagrams/package-diagram.js +64 -101
- package/dist/diagrams/relational-diagram.d.ts +12 -10
- package/dist/diagrams/relational-diagram.js +87 -114
- package/dist/diagrams/schemadoc-diagram.d.ts +8 -8
- package/dist/diagrams/schemadoc-diagram.js +71 -93
- package/dist/diagrams/sequence-diagram.d.ts +10 -10
- package/dist/diagrams/sequence-diagram.js +64 -89
- package/dist/diagrams/state-diagram.d.ts +10 -9
- package/dist/diagrams/state-diagram.js +69 -92
- package/dist/diagrams/tree-diagram.d.ts +11 -5
- package/dist/diagrams/tree-diagram.js +41 -65
- package/dist/dialects/clickhouse/index.js +15 -0
- package/dist/dialects/cockroachdb/index.d.ts +1 -1
- package/dist/dialects/cockroachdb/index.js +32 -63
- package/dist/dialects/db2/index.js +23 -8
- package/dist/dialects/dialect.d.ts +141 -5
- package/dist/dialects/duckdb/index.js +9 -2
- package/dist/dialects/hana/index.js +22 -5
- package/dist/dialects/lock-clause-helper.d.ts +167 -0
- package/dist/dialects/lock-clause-helper.js +316 -0
- package/dist/dialects/mariadb/index.d.ts +7 -4
- package/dist/dialects/mariadb/index.js +36 -60
- package/dist/dialects/mssql/index.js +34 -3
- package/dist/dialects/mysql/index.d.ts +1 -1
- package/dist/dialects/mysql/index.js +17 -45
- package/dist/dialects/oracle/index.d.ts +14 -3
- package/dist/dialects/oracle/index.js +66 -36
- package/dist/dialects/order-expression-helper.d.ts +72 -0
- package/dist/dialects/order-expression-helper.js +154 -0
- package/dist/dialects/partial-index.d.ts +52 -0
- package/dist/dialects/partial-index.js +251 -0
- package/dist/dialects/postgres/index.d.ts +1 -1
- package/dist/dialects/postgres/index.js +43 -68
- package/dist/dialects/redshift/index.js +9 -2
- package/dist/dialects/snowflake/index.js +17 -0
- package/dist/dialects/spanner/index.js +7 -2
- package/dist/dialects/sqlite/driver.d.ts +55 -0
- package/dist/dialects/sqlite/driver.js +102 -0
- package/dist/dialects/sqlite/index.d.ts +1 -1
- package/dist/dialects/sqlite/index.js +49 -27
- package/dist/external-fields/decorator.d.ts +2 -0
- package/dist/external-fields/decorator.js +2 -0
- package/dist/graph/base-graph-dialect.d.ts +24 -3
- package/dist/graph/base-graph-dialect.js +43 -2
- package/dist/graph/dgraph/index.js +6 -0
- package/dist/graph/gremlin/index.d.ts +6 -0
- package/dist/graph/gremlin/index.js +12 -1
- package/dist/graph/index.d.ts +1 -1
- package/dist/graph/neo4j/index.d.ts +2 -0
- package/dist/graph/neo4j/index.js +6 -1
- package/dist/graph/types.d.ts +12 -1
- package/dist/index.d.ts +12 -3
- package/dist/index.js +53 -7
- package/dist/logging/index.d.ts +10 -0
- package/dist/logging/index.js +23 -0
- package/dist/logging/query-logging.d.ts +82 -0
- package/dist/logging/query-logging.js +102 -0
- package/dist/models/associations.d.ts +38 -0
- package/dist/models/associations.js +16 -0
- package/dist/models/decorators.d.ts +55 -19
- package/dist/models/decorators.js +95 -19
- package/dist/models/eager-load.d.ts +99 -0
- package/dist/models/eager-load.js +348 -5
- package/dist/models/indexes.d.ts +3 -2
- package/dist/models/indexes.js +7 -1
- package/dist/models/model.js +69 -43
- package/dist/prorm.d.ts +175 -409
- package/dist/prorm.js +1132 -553
- package/dist/query-builders/order-limit-builder.js +12 -10
- package/dist/query-builders/sql-compiler.d.ts +10 -3
- package/dist/query-builders/sql-compiler.js +14 -43
- package/dist/query-interface.d.ts +2 -1
- package/dist/schema-objects.d.ts +42 -0
- package/dist/schema-objects.js +28 -0
- package/dist/sql-constants.d.ts +44 -0
- package/dist/sql-constants.js +138 -1
- package/dist/types/index.d.ts +387 -17
- package/dist/types/index.js +10 -15
- package/dist/types/query-types.d.ts +26 -0
- package/dist/types/query-types.js +30 -0
- package/package.json +39 -8
- package/dist/decorators/belongs-to-many.js +0 -115
- package/dist/decorators/belongs-to.js +0 -115
- package/dist/decorators/has-many.js +0 -127
- package/dist/decorators/has-one.js +0 -116
- package/dist/diagrams/palette.d.ts +0 -138
- package/dist/diagrams/palette.js +0 -194
- package/dist/hooks/hooks-manager.d.ts +0 -189
- package/dist/hooks/hooks-manager.js +0 -350
- package/dist/hooks/index.d.ts +0 -8
- package/dist/hooks/index.js +0 -37
- /package/dist/{logging.d.ts → logging/logger.d.ts} +0 -0
- /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 (
|
|
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 (
|
|
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
|
+
}
|
|
@@ -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
|
-
|
|
10
|
-
//
|
|
11
|
-
// better-sqlite3
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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 (
|
|
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
|
|
1855
|
-
|
|
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
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
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 (
|
|
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
|
-
/**
|
|
114
|
-
|
|
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
|
-
/**
|
|
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]) =>
|
|
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 +=
|
|
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;
|
package/dist/graph/index.d.ts
CHANGED
|
@@ -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
|
-
|
|
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)}`;
|