uql-orm 0.37.1 → 0.39.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/dist/browser/uql-browser.min.js +2 -2
- package/dist/browser/uql-browser.min.js.map +5 -5
- package/dist/cockroachdb/cockroachDialect.d.ts +5 -24
- package/dist/cockroachdb/cockroachDialect.js +3 -29
- package/dist/dialect/abstractSqlDialect.d.ts +42 -12
- package/dist/dialect/abstractSqlDialect.js +117 -48
- package/dist/dialect/aliases.d.ts +6 -0
- package/dist/dialect/aliases.js +6 -0
- package/dist/dialect/index.d.ts +0 -5
- package/dist/dialect/index.js +2 -5
- package/dist/dialect/jsonSql.d.ts +17 -2
- package/dist/dialect/jsonSql.js +15 -0
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +13 -14
- package/dist/dialect/mysqlLikeSqlDialect.js +16 -20
- package/dist/dialect/pgLikeSqlDialect.d.ts +17 -20
- package/dist/dialect/pgLikeSqlDialect.js +30 -62
- package/dist/dialect/vectorCast.d.ts +0 -9
- package/dist/dialect/vectorCast.js +0 -8
- package/dist/dialect/vectorSqlDialect.d.ts +47 -17
- package/dist/dialect/vectorSqlDialect.js +78 -30
- package/dist/entity/decorator/entity.d.ts +1 -1
- package/dist/entity/metadata/definition.d.ts +1 -1
- package/dist/entity/metadata/definition.js +4 -3
- package/dist/http/query.js +3 -2
- package/dist/libsql/libsqlDialect.d.ts +2 -2
- package/dist/libsql/libsqlDialect.js +3 -3
- package/dist/maria/mariaDialect.d.ts +12 -17
- package/dist/maria/mariaDialect.js +21 -36
- package/dist/maria/mariaVectorMetrics.d.ts +8 -0
- package/dist/maria/mariaVectorMetrics.js +10 -0
- package/dist/maria/mariadbQuerier.d.ts +5 -0
- package/dist/maria/mariadbQuerier.js +5 -0
- package/dist/migrate/builder/migrationBuilder.d.ts +8 -17
- package/dist/migrate/builder/migrationBuilder.js +48 -136
- package/dist/migrate/builder/types.d.ts +0 -2
- package/dist/migrate/ddl/index.d.ts +11 -0
- package/dist/migrate/ddl/index.js +34 -0
- package/dist/{dialect/indexSqlDialect.d.ts → migrate/ddl/indexDdl.d.ts} +23 -19
- package/dist/migrate/ddl/indexDdl.js +126 -0
- package/dist/migrate/ddl/mysqlIndexDdl.d.ts +52 -0
- package/dist/migrate/ddl/mysqlIndexDdl.js +125 -0
- package/dist/migrate/ddl/pgIndexDdl.d.ts +36 -0
- package/dist/migrate/ddl/pgIndexDdl.js +87 -0
- package/dist/migrate/drift/driftDetector.js +6 -1
- package/dist/migrate/generator/mongoSchemaGenerator.js +1 -1
- package/dist/migrate/index.d.ts +1 -0
- package/dist/migrate/index.js +2 -0
- package/dist/migrate/introspection/mysqlIntrospector.d.ts +9 -3
- package/dist/migrate/introspection/mysqlIntrospector.js +27 -5
- package/dist/migrate/migrator.js +3 -2
- package/dist/migrate/schemaGenerator.d.ts +6 -6
- package/dist/migrate/schemaGenerator.js +13 -22
- package/dist/mongo/mongoDialect.d.ts +1 -2
- package/dist/mongo/mongoDialect.js +29 -22
- package/dist/mongo/mongodbQuerier.js +1 -1
- package/dist/mysql/mysqlDialect.d.ts +3 -6
- package/dist/mysql/mysqlDialect.js +4 -11
- package/dist/postgres/postgresDialect.d.ts +2 -0
- package/dist/postgres/postgresDialect.js +2 -0
- package/dist/querier/abstractSqlQuerier.d.ts +11 -0
- package/dist/querier/abstractSqlQuerier.js +35 -0
- package/dist/schema/canonicalType.js +35 -36
- package/dist/schema/indexDifferences.d.ts +2 -1
- package/dist/schema/indexDifferences.js +3 -2
- package/dist/sqlite/sqliteDialect.d.ts +2 -2
- package/dist/sqlite/sqliteDialect.js +5 -5
- package/dist/turso/tursoDialect.d.ts +2 -2
- package/dist/turso/tursoDialect.js +4 -4
- package/dist/type/dialect.d.ts +21 -7
- package/dist/type/dialect.js +17 -0
- package/dist/type/entity.d.ts +117 -8
- package/dist/type/entity.js +7 -0
- package/dist/type/query.d.ts +18 -0
- package/dist/type/query.js +6 -0
- package/dist/type/queryWhere.d.ts +46 -2
- package/dist/type/vector.d.ts +45 -7
- package/dist/type/vector.js +16 -1
- package/dist/util/dialect.util.d.ts +20 -1
- package/dist/util/dialect.util.js +49 -4
- package/dist/util/object.util.d.ts +7 -1
- package/dist/util/object.util.js +8 -0
- package/dist/util/relationQuery.util.d.ts +3 -1
- package/dist/util/relationQuery.util.js +8 -3
- package/package.json +1 -1
- package/dist/dialect/indexSqlDialect.js +0 -103
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
import { jsonPath } from '../dialect/jsonSql.js';
|
|
2
2
|
import { MysqlLikeSqlDialect } from '../dialect/mysqlLikeSqlDialect.js';
|
|
3
3
|
import { isVectorFieldType } from '../dialect/vectorCast.js';
|
|
4
|
+
import { getMeta } from '../entity/index.js';
|
|
5
|
+
import { MARIA_VECTOR_METRICS } from './mariaVectorMetrics.js';
|
|
4
6
|
export class MariaDialect extends MysqlLikeSqlDialect {
|
|
5
7
|
dialectName = 'mariadb';
|
|
6
|
-
// MariaDB 10.5+
|
|
8
|
+
// MariaDB 10.5+ has `INSERT ... RETURNING`, so ids come back exact per row - the upsert's too.
|
|
7
9
|
insertIdSource = 'returning';
|
|
8
|
-
/**
|
|
9
|
-
* MariaDB has no functional indexes: `CREATE INDEX ... ((lower(col)))` is a syntax error even on
|
|
10
|
-
* 12.3, where the documented workaround is a generated column. So it keeps the prefix lengths the
|
|
11
|
-
* family shares and drops expressions.
|
|
12
|
-
*/
|
|
13
|
-
indexFeatures = new Set(['prefixLength']);
|
|
14
10
|
/** MariaDB has no `FOR ... OF`, so a lock cannot be narrowed to one table of a join. */
|
|
15
11
|
supportsLockOf = false;
|
|
16
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Unlike MySQL: `VECTOR(n)` takes its dimension, every column of a vector index has to be NOT NULL,
|
|
14
|
+
* and `CREATE INDEX` takes `IF NOT EXISTS` - which MySQL's grammar has no place for.
|
|
15
|
+
*/
|
|
17
16
|
featureOverrides = {
|
|
18
17
|
vectorSupportsLength: true,
|
|
19
|
-
|
|
18
|
+
vectorIndexRequiresNotNull: true,
|
|
19
|
+
indexIfNotExists: true,
|
|
20
20
|
};
|
|
21
|
-
/** MariaDB 10.5+ supports `INSERT ... RETURNING`, so the ids are exact per row. */
|
|
22
21
|
upsertReturning(entity) {
|
|
23
22
|
return ` ${this.returningId(entity)}`;
|
|
24
23
|
}
|
|
@@ -47,16 +46,8 @@ export class MariaDialect extends MysqlLikeSqlDialect {
|
|
|
47
46
|
jsonPullKeep(alias, operand) {
|
|
48
47
|
return `NOT JSON_EQUALS(${alias}.v, ${operand})`;
|
|
49
48
|
}
|
|
50
|
-
/**
|
|
51
|
-
|
|
52
|
-
['cosine', 'cosine'],
|
|
53
|
-
['l2', 'euclidean'],
|
|
54
|
-
]);
|
|
55
|
-
/** MariaDB 11.7+ vector distance functions. */
|
|
56
|
-
vectorDistanceFns = new Map([
|
|
57
|
-
['cosine', 'VEC_DISTANCE_COSINE'],
|
|
58
|
-
['l2', 'VEC_DISTANCE_EUCLIDEAN'],
|
|
59
|
-
]);
|
|
49
|
+
/** `VEC_DISTANCE_COSINE`/`VEC_DISTANCE_EUCLIDEAN`, 11.7+: the metric's own name, uppercased. */
|
|
50
|
+
vectorMetrics = new Map([...MARIA_VECTOR_METRICS].map(([metric, name]) => [metric, { fn: `VEC_DISTANCE_${name.toUpperCase()}` }]));
|
|
60
51
|
/**
|
|
61
52
|
* A `VECTOR` column holds a packed little-endian float32 blob, and MariaDB refuses text where one
|
|
62
53
|
* belongs: inserting `'[1,2,3]'` fails with `Incorrect vector value`, and passing it to
|
|
@@ -69,24 +60,18 @@ export class MariaDialect extends MysqlLikeSqlDialect {
|
|
|
69
60
|
ctx.append(')');
|
|
70
61
|
}
|
|
71
62
|
/**
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
63
|
+
* `SET STATEMENT mhnsw_ef_search=N FOR SELECT ...` - MariaDB scopes a variable to one statement, so
|
|
64
|
+
* the tuning needs neither a transaction nor a restore afterwards, and cannot leak to the next
|
|
65
|
+
* query on this pooled connection. That is why it prefixes the SQL here instead of coming back
|
|
66
|
+
* from `vectorTuningStatements`, which is Postgres's `SET LOCAL` shape.
|
|
75
67
|
*/
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
if (index.distance) {
|
|
83
|
-
const metric = MariaDialect.INLINE_VECTOR_METRICS.get(index.distance);
|
|
84
|
-
if (!metric) {
|
|
85
|
-
throw new TypeError(`${this.dialectName} does not support vector distance metric: ${index.distance} (index "${index.name}")`);
|
|
86
|
-
}
|
|
87
|
-
clause += ` DISTANCE=${metric}`;
|
|
68
|
+
find(ctx, entity, q = {}, opts, totalAlias) {
|
|
69
|
+
// `$candidates` first: `getMeta` would otherwise be resolved on every read, to discover that
|
|
70
|
+
// almost none of them tune anything.
|
|
71
|
+
if (q.$candidates !== undefined && this.tunedVectorIndex(getMeta(entity), q)) {
|
|
72
|
+
ctx.append(`SET STATEMENT mhnsw_ef_search=${q.$candidates} FOR `);
|
|
88
73
|
}
|
|
89
|
-
|
|
74
|
+
super.find(ctx, entity, q, opts, totalAlias);
|
|
90
75
|
}
|
|
91
76
|
/** The reverse: selecting a `VECTOR` column raw yields that blob, so it is read back as text. */
|
|
92
77
|
selectFieldExpr(escapedColumn, field) {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { VectorDistance } from '../type/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* MariaDB's own name for each metric it supports (`euclidean`, not `l2`), which its index clause and
|
|
4
|
+
* its distance function are both spelled from - one list, so a metric can never be searchable and
|
|
5
|
+
* unindexable or the reverse. Its own module because the two ends now live apart: the distance
|
|
6
|
+
* function on the dialect, the `DISTANCE=` clause in the migrator's index DDL.
|
|
7
|
+
*/
|
|
8
|
+
export declare const MARIA_VECTOR_METRICS: Map<VectorDistance, string>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MariaDB's own name for each metric it supports (`euclidean`, not `l2`), which its index clause and
|
|
3
|
+
* its distance function are both spelled from - one list, so a metric can never be searchable and
|
|
4
|
+
* unindexable or the reverse. Its own module because the two ends now live apart: the distance
|
|
5
|
+
* function on the dialect, the `DISTANCE=` clause in the migrator's index DDL.
|
|
6
|
+
*/
|
|
7
|
+
export const MARIA_VECTOR_METRICS = new Map([
|
|
8
|
+
['cosine', 'cosine'],
|
|
9
|
+
['l2', 'euclidean'],
|
|
10
|
+
]);
|
|
@@ -7,5 +7,10 @@ export declare class MariadbQuerier extends AbstractPoolQuerier<PoolConnection>
|
|
|
7
7
|
internalAll<T>(query: string, values?: unknown[]): Promise<T[]>;
|
|
8
8
|
internalRun(query: string, values?: unknown[]): Promise<import("../type/query.js").QueryUpdateResult>;
|
|
9
9
|
internalStream<T>(query: string, values?: unknown[]): AsyncGenerator<Awaited<T>, void, unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* No `discard` branch, unlike mysql2's: this driver resets the connection on release, so one taken
|
|
12
|
+
* back mid-transaction rolls back rather than handing the next caller an open one. Verified on
|
|
13
|
+
* 12.3 - same `threadId` on reacquire, `@@in_transaction` 0, the uncommitted row gone.
|
|
14
|
+
*/
|
|
10
15
|
protected releaseConn(conn: PoolConnection): Promise<void>;
|
|
11
16
|
}
|
|
@@ -24,6 +24,11 @@ export class MariadbQuerier extends AbstractPoolQuerier {
|
|
|
24
24
|
stream.destroy();
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* No `discard` branch, unlike mysql2's: this driver resets the connection on release, so one taken
|
|
29
|
+
* back mid-transaction rolls back rather than handing the next caller an open one. Verified on
|
|
30
|
+
* 12.3 - same `threadId` on reacquire, `@@in_transaction` 0, the uncommitted row gone.
|
|
31
|
+
*/
|
|
27
32
|
async releaseConn(conn) {
|
|
28
33
|
await conn.release();
|
|
29
34
|
}
|
|
@@ -24,6 +24,12 @@ type ForeignKeyOptions = {
|
|
|
24
24
|
*/
|
|
25
25
|
export declare class OperationRecorder implements IMigrationBuilder {
|
|
26
26
|
protected readonly operations: AnyMigrationOperation[];
|
|
27
|
+
/**
|
|
28
|
+
* Where every operation this class builds lands, and the one thing {@link MigrationBuilder}
|
|
29
|
+
* overrides: it records and then runs. Each operation is spelled once, here, rather than once per
|
|
30
|
+
* class, which is what let the two drift into recording different shapes of the same change.
|
|
31
|
+
*/
|
|
32
|
+
protected record(operation: AnyMigrationOperation): Promise<void>;
|
|
27
33
|
createTable(name: string, callback: (table: ITableBuilder) => void): Promise<void>;
|
|
28
34
|
dropTable(name: string, options?: {
|
|
29
35
|
ifExists?: boolean;
|
|
@@ -41,7 +47,6 @@ export declare class OperationRecorder implements IMigrationBuilder {
|
|
|
41
47
|
dropForeignKey(tableName: string, constraintName: string): Promise<void>;
|
|
42
48
|
raw(sql: string): Promise<void>;
|
|
43
49
|
getOperations(): AnyMigrationOperation[];
|
|
44
|
-
recordOperationSync(operation: AnyMigrationOperation): void;
|
|
45
50
|
}
|
|
46
51
|
/**
|
|
47
52
|
* Executes DDL operations via a SQL querier.
|
|
@@ -62,22 +67,8 @@ export declare class MigrationBuilder extends OperationRecorder {
|
|
|
62
67
|
private readonly querier;
|
|
63
68
|
private readonly sqlGenerator;
|
|
64
69
|
constructor(querier: SqlQuerier);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
createTable(name: string, callback: (table: ITableBuilder) => void): Promise<void>;
|
|
68
|
-
dropTable(name: string, options?: {
|
|
69
|
-
ifExists?: boolean;
|
|
70
|
-
cascade?: boolean;
|
|
71
|
-
}): Promise<void>;
|
|
72
|
-
renameTable(oldName: string, newName: string): Promise<void>;
|
|
73
|
-
addColumn(tableName: string, callback: (columns: IColumnFactory) => IColumnBuilder): Promise<void>;
|
|
74
|
-
dropColumn(tableName: string, columnName: string): Promise<void>;
|
|
75
|
-
alterColumn(tableName: string, callback: (columns: IColumnFactory) => IColumnBuilder): Promise<void>;
|
|
76
|
-
renameColumn(tableName: string, oldName: string, newName: string): Promise<void>;
|
|
77
|
-
createIndex(tableName: string, columns: readonly IndexColumnInput[], options?: IndexOptions): Promise<void>;
|
|
78
|
-
dropIndex(tableName: string, indexName: string): Promise<void>;
|
|
79
|
-
addForeignKey(tableName: string, columns: string[], target: ForeignKeyTarget, options?: ForeignKeyOptions): Promise<void>;
|
|
80
|
-
dropForeignKey(tableName: string, constraintName: string): Promise<void>;
|
|
70
|
+
/** The recorder's sink, plus the statements the operation turns into. */
|
|
71
|
+
protected record(operation: AnyMigrationOperation): Promise<void>;
|
|
81
72
|
private getCreateTableStatements;
|
|
82
73
|
private execute;
|
|
83
74
|
private operationToSql;
|
|
@@ -63,15 +63,21 @@ function addForeignKeyOperation(tableName, columns, target, options = {}) {
|
|
|
63
63
|
function buildOneColumn(callback) {
|
|
64
64
|
return callback(new TableBuilder('')).build();
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Collects the operations one `alterTable` callback declares, in the order it declared them.
|
|
68
|
+
*
|
|
69
|
+
* Collected rather than dispatched to the parent as they are made: the chaining methods are
|
|
70
|
+
* synchronous by contract, so a builder that executes could only fire and forget, which returned from
|
|
71
|
+
* `alterTable` with the statements still in flight and turned a failure into an unhandled rejection.
|
|
72
|
+
*/
|
|
66
73
|
class AlterTableBuilder {
|
|
67
74
|
tableName;
|
|
68
|
-
|
|
69
|
-
constructor(tableName
|
|
75
|
+
operations = [];
|
|
76
|
+
constructor(tableName) {
|
|
70
77
|
this.tableName = tableName;
|
|
71
|
-
this.parentBuilder = parentBuilder;
|
|
72
78
|
}
|
|
73
79
|
addColumn(callback) {
|
|
74
|
-
this.
|
|
80
|
+
this.operations.push({
|
|
75
81
|
type: 'addColumn',
|
|
76
82
|
tableName: this.tableName,
|
|
77
83
|
column: buildOneColumn(callback),
|
|
@@ -79,7 +85,7 @@ class AlterTableBuilder {
|
|
|
79
85
|
return this;
|
|
80
86
|
}
|
|
81
87
|
dropColumn(name) {
|
|
82
|
-
this.
|
|
88
|
+
this.operations.push({
|
|
83
89
|
type: 'dropColumn',
|
|
84
90
|
tableName: this.tableName,
|
|
85
91
|
columnName: name,
|
|
@@ -87,7 +93,7 @@ class AlterTableBuilder {
|
|
|
87
93
|
return this;
|
|
88
94
|
}
|
|
89
95
|
renameColumn(oldName, newName) {
|
|
90
|
-
this.
|
|
96
|
+
this.operations.push({
|
|
91
97
|
type: 'renameColumn',
|
|
92
98
|
tableName: this.tableName,
|
|
93
99
|
oldName,
|
|
@@ -97,7 +103,7 @@ class AlterTableBuilder {
|
|
|
97
103
|
}
|
|
98
104
|
alterColumn(callback) {
|
|
99
105
|
const column = buildOneColumn(callback);
|
|
100
|
-
this.
|
|
106
|
+
this.operations.push({
|
|
101
107
|
type: 'alterColumn',
|
|
102
108
|
tableName: this.tableName,
|
|
103
109
|
columnName: column.name,
|
|
@@ -106,11 +112,11 @@ class AlterTableBuilder {
|
|
|
106
112
|
return this;
|
|
107
113
|
}
|
|
108
114
|
addIndex(columns, options) {
|
|
109
|
-
this.
|
|
115
|
+
this.operations.push(createIndexOperation(this.tableName, columns, options));
|
|
110
116
|
return this;
|
|
111
117
|
}
|
|
112
118
|
dropIndex(name) {
|
|
113
|
-
this.
|
|
119
|
+
this.operations.push({
|
|
114
120
|
type: 'dropIndex',
|
|
115
121
|
tableName: this.tableName,
|
|
116
122
|
indexName: name,
|
|
@@ -118,11 +124,11 @@ class AlterTableBuilder {
|
|
|
118
124
|
return this;
|
|
119
125
|
}
|
|
120
126
|
addForeignKey(columns, target, options) {
|
|
121
|
-
this.
|
|
127
|
+
this.operations.push(addForeignKeyOperation(this.tableName, columns, target, options));
|
|
122
128
|
return this;
|
|
123
129
|
}
|
|
124
130
|
dropForeignKey(name) {
|
|
125
|
-
this.
|
|
131
|
+
this.operations.push({
|
|
126
132
|
type: 'dropForeignKey',
|
|
127
133
|
tableName: this.tableName,
|
|
128
134
|
constraintName: name,
|
|
@@ -130,22 +136,35 @@ class AlterTableBuilder {
|
|
|
130
136
|
return this;
|
|
131
137
|
}
|
|
132
138
|
}
|
|
139
|
+
function collectAlterOperations(tableName, callback) {
|
|
140
|
+
const builder = new AlterTableBuilder(tableName);
|
|
141
|
+
callback(builder);
|
|
142
|
+
return builder.operations;
|
|
143
|
+
}
|
|
133
144
|
/**
|
|
134
145
|
* Records migration operations without executing them.
|
|
135
146
|
* Use for migration code generation and dry-run scenarios.
|
|
136
147
|
*/
|
|
137
148
|
export class OperationRecorder {
|
|
138
149
|
operations = [];
|
|
150
|
+
/**
|
|
151
|
+
* Where every operation this class builds lands, and the one thing {@link MigrationBuilder}
|
|
152
|
+
* overrides: it records and then runs. Each operation is spelled once, here, rather than once per
|
|
153
|
+
* class, which is what let the two drift into recording different shapes of the same change.
|
|
154
|
+
*/
|
|
155
|
+
async record(operation) {
|
|
156
|
+
this.operations.push(operation);
|
|
157
|
+
}
|
|
139
158
|
async createTable(name, callback) {
|
|
140
159
|
const builder = new TableBuilder(name);
|
|
141
160
|
callback(builder);
|
|
142
|
-
this.
|
|
161
|
+
await this.record({
|
|
143
162
|
type: 'createTable',
|
|
144
163
|
table: builder.build(),
|
|
145
164
|
});
|
|
146
165
|
}
|
|
147
166
|
async dropTable(name, options = {}) {
|
|
148
|
-
this.
|
|
167
|
+
await this.record({
|
|
149
168
|
type: 'dropTable',
|
|
150
169
|
tableName: name,
|
|
151
170
|
ifExists: options.ifExists,
|
|
@@ -153,25 +172,26 @@ export class OperationRecorder {
|
|
|
153
172
|
});
|
|
154
173
|
}
|
|
155
174
|
async renameTable(oldName, newName) {
|
|
156
|
-
this.
|
|
175
|
+
await this.record({
|
|
157
176
|
type: 'renameTable',
|
|
158
177
|
oldName,
|
|
159
178
|
newName,
|
|
160
179
|
});
|
|
161
180
|
}
|
|
162
181
|
async alterTable(name, callback) {
|
|
163
|
-
const
|
|
164
|
-
|
|
182
|
+
for (const operation of collectAlterOperations(name, callback)) {
|
|
183
|
+
await this.record(operation);
|
|
184
|
+
}
|
|
165
185
|
}
|
|
166
186
|
async addColumn(tableName, callback) {
|
|
167
|
-
this.
|
|
187
|
+
await this.record({
|
|
168
188
|
type: 'addColumn',
|
|
169
189
|
tableName,
|
|
170
190
|
column: buildOneColumn(callback),
|
|
171
191
|
});
|
|
172
192
|
}
|
|
173
193
|
async dropColumn(tableName, columnName) {
|
|
174
|
-
this.
|
|
194
|
+
await this.record({
|
|
175
195
|
type: 'dropColumn',
|
|
176
196
|
tableName,
|
|
177
197
|
columnName,
|
|
@@ -179,7 +199,7 @@ export class OperationRecorder {
|
|
|
179
199
|
}
|
|
180
200
|
async alterColumn(tableName, callback) {
|
|
181
201
|
const column = buildOneColumn(callback);
|
|
182
|
-
this.
|
|
202
|
+
await this.record({
|
|
183
203
|
type: 'alterColumn',
|
|
184
204
|
tableName,
|
|
185
205
|
columnName: column.name,
|
|
@@ -187,7 +207,7 @@ export class OperationRecorder {
|
|
|
187
207
|
});
|
|
188
208
|
}
|
|
189
209
|
async renameColumn(tableName, oldName, newName) {
|
|
190
|
-
this.
|
|
210
|
+
await this.record({
|
|
191
211
|
type: 'renameColumn',
|
|
192
212
|
tableName,
|
|
193
213
|
oldName,
|
|
@@ -195,27 +215,27 @@ export class OperationRecorder {
|
|
|
195
215
|
});
|
|
196
216
|
}
|
|
197
217
|
async createIndex(tableName, columns, options) {
|
|
198
|
-
this.
|
|
218
|
+
await this.record(createIndexOperation(tableName, columns, options));
|
|
199
219
|
}
|
|
200
220
|
async dropIndex(tableName, indexName) {
|
|
201
|
-
this.
|
|
221
|
+
await this.record({
|
|
202
222
|
type: 'dropIndex',
|
|
203
223
|
tableName,
|
|
204
224
|
indexName,
|
|
205
225
|
});
|
|
206
226
|
}
|
|
207
227
|
async addForeignKey(tableName, columns, target, options = {}) {
|
|
208
|
-
this.
|
|
228
|
+
await this.record(addForeignKeyOperation(tableName, columns, target, options));
|
|
209
229
|
}
|
|
210
230
|
async dropForeignKey(tableName, constraintName) {
|
|
211
|
-
this.
|
|
231
|
+
await this.record({
|
|
212
232
|
type: 'dropForeignKey',
|
|
213
233
|
tableName,
|
|
214
234
|
constraintName,
|
|
215
235
|
});
|
|
216
236
|
}
|
|
217
237
|
async raw(sql) {
|
|
218
|
-
this.
|
|
238
|
+
await this.record({
|
|
219
239
|
type: 'raw',
|
|
220
240
|
sql,
|
|
221
241
|
});
|
|
@@ -223,9 +243,6 @@ export class OperationRecorder {
|
|
|
223
243
|
getOperations() {
|
|
224
244
|
return [...this.operations];
|
|
225
245
|
}
|
|
226
|
-
recordOperationSync(operation) {
|
|
227
|
-
this.operations.push(operation);
|
|
228
|
-
}
|
|
229
246
|
}
|
|
230
247
|
/**
|
|
231
248
|
* Executes DDL operations via a SQL querier.
|
|
@@ -254,114 +271,9 @@ export class MigrationBuilder extends OperationRecorder {
|
|
|
254
271
|
}
|
|
255
272
|
this.sqlGenerator = generator;
|
|
256
273
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
void this.execute(operation);
|
|
261
|
-
}
|
|
262
|
-
async raw(sql) {
|
|
263
|
-
const operation = {
|
|
264
|
-
type: 'raw',
|
|
265
|
-
sql,
|
|
266
|
-
};
|
|
267
|
-
this.operations.push(operation);
|
|
268
|
-
await this.querier.run(sql);
|
|
269
|
-
}
|
|
270
|
-
// Override async methods to execute immediately
|
|
271
|
-
async createTable(name, callback) {
|
|
272
|
-
const builder = new TableBuilder(name);
|
|
273
|
-
callback(builder);
|
|
274
|
-
const operation = {
|
|
275
|
-
type: 'createTable',
|
|
276
|
-
table: builder.build(),
|
|
277
|
-
};
|
|
278
|
-
this.operations.push(operation);
|
|
279
|
-
await this.execute(operation);
|
|
280
|
-
}
|
|
281
|
-
async dropTable(name, options = {}) {
|
|
282
|
-
const operation = {
|
|
283
|
-
type: 'dropTable',
|
|
284
|
-
tableName: name,
|
|
285
|
-
ifExists: options.ifExists,
|
|
286
|
-
cascade: options.cascade,
|
|
287
|
-
};
|
|
288
|
-
this.operations.push(operation);
|
|
289
|
-
await this.execute(operation);
|
|
290
|
-
}
|
|
291
|
-
async renameTable(oldName, newName) {
|
|
292
|
-
const operation = {
|
|
293
|
-
type: 'renameTable',
|
|
294
|
-
oldName,
|
|
295
|
-
newName,
|
|
296
|
-
};
|
|
297
|
-
this.operations.push(operation);
|
|
298
|
-
await this.execute(operation);
|
|
299
|
-
}
|
|
300
|
-
async addColumn(tableName, callback) {
|
|
301
|
-
const operation = {
|
|
302
|
-
type: 'addColumn',
|
|
303
|
-
tableName,
|
|
304
|
-
column: buildOneColumn(callback),
|
|
305
|
-
};
|
|
306
|
-
this.operations.push(operation);
|
|
307
|
-
await this.execute(operation);
|
|
308
|
-
}
|
|
309
|
-
async dropColumn(tableName, columnName) {
|
|
310
|
-
const operation = {
|
|
311
|
-
type: 'dropColumn',
|
|
312
|
-
tableName,
|
|
313
|
-
columnName,
|
|
314
|
-
};
|
|
315
|
-
this.operations.push(operation);
|
|
316
|
-
await this.execute(operation);
|
|
317
|
-
}
|
|
318
|
-
async alterColumn(tableName, callback) {
|
|
319
|
-
const column = buildOneColumn(callback);
|
|
320
|
-
const operation = {
|
|
321
|
-
type: 'alterColumn',
|
|
322
|
-
tableName,
|
|
323
|
-
columnName: column.name,
|
|
324
|
-
changes: column,
|
|
325
|
-
};
|
|
326
|
-
this.operations.push(operation);
|
|
327
|
-
await this.execute(operation);
|
|
328
|
-
}
|
|
329
|
-
async renameColumn(tableName, oldName, newName) {
|
|
330
|
-
const operation = {
|
|
331
|
-
type: 'renameColumn',
|
|
332
|
-
tableName,
|
|
333
|
-
oldName,
|
|
334
|
-
newName,
|
|
335
|
-
};
|
|
336
|
-
this.operations.push(operation);
|
|
337
|
-
await this.execute(operation);
|
|
338
|
-
}
|
|
339
|
-
async createIndex(tableName, columns, options) {
|
|
340
|
-
const operation = createIndexOperation(tableName, columns, options);
|
|
341
|
-
this.operations.push(operation);
|
|
342
|
-
await this.execute(operation);
|
|
343
|
-
}
|
|
344
|
-
async dropIndex(tableName, indexName) {
|
|
345
|
-
const operation = {
|
|
346
|
-
type: 'dropIndex',
|
|
347
|
-
tableName,
|
|
348
|
-
indexName,
|
|
349
|
-
};
|
|
350
|
-
this.operations.push(operation);
|
|
351
|
-
await this.execute(operation);
|
|
352
|
-
}
|
|
353
|
-
async addForeignKey(tableName, columns, target, options = {}) {
|
|
354
|
-
const operation = addForeignKeyOperation(tableName, columns, target, options);
|
|
355
|
-
this.operations.push(operation);
|
|
356
|
-
await this.execute(operation);
|
|
357
|
-
}
|
|
358
|
-
async dropForeignKey(tableName, constraintName) {
|
|
359
|
-
const operation = {
|
|
360
|
-
type: 'dropForeignKey',
|
|
361
|
-
tableName,
|
|
362
|
-
constraintName,
|
|
363
|
-
};
|
|
364
|
-
this.operations.push(operation);
|
|
274
|
+
/** The recorder's sink, plus the statements the operation turns into. */
|
|
275
|
+
async record(operation) {
|
|
276
|
+
await super.record(operation);
|
|
365
277
|
await this.execute(operation);
|
|
366
278
|
}
|
|
367
279
|
getCreateTableStatements(operation) {
|
|
@@ -449,6 +449,4 @@ export interface IMigrationBuilder {
|
|
|
449
449
|
raw(sql: string): Promise<void>;
|
|
450
450
|
/** Get all recorded operations */
|
|
451
451
|
getOperations(): AnyMigrationOperation[];
|
|
452
|
-
/** Record an operation synchronously */
|
|
453
|
-
recordOperationSync(operation: AnyMigrationOperation): void;
|
|
454
452
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AbstractSqlDialect } from '../../dialect/abstractSqlDialect.js';
|
|
2
|
+
import { IndexDdl } from './indexDdl.js';
|
|
3
|
+
export { IndexDdl } from './indexDdl.js';
|
|
4
|
+
export { MariaIndexDdl, MySqlIndexDdl, MysqlLikeIndexDdl } from './mysqlIndexDdl.js';
|
|
5
|
+
export { CockroachIndexDdl, PgIndexDdl } from './pgIndexDdl.js';
|
|
6
|
+
/**
|
|
7
|
+
* The index DDL a dialect gets, most specific first. `instanceof` rather than `dialectName` so a
|
|
8
|
+
* dialect subclassed by a user keeps its family's DDL, which is what overriding gave it while this
|
|
9
|
+
* lived on the dialect itself. Anything else gets the portable form, which is SQLite's.
|
|
10
|
+
*/
|
|
11
|
+
export declare function indexDdlFor(dialect: AbstractSqlDialect): IndexDdl;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { CockroachDialect } from '../../cockroachdb/cockroachDialect.js';
|
|
2
|
+
import { MysqlLikeSqlDialect } from '../../dialect/mysqlLikeSqlDialect.js';
|
|
3
|
+
import { PgLikeSqlDialect } from '../../dialect/pgLikeSqlDialect.js';
|
|
4
|
+
import { MariaDialect } from '../../maria/mariaDialect.js';
|
|
5
|
+
import { MySqlDialect } from '../../mysql/mysqlDialect.js';
|
|
6
|
+
import { IndexDdl } from './indexDdl.js';
|
|
7
|
+
import { MariaIndexDdl, MySqlIndexDdl, MysqlLikeIndexDdl } from './mysqlIndexDdl.js';
|
|
8
|
+
import { CockroachIndexDdl, PgIndexDdl } from './pgIndexDdl.js';
|
|
9
|
+
export { IndexDdl } from './indexDdl.js';
|
|
10
|
+
export { MariaIndexDdl, MySqlIndexDdl, MysqlLikeIndexDdl } from './mysqlIndexDdl.js';
|
|
11
|
+
export { CockroachIndexDdl, PgIndexDdl } from './pgIndexDdl.js';
|
|
12
|
+
/**
|
|
13
|
+
* The index DDL a dialect gets, most specific first. `instanceof` rather than `dialectName` so a
|
|
14
|
+
* dialect subclassed by a user keeps its family's DDL, which is what overriding gave it while this
|
|
15
|
+
* lived on the dialect itself. Anything else gets the portable form, which is SQLite's.
|
|
16
|
+
*/
|
|
17
|
+
export function indexDdlFor(dialect) {
|
|
18
|
+
if (dialect instanceof CockroachDialect) {
|
|
19
|
+
return new CockroachIndexDdl(dialect);
|
|
20
|
+
}
|
|
21
|
+
if (dialect instanceof PgLikeSqlDialect) {
|
|
22
|
+
return new PgIndexDdl(dialect);
|
|
23
|
+
}
|
|
24
|
+
if (dialect instanceof MySqlDialect) {
|
|
25
|
+
return new MySqlIndexDdl(dialect);
|
|
26
|
+
}
|
|
27
|
+
if (dialect instanceof MariaDialect) {
|
|
28
|
+
return new MariaIndexDdl(dialect);
|
|
29
|
+
}
|
|
30
|
+
if (dialect instanceof MysqlLikeSqlDialect) {
|
|
31
|
+
return new MysqlLikeIndexDdl(dialect);
|
|
32
|
+
}
|
|
33
|
+
return new IndexDdl(dialect);
|
|
34
|
+
}
|
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import type { AbstractSqlDialect } from '../../dialect/abstractSqlDialect.js';
|
|
2
|
+
import type { IndexType } from '../../schema/types.js';
|
|
3
|
+
import { type IndexColumnSchema, type IndexFeature, type IndexJsonArray, type IndexSchema } from '../../type/index.js';
|
|
3
4
|
/**
|
|
4
5
|
* `CREATE INDEX` for SQL dialects: the statement and the fragments each engine spells differently.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* ({@link indexFeatures}), validated once, rather than a throw per feature per dialect.
|
|
6
|
+
* The migrator's rather than the dialect's, since {@link SqlSchemaGenerator} is the only thing that
|
|
7
|
+
* emits DDL - which is what keeps a `CAST(... ARRAY)` table out of every runtime consumer's entry.
|
|
8
|
+
* The form here is the portable one, which SQLite (and so libSQL, Turso and D1) takes verbatim: no
|
|
9
|
+
* access-method clause, no operator classes, no tuning parameters.
|
|
10
10
|
*/
|
|
11
|
-
export declare
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* (and so libSQL, Turso and D1) takes verbatim: no access-method clause, no operator classes, no
|
|
15
|
-
* tuning parameters. Dialects that have those override the fragments below rather than this.
|
|
16
|
-
*/
|
|
11
|
+
export declare class IndexDdl<D extends AbstractSqlDialect = AbstractSqlDialect> {
|
|
12
|
+
protected readonly dialect: D;
|
|
13
|
+
constructor(dialect: D);
|
|
17
14
|
getCreateIndexStatement(tableName: string, index: IndexSchema, opts?: {
|
|
18
15
|
ifNotExists?: boolean;
|
|
19
16
|
}): string;
|
|
@@ -25,20 +22,27 @@ export declare abstract class IndexSqlDialect extends VectorSqlDialect {
|
|
|
25
22
|
protected readonly indexFeatures: ReadonlySet<IndexFeature>;
|
|
26
23
|
private assertIndexFeatures;
|
|
27
24
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
25
|
+
* Index types this dialect spells as a keyword of their own (`FULLTEXT INDEX`, `VECTOR INDEX`)
|
|
26
|
+
* rather than as an access method after the table. One table drives both, so a type that is a
|
|
27
|
+
* keyword here can never also leak out as a ` USING` clause the engine has no word for.
|
|
30
28
|
*/
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
protected indexKeyword(
|
|
29
|
+
protected readonly indexTypeKeywords: ReadonlyMap<IndexType, string>;
|
|
30
|
+
/** The keyword an index type replaces `INDEX` with, or `INDEX` for the types that do not. */
|
|
31
|
+
protected indexKeyword(index: IndexSchema): string;
|
|
34
32
|
/** One index entry: what is indexed, its operator class if any, then its stored order. */
|
|
35
33
|
protected indexColumn(entry: IndexColumnSchema, index: IndexSchema): string;
|
|
36
34
|
/**
|
|
37
35
|
* A quoted column, optionally prefix-limited, or an expression in its own parentheses - the form
|
|
38
36
|
* `((lower("email")))` that MySQL requires and Postgres, CockroachDB and SQLite all accept, so one
|
|
39
|
-
* rendering serves every engine that has expression indexes.
|
|
37
|
+
* rendering serves every engine that has expression indexes. A JSON entry is one of those too, its
|
|
38
|
+
* expression compiled from the path rather than written out by the caller.
|
|
40
39
|
*/
|
|
41
40
|
protected indexColumnTarget(entry: IndexColumnSchema): string;
|
|
41
|
+
/**
|
|
42
|
+
* One key per *element* of the JSON array, which is MySQL's multi-valued index and nothing else's -
|
|
43
|
+
* every other dialect refuses `jsonArray` in {@link assertIndexFeatures} and never reaches this.
|
|
44
|
+
*/
|
|
45
|
+
protected jsonArrayIndexExpr(_escapedColumn: string, _json: IndexJsonArray): string;
|
|
42
46
|
/** Postgres-wire dialects put a vector or user-declared operator class here. */
|
|
43
47
|
protected indexColumnOpsClass(_entry: IndexColumnSchema, _index: IndexSchema): string;
|
|
44
48
|
/** `ASC` is every engine's default, so only `DESC` is worth emitting. */
|