uql-orm 0.55.0 → 0.57.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/README.md +1 -1
- package/dist/browser/uql-browser.min.js +2 -2
- package/dist/browser/uql-browser.min.js.map +4 -4
- package/dist/bunSql/bunSql.util.js +1 -1
- package/dist/cockroachdb/cockroachDialect.d.ts +5 -2
- package/dist/cockroachdb/cockroachDialect.js +2 -10
- package/dist/d1/d1SqliteDialect.d.ts +1 -0
- package/dist/d1/d1SqliteDialect.js +2 -0
- package/dist/dialect/abstractSqlDialect.d.ts +195 -32
- package/dist/dialect/abstractSqlDialect.js +406 -199
- package/dist/dialect/aliases.d.ts +10 -7
- package/dist/dialect/aliases.js +12 -7
- package/dist/dialect/hydrateColumn.d.ts +8 -2
- package/dist/dialect/hydrateColumn.js +33 -1
- package/dist/dialect/jsonSql.d.ts +13 -5
- package/dist/dialect/jsonSql.js +24 -7
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +30 -2
- package/dist/dialect/mysqlLikeSqlDialect.js +58 -7
- package/dist/dialect/pgLikeSqlDialect.d.ts +20 -20
- package/dist/dialect/pgLikeSqlDialect.js +25 -50
- package/dist/dialect/pgVectorMetrics.d.ts +13 -0
- package/dist/dialect/pgVectorMetrics.js +17 -0
- package/dist/dialect/queryContext.d.ts +3 -7
- package/dist/dialect/queryContext.js +13 -8
- package/dist/dialect/queryJoins.d.ts +8 -4
- package/dist/dialect/queryJoins.js +27 -15
- package/dist/dialect/vectorSqlDialect.d.ts +2 -2
- package/dist/dialect/vectorSqlDialect.js +2 -3
- package/dist/entity/index.d.ts +1 -1
- package/dist/entity/index.js +1 -1
- package/dist/entity/metadata/definition.d.ts +4 -2
- package/dist/entity/metadata/definition.js +27 -29
- package/dist/maria/mariaDialect.d.ts +13 -6
- package/dist/maria/mariaDialect.js +29 -9
- package/dist/migrate/builder/splitSqlStatements.js +2 -2
- package/dist/migrate/cli.d.ts +2 -3
- package/dist/migrate/cli.js +4 -11
- package/dist/migrate/codegen/fieldOptionsSource.js +1 -1
- package/dist/migrate/ddl/index.d.ts +1 -5
- package/dist/migrate/ddl/index.js +14 -25
- package/dist/migrate/ddl/indexDdl.d.ts +11 -2
- package/dist/migrate/ddl/indexDdl.js +17 -1
- package/dist/migrate/ddl/mssqlIndexDdl.d.ts +10 -0
- package/dist/migrate/ddl/mssqlIndexDdl.js +10 -0
- package/dist/migrate/ddl/mysqlIndexDdl.d.ts +10 -17
- package/dist/migrate/ddl/mysqlIndexDdl.js +16 -27
- package/dist/migrate/ddl/pgIndexDdl.d.ts +18 -3
- package/dist/migrate/ddl/pgIndexDdl.js +29 -3
- package/dist/migrate/drift/driftDetector.js +21 -8
- package/dist/migrate/generator/mongoSchemaGenerator.js +1 -1
- package/dist/migrate/introspection/baseSqlIntrospector.d.ts +1 -1
- package/dist/migrate/introspection/baseSqlIntrospector.js +65 -76
- package/dist/migrate/introspection/mssqlIntrospector.js +2 -1
- package/dist/migrate/introspection/mysqlIntrospector.js +5 -8
- package/dist/migrate/introspection/sqliteIntrospector.js +2 -5
- package/dist/migrate/migrator.d.ts +7 -4
- package/dist/migrate/migrator.js +9 -14
- package/dist/migrate/schemaGenerator.d.ts +3 -3
- package/dist/migrate/schemaGenerator.js +7 -13
- package/dist/migrate/schemaGeneratorAsync.d.ts +2 -3
- package/dist/mongo/mongoDialect.d.ts +31 -18
- package/dist/mongo/mongoDialect.js +147 -108
- package/dist/mongo/mongodbQuerier.d.ts +10 -17
- package/dist/mongo/mongodbQuerier.js +34 -108
- package/dist/mssql/mssqlDialect.d.ts +16 -0
- package/dist/mssql/mssqlDialect.js +26 -4
- package/dist/mysql/mysqlDialect.d.ts +2 -0
- package/dist/mysql/mysqlDialect.js +4 -0
- package/dist/querier/abstractQuerier.d.ts +20 -36
- package/dist/querier/abstractQuerier.js +44 -143
- package/dist/querier/abstractQuerierPool.d.ts +2 -2
- package/dist/querier/abstractSqlQuerier.d.ts +11 -22
- package/dist/querier/abstractSqlQuerier.js +49 -53
- package/dist/schema/canonicalType.js +4 -6
- package/dist/schema/dependencyGraph.js +2 -4
- package/dist/schema/indexDifferences.js +5 -5
- package/dist/schema/schemaASTBuilder.js +34 -12
- package/dist/schema/schemaASTDiffer.d.ts +10 -2
- package/dist/schema/schemaASTDiffer.js +17 -16
- package/dist/schema/types.d.ts +1 -1
- package/dist/sqlite/sqliteDialect.d.ts +20 -1
- package/dist/sqlite/sqliteDialect.js +40 -8
- package/dist/turso/tursoDialect.d.ts +2 -0
- package/dist/turso/tursoDialect.js +2 -0
- package/dist/type/config.d.ts +2 -2
- package/dist/type/dialect.d.ts +4 -5
- package/dist/type/entity.d.ts +2 -1
- package/dist/type/migratorDialect.d.ts +4 -0
- package/dist/type/querier.d.ts +6 -6
- package/dist/type/query.d.ts +25 -48
- package/dist/type/query.js +10 -5
- package/dist/type/queryAggregate.d.ts +10 -10
- package/dist/type/queryAggregate.js +1 -1
- package/dist/type/universalQuerier.d.ts +4 -4
- package/dist/util/dialect.util.d.ts +8 -2
- package/dist/util/dialect.util.js +19 -0
- package/dist/util/field.util.d.ts +5 -0
- package/dist/util/field.util.js +19 -0
- package/dist/util/logger.d.ts +10 -1
- package/dist/util/logger.js +18 -0
- package/dist/util/object.util.d.ts +4 -0
- package/dist/util/object.util.js +8 -0
- package/dist/util/relationQuery.util.d.ts +15 -68
- package/dist/util/relationQuery.util.js +35 -83
- package/dist/util/rowKey.util.d.ts +1 -11
- package/dist/util/rowKey.util.js +1 -13
- package/package.json +1 -1
- package/dist/querier/relationCount.d.ts +0 -16
- package/dist/querier/relationCount.js +0 -121
|
@@ -10,14 +10,14 @@ export class SqlQueryContext {
|
|
|
10
10
|
statement;
|
|
11
11
|
sqlChunks = [];
|
|
12
12
|
params;
|
|
13
|
-
|
|
13
|
+
tableAliases = new Set();
|
|
14
14
|
/**
|
|
15
15
|
* @param dialect The SQL dialect used to determine how values should be formatted as placeholders.
|
|
16
16
|
* @param params An existing values array to bind into instead of a fresh one - shared by a
|
|
17
17
|
* fragment context built via {@link AbstractSqlDialect.buildFragment}, so a bound value's
|
|
18
18
|
* placeholder is numbered correctly against the real query from the moment it's added, rather
|
|
19
19
|
* than needing to be reconciled after the fact.
|
|
20
|
-
* @param statement The context this one renders a fragment of, which owns the
|
|
20
|
+
* @param statement The context this one renders a fragment of, which owns the claimed aliases: a
|
|
21
21
|
* fragment is part of one statement, so its aliases have to be unique across the whole of it.
|
|
22
22
|
*/
|
|
23
23
|
constructor(dialect, params = [], statement) {
|
|
@@ -62,12 +62,17 @@ export class SqlQueryContext {
|
|
|
62
62
|
this.params.push(...values.map((v) => this.dialect.normalizeValue(v)));
|
|
63
63
|
return this;
|
|
64
64
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
claimAlias(name, parent) {
|
|
66
|
+
if (this.statement) {
|
|
67
|
+
return this.statement.claimAlias(name, parent);
|
|
68
|
+
}
|
|
69
|
+
const reserved = parent?.toLowerCase();
|
|
70
|
+
let alias = name;
|
|
71
|
+
for (let n = 2; this.tableAliases.has(alias.toLowerCase()) || alias.toLowerCase() === reserved; n++) {
|
|
72
|
+
alias = `${name}_${n}`;
|
|
73
|
+
}
|
|
74
|
+
this.tableAliases.add(alias.toLowerCase());
|
|
75
|
+
return alias;
|
|
71
76
|
}
|
|
72
77
|
/**
|
|
73
78
|
* Returns the complete SQL query string by joining all accumulated chunks.
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { EntityMeta, Query, QuerySortMap, RelationMeta, Type } from '../type/index.js';
|
|
2
|
-
import { type RelationQuery } from '../util/index.js';
|
|
1
|
+
import type { EntityMeta, Query, QuerySortMap, RelationMeta, RelationQuery, Type } from '../type/index.js';
|
|
3
2
|
/**
|
|
4
3
|
* One relation a statement joins, keyed by the alias its columns are addressed by (`tax`,
|
|
5
4
|
* `tax.category`). `projected` tells a `$populate` join, whose columns are selected, from one only
|
|
@@ -8,8 +7,10 @@ import { type RelationQuery } from '../util/index.js';
|
|
|
8
7
|
export type QueryJoin = {
|
|
9
8
|
/** The relation key on its parent, which is how MongoDB names the field a `$lookup` adds. */
|
|
10
9
|
readonly key: string;
|
|
11
|
-
/** Dotted path from the queried entity, which is
|
|
10
|
+
/** Dotted path from the queried entity, which is what a joined row's columns answer under. */
|
|
12
11
|
readonly path: string;
|
|
12
|
+
/** The alias the statement reads it through: its path, unless another table of the statement took it. */
|
|
13
|
+
readonly alias: string;
|
|
13
14
|
readonly entity: Type<object>;
|
|
14
15
|
readonly meta: EntityMeta<object>;
|
|
15
16
|
readonly relation: RelationMeta;
|
|
@@ -38,14 +39,17 @@ export type QuerySortOptions = {
|
|
|
38
39
|
* related column needs that relation joined just as much as selecting it does. The two sources meet
|
|
39
40
|
* here, so the columns, the `ORDER BY` and the row lock cannot disagree about what is in the
|
|
40
41
|
* statement. `$sort` contributes to-one relations only; the rest is rejected where it is rendered.
|
|
42
|
+
* `claimAlias` names each join's table, parents first.
|
|
41
43
|
*/
|
|
42
|
-
export declare function resolveQueryJoins<E>(meta: EntityMeta<E>, q: Query<E
|
|
44
|
+
export declare function resolveQueryJoins<E>(meta: EntityMeta<E>, q: Query<E>, claimAlias?: (path: string) => string): QueryJoins;
|
|
43
45
|
/**
|
|
44
46
|
* Whether a join drops parents that have no match, which is the one thing a join does to *how many*
|
|
45
47
|
* rows a read returns rather than how wide they are. A count that skips the joins has to be told, or
|
|
46
48
|
* it counts the parents the read will never hand back.
|
|
47
49
|
*/
|
|
48
50
|
export declare function hasRequiredJoin<E>(meta: EntityMeta<E>, q: Query<E>): boolean;
|
|
51
|
+
/** Whether a statement aggregates a relation's rows: a to-many off its own row, or off a row it joins. */
|
|
52
|
+
export declare function aggregatesRelations<E>(meta: EntityMeta<E>, q: Query<E>): boolean;
|
|
49
53
|
/**
|
|
50
54
|
* The join an ordering may address at `path`, with the relation's own sort map, or why it may not.
|
|
51
55
|
* Every backend answers this the same way - a to-many has no single value to order by, a relation
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import { getMeta } from '../entity/index.js';
|
|
2
|
-
import { getKeys, getRelationRequestSummary, isToManyRelation, parseRelationAtKey
|
|
1
|
+
import { getMeta, relationOf } from '../entity/index.js';
|
|
2
|
+
import { getKeys, getRelationRequestSummary, isToManyRelation, parseRelationAtKey } from '../util/index.js';
|
|
3
3
|
export const NO_JOINS = new Map();
|
|
4
4
|
/**
|
|
5
5
|
* What the statement joins, from the whole query rather than from `$populate` alone: ordering by a
|
|
6
6
|
* related column needs that relation joined just as much as selecting it does. The two sources meet
|
|
7
7
|
* here, so the columns, the `ORDER BY` and the row lock cannot disagree about what is in the
|
|
8
8
|
* statement. `$sort` contributes to-one relations only; the rest is rejected where it is rendered.
|
|
9
|
+
* `claimAlias` names each join's table, parents first.
|
|
9
10
|
*/
|
|
10
|
-
export function resolveQueryJoins(meta, q) {
|
|
11
|
+
export function resolveQueryJoins(meta, q, claimAlias = (path) => path) {
|
|
11
12
|
if (!q.$populate && !q.$sort) {
|
|
12
13
|
return NO_JOINS;
|
|
13
14
|
}
|
|
14
15
|
const joins = new Map();
|
|
15
|
-
addPopulateJoins(joins, meta, q.$populate);
|
|
16
|
-
addSortJoins(joins, meta, q.$sort);
|
|
16
|
+
addPopulateJoins(joins, claimAlias, meta, q.$populate);
|
|
17
|
+
addSortJoins(joins, claimAlias, meta, q.$sort);
|
|
17
18
|
return joins;
|
|
18
19
|
}
|
|
19
20
|
/**
|
|
@@ -29,7 +30,19 @@ export function hasRequiredJoin(meta, q) {
|
|
|
29
30
|
}
|
|
30
31
|
return false;
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
+
/** Whether a statement aggregates a relation's rows: a to-many off its own row, or off a row it joins. */
|
|
34
|
+
export function aggregatesRelations(meta, q) {
|
|
35
|
+
if (getRelationRequestSummary(meta, q.$populate).toManyKeys.length) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
for (const join of resolveQueryJoins(meta, q).values()) {
|
|
39
|
+
if (getRelationRequestSummary(join.meta, join.query.$populate).toManyKeys.length) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
function addJoin(joins, claimAlias, parent, key, relation, query, required, projected) {
|
|
33
46
|
const path = parent ? `${parent.path}.${key}` : key;
|
|
34
47
|
const existing = joins.get(path);
|
|
35
48
|
// `$populate` runs first, so an already-joined relation keeps its columns and its `$required`
|
|
@@ -41,6 +54,7 @@ function addJoin(joins, parent, key, relation, query, required, projected) {
|
|
|
41
54
|
const join = {
|
|
42
55
|
key,
|
|
43
56
|
path,
|
|
57
|
+
alias: claimAlias(path),
|
|
44
58
|
entity,
|
|
45
59
|
meta: getMeta(entity),
|
|
46
60
|
relation,
|
|
@@ -52,17 +66,15 @@ function addJoin(joins, parent, key, relation, query, required, projected) {
|
|
|
52
66
|
joins.set(path, join);
|
|
53
67
|
return join;
|
|
54
68
|
}
|
|
55
|
-
function addPopulateJoins(joins, meta, populate, parent) {
|
|
69
|
+
function addPopulateJoins(joins, claimAlias, meta, populate, parent) {
|
|
56
70
|
for (const key of getRelationRequestSummary(meta, populate).joinableKeys) {
|
|
57
|
-
const relation = meta
|
|
58
|
-
if (!relation)
|
|
59
|
-
continue;
|
|
71
|
+
const relation = relationOf(meta, key);
|
|
60
72
|
const { query, required } = parseRelationAtKey(key, populate);
|
|
61
|
-
const join = addJoin(joins, parent, key, relation, query, required, true);
|
|
62
|
-
addPopulateJoins(joins, join.meta, query.$populate, join);
|
|
73
|
+
const join = addJoin(joins, claimAlias, parent, key, relation, query, required, true);
|
|
74
|
+
addPopulateJoins(joins, claimAlias, join.meta, query.$populate, join);
|
|
63
75
|
}
|
|
64
76
|
}
|
|
65
|
-
function addSortJoins(joins, meta, sort, parent) {
|
|
77
|
+
function addSortJoins(joins, claimAlias, meta, sort, parent) {
|
|
66
78
|
if (!sort) {
|
|
67
79
|
return;
|
|
68
80
|
}
|
|
@@ -74,8 +86,8 @@ function addSortJoins(joins, meta, sort, parent) {
|
|
|
74
86
|
if (!relation || isToManyRelation(relation) || !isSortMap(value)) {
|
|
75
87
|
continue;
|
|
76
88
|
}
|
|
77
|
-
const join = addJoin(joins, parent, key, relation, {}, false, false);
|
|
78
|
-
addSortJoins(joins, join.meta, value, join);
|
|
89
|
+
const join = addJoin(joins, claimAlias, parent, key, relation, {}, false, false);
|
|
90
|
+
addSortJoins(joins, claimAlias, join.meta, value, join);
|
|
79
91
|
}
|
|
80
92
|
}
|
|
81
93
|
/**
|
|
@@ -78,8 +78,8 @@ export declare abstract class VectorSqlDialect extends AbstractDialect {
|
|
|
78
78
|
*/
|
|
79
79
|
supportedVectorType(cast: VectorCast): VectorCast;
|
|
80
80
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
81
|
+
* The distance a vector `$sort` projects, which the projection names after `$project`. Delegates to
|
|
82
|
+
* `appendVectorSort` so each dialect's distance syntax is written once.
|
|
83
83
|
*/
|
|
84
84
|
protected appendVectorProjection<E>(ctx: QueryContext, meta: EntityMeta<E>, key: string, search: QueryVectorSearch): void;
|
|
85
85
|
/**
|
|
@@ -96,8 +96,8 @@ export class VectorSqlDialect extends AbstractDialect {
|
|
|
96
96
|
return this.hasNarrowVectorTypes ? cast : 'vector';
|
|
97
97
|
}
|
|
98
98
|
/**
|
|
99
|
-
*
|
|
100
|
-
*
|
|
99
|
+
* The distance a vector `$sort` projects, which the projection names after `$project`. Delegates to
|
|
100
|
+
* `appendVectorSort` so each dialect's distance syntax is written once.
|
|
101
101
|
*/
|
|
102
102
|
appendVectorProjection(ctx, meta, key, search) {
|
|
103
103
|
const alias = search.$project;
|
|
@@ -108,7 +108,6 @@ export class VectorSqlDialect extends AbstractDialect {
|
|
|
108
108
|
throw new TypeError(`$project '${alias}' collides with a field of '${entityName(meta)}'`);
|
|
109
109
|
}
|
|
110
110
|
this.appendVectorSort(ctx, meta, key, search);
|
|
111
|
-
ctx.append(` AS ${this.escapeId(alias)}`);
|
|
112
111
|
}
|
|
113
112
|
/**
|
|
114
113
|
* The distance expression, in whichever of the two shapes this dialect spells it. One method for
|
package/dist/entity/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export * from './decorator/entity.js';
|
|
2
2
|
export * from './decorator/members.js';
|
|
3
|
-
export { defineEntity, defineField, defineFilter, defineHook, defineId, defineIndex, defineRelation, getEntities, getMeta, removeEntity, assertSoleId, fieldOf, idOf, namesKey, soleIdOf, } from './metadata/definition.js';
|
|
3
|
+
export { defineEntity, defineField, defineFilter, defineHook, defineId, defineIndex, defineRelation, getEntities, getMeta, removeEntity, assertSoleId, fieldOf, idOf, namesKey, relationOf, soleIdOf, } from './metadata/definition.js';
|
package/dist/entity/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export * from './decorator/entity.js';
|
|
2
2
|
export * from './decorator/members.js';
|
|
3
|
-
export { defineEntity, defineField, defineFilter, defineHook, defineId, defineIndex, defineRelation, getEntities, getMeta, removeEntity, assertSoleId, fieldOf, idOf, namesKey, soleIdOf, } from './metadata/definition.js';
|
|
3
|
+
export { defineEntity, defineField, defineFilter, defineHook, defineId, defineIndex, defineRelation, getEntities, getMeta, removeEntity, assertSoleId, fieldOf, idOf, namesKey, relationOf, soleIdOf, } from './metadata/definition.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EntityData, EntityIndexInput, EntityMembers, EntityMeta, EntityOptions, FieldKey, FieldMeta, FieldOptions, FilterOptions, HookEvent, IdKey, RelationOptions, Type, WrittenId } from '../../type/index.js';
|
|
1
|
+
import type { EntityData, EntityIndexInput, EntityMembers, EntityMeta, EntityOptions, FieldKey, FieldMeta, FieldOptions, FilterOptions, HookEvent, IdKey, RelationKey, RelationMeta, RelationOptions, Type, WrittenId } from '../../type/index.js';
|
|
2
2
|
export declare function defineField<E>(entity: Type<E>, key: string, opts?: FieldOptions): EntityMeta<E>;
|
|
3
3
|
export declare function defineId<E>(entity: Type<E>, key: string, opts: FieldOptions): EntityMeta<E>;
|
|
4
4
|
export declare function defineRelation<E>(entity: Type<E>, key: string, opts: RelationOptions): EntityMeta<E>;
|
|
@@ -31,7 +31,9 @@ export declare function assertSoleId<E>(meta: EntityMeta<E>, what: string): void
|
|
|
31
31
|
/** The entity's one primary key, for a path that cannot express a composite. See {@link assertSoleId}. */
|
|
32
32
|
export declare function soleIdOf<E>(meta: EntityMeta<E>, what: string): IdKey<E>;
|
|
33
33
|
/** The field `key` names, for a caller that took `key` from the metadata itself. */
|
|
34
|
-
export declare function fieldOf<E>(meta: EntityMeta<E>, key:
|
|
34
|
+
export declare function fieldOf<E>(meta: EntityMeta<E>, key: FieldKey<E>): FieldMeta;
|
|
35
|
+
/** The relation `key` names, for a caller that took `key` from the metadata itself. */
|
|
36
|
+
export declare function relationOf<E>(meta: EntityMeta<E>, key: RelationKey<E>): RelationMeta;
|
|
35
37
|
/**
|
|
36
38
|
* Whether the caller named every column of the row's primary key, so {@link idOf} can name the row.
|
|
37
39
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SOFT_DELETE_FILTER } from '../../type/index.js';
|
|
2
2
|
import { isInlinedExpression } from '../../util/field.util.js';
|
|
3
|
-
import { entityName, fieldOptionConflict, getKeys, ddlText, hasKeys, isToManyRelation, lowerFirst, normalizeIndexColumn, upperFirst, } from '../../util/index.js';
|
|
3
|
+
import { entityName, fieldOptionConflict, getKeys, ddlText, hasKeys, isToManyRelation, lowerFirst, normalizeIndexColumn, upperFirst, definedEntries, } from '../../util/index.js';
|
|
4
4
|
import { ownRegistrations } from '../decorator/bag.js';
|
|
5
5
|
/**
|
|
6
6
|
* A map held on `globalThis` through the global symbol registry, so a single one survives multiple
|
|
@@ -95,9 +95,7 @@ export function defineFilter(entity, name, opts) {
|
|
|
95
95
|
* API converge on one registration path before anything is finalized.
|
|
96
96
|
*/
|
|
97
97
|
export function applyMembers(entity, specs) {
|
|
98
|
-
for (const [key, spec] of
|
|
99
|
-
if (!spec)
|
|
100
|
-
continue;
|
|
98
|
+
for (const [key, spec] of definedEntries(specs?.fields ?? {})) {
|
|
101
99
|
if (spec.isId) {
|
|
102
100
|
defineId(entity, key, spec);
|
|
103
101
|
}
|
|
@@ -105,12 +103,11 @@ export function applyMembers(entity, specs) {
|
|
|
105
103
|
defineField(entity, key, spec);
|
|
106
104
|
}
|
|
107
105
|
}
|
|
108
|
-
for (const [key, spec] of
|
|
109
|
-
|
|
110
|
-
defineRelation(entity, key, spec);
|
|
106
|
+
for (const [key, spec] of definedEntries(specs?.relations ?? {})) {
|
|
107
|
+
defineRelation(entity, key, spec);
|
|
111
108
|
}
|
|
112
|
-
for (const [event, methodNames] of
|
|
113
|
-
for (const methodName of methodNames
|
|
109
|
+
for (const [event, methodNames] of definedEntries(specs?.hooks ?? {})) {
|
|
110
|
+
for (const methodName of methodNames) {
|
|
114
111
|
defineHook(entity, methodName, event);
|
|
115
112
|
}
|
|
116
113
|
}
|
|
@@ -143,9 +140,8 @@ export function defineEntity(entity, opts = {}) {
|
|
|
143
140
|
for (const index of opts.indexes ?? []) {
|
|
144
141
|
defineIndex(entity, index);
|
|
145
142
|
}
|
|
146
|
-
for (const [name, filter] of
|
|
147
|
-
|
|
148
|
-
defineFilter(entity, name, filter);
|
|
143
|
+
for (const [name, filter] of definedEntries(opts.filters ?? {})) {
|
|
144
|
+
defineFilter(entity, name, filter);
|
|
149
145
|
}
|
|
150
146
|
if (!hasKeys(meta.fields)) {
|
|
151
147
|
throw TypeError(`'${entity.name}' must have fields`);
|
|
@@ -227,6 +223,14 @@ export function fieldOf(meta, key) {
|
|
|
227
223
|
}
|
|
228
224
|
return field;
|
|
229
225
|
}
|
|
226
|
+
/** The relation `key` names, for a caller that took `key` from the metadata itself. */
|
|
227
|
+
export function relationOf(meta, key) {
|
|
228
|
+
const relation = meta.relations[key];
|
|
229
|
+
if (!relation) {
|
|
230
|
+
throw new TypeError(`'${meta.entity.name}' has no relation '${key}'`);
|
|
231
|
+
}
|
|
232
|
+
return relation;
|
|
233
|
+
}
|
|
230
234
|
/**
|
|
231
235
|
* Whether the caller named every column of the row's primary key, so {@link idOf} can name the row.
|
|
232
236
|
*
|
|
@@ -303,11 +307,9 @@ export function getMeta(entity) {
|
|
|
303
307
|
return fillRelations(meta);
|
|
304
308
|
}
|
|
305
309
|
function fillRelations(meta) {
|
|
306
|
-
for (const relKey
|
|
310
|
+
for (const [relKey, relation] of definedEntries(meta.relations)) {
|
|
307
311
|
// The authored view: `mappedBy` may still be the callback and `references` unset until this settles them.
|
|
308
|
-
const relOpts =
|
|
309
|
-
if (!relOpts)
|
|
310
|
-
continue;
|
|
312
|
+
const relOpts = relation;
|
|
311
313
|
const at = `'${meta.entity.name}.${relKey}'`;
|
|
312
314
|
if (relOpts.mappedBy) {
|
|
313
315
|
fillInverseSide(at, meta, relOpts);
|
|
@@ -335,9 +337,9 @@ function fillRelations(meta) {
|
|
|
335
337
|
function fillOwningSide(at, meta, relKey, relOpts) {
|
|
336
338
|
const relMeta = ensureMeta(relOpts.entity());
|
|
337
339
|
if (relOpts.through) {
|
|
338
|
-
// Both columns live on the junction, whatever the cardinality: `
|
|
339
|
-
//
|
|
340
|
-
//
|
|
340
|
+
// Both columns live on the junction, whatever the cardinality: `deleteRelations` and every dialect
|
|
341
|
+
// read them as junction columns. A composite key contributes one pair per column of it, which is
|
|
342
|
+
// what makes the join address a whole key rather than part.
|
|
341
343
|
relOpts.references = [
|
|
342
344
|
...meta.ids.map((key) => ({ local: junctionColumn(meta, key), foreign: key })),
|
|
343
345
|
...relMeta.ids.map((key) => ({ local: junctionColumn(relMeta, key), foreign: key })),
|
|
@@ -363,7 +365,7 @@ function fillOwningSide(at, meta, relKey, relOpts) {
|
|
|
363
365
|
for (const { local, foreign } of relOpts.references) {
|
|
364
366
|
fields[local] ??= {
|
|
365
367
|
name: local,
|
|
366
|
-
type: relMeta.
|
|
368
|
+
type: fieldOf(relMeta, foreign).type ?? Number,
|
|
367
369
|
references: relOpts.entity,
|
|
368
370
|
referencedKey: foreign,
|
|
369
371
|
typeFromReference: true,
|
|
@@ -413,9 +415,8 @@ function fillInverseSide(at, meta, relOpts) {
|
|
|
413
415
|
* own cardinality and `cascade`.
|
|
414
416
|
*/
|
|
415
417
|
function fillForeignKeyRelations(meta) {
|
|
416
|
-
const joined = new Set(
|
|
417
|
-
for (const fieldKey of
|
|
418
|
-
const references = meta.fields[fieldKey]?.references;
|
|
418
|
+
const joined = new Set(definedEntries(meta.relations).flatMap(([, relation]) => relation.references.map(({ local }) => local)));
|
|
419
|
+
for (const [fieldKey, { references }] of definedEntries(meta.fields)) {
|
|
419
420
|
if (!references || joined.has(fieldKey))
|
|
420
421
|
continue;
|
|
421
422
|
const target = ensureMeta(references());
|
|
@@ -445,7 +446,7 @@ function fillForeignKeyRelations(meta) {
|
|
|
445
446
|
}
|
|
446
447
|
/** `<entityName><IdColumn>`, not the `<relationKey>Id` an owning to-one derives: a junction row has no relation key to borrow from. */
|
|
447
448
|
function junctionColumn(meta, idKey) {
|
|
448
|
-
return lowerFirst(entityName(meta)) + upperFirst(meta.
|
|
449
|
+
return lowerFirst(entityName(meta)) + upperFirst(fieldOf(meta, idKey).name ?? idKey);
|
|
449
450
|
}
|
|
450
451
|
/** A callback only reads one property off the key map, and that property is the key, so one serves every entity. */
|
|
451
452
|
const RELATION_KEY_MAP = new Proxy({}, { get: (_, key) => key });
|
|
@@ -478,11 +479,8 @@ function extendMeta(target, source) {
|
|
|
478
479
|
if (source.hooks) {
|
|
479
480
|
if (!target.hooks)
|
|
480
481
|
target.hooks = {};
|
|
481
|
-
for (const event of
|
|
482
|
-
|
|
483
|
-
if (sourceList?.length) {
|
|
484
|
-
target.hooks[event] = [...sourceList, ...(target.hooks[event] ?? [])];
|
|
485
|
-
}
|
|
482
|
+
for (const [event, sourceList] of definedEntries(source.hooks)) {
|
|
483
|
+
target.hooks[event] = [...sourceList, ...(target.hooks[event] ?? [])];
|
|
486
484
|
}
|
|
487
485
|
}
|
|
488
486
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { type RelationRows } from '../dialect/abstractSqlDialect.js';
|
|
1
2
|
import { MysqlLikeSqlDialect } from '../dialect/mysqlLikeSqlDialect.js';
|
|
2
|
-
import type { DialectFeatures, EntityMeta, FieldOptions, Query, QueryContext,
|
|
3
|
+
import type { DialectFeatures, EntityMeta, FieldOptions, Query, QueryContext, Type, VectorDistance, VectorMetric } from '../type/index.js';
|
|
3
4
|
export declare class MariaDialect extends MysqlLikeSqlDialect {
|
|
4
5
|
readonly dialectName = "mariadb";
|
|
5
6
|
readonly insertIdSource = "returning";
|
|
@@ -10,6 +11,11 @@ export declare class MariaDialect extends MysqlLikeSqlDialect {
|
|
|
10
11
|
* and `CREATE INDEX` takes `IF NOT EXISTS` - which MySQL's grammar has no place for.
|
|
11
12
|
*/
|
|
12
13
|
protected readonly featureOverrides: Partial<DialectFeatures>;
|
|
14
|
+
/**
|
|
15
|
+
* A derived table here reads no column of the statement around it, so the aggregate reads the
|
|
16
|
+
* related table itself, and orders and pages inside `JSON_ARRAYAGG`, which takes both.
|
|
17
|
+
*/
|
|
18
|
+
protected appendRelationArray(ctx: QueryContext, { entity, query, alias, joins }: RelationRows): void;
|
|
13
19
|
protected upsertReturning<E>(meta: EntityMeta<E>): string;
|
|
14
20
|
/**
|
|
15
21
|
* MariaDB supports neither MySQL's `->`/`->>` shorthand nor the base's chained form. `JSON_VALUE`
|
|
@@ -36,12 +42,13 @@ export declare class MariaDialect extends MysqlLikeSqlDialect {
|
|
|
36
42
|
*/
|
|
37
43
|
protected appendVectorValue(ctx: QueryContext, value: readonly unknown[]): void;
|
|
38
44
|
/**
|
|
39
|
-
* `
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* from `vectorTuningStatements`, which is Postgres's `SET LOCAL` shape.
|
|
45
|
+
* `mhnsw_ef_search` too, where a vector search is tuned. A setting scoped to one statement needs
|
|
46
|
+
* neither a transaction nor a restore, and cannot leak to the next query on this pooled connection,
|
|
47
|
+
* which is why the tuning is not `vectorTuningStatements`, Postgres's `SET LOCAL` shape.
|
|
43
48
|
*/
|
|
44
|
-
|
|
49
|
+
protected statementSettings<E>(entity: Type<E>, q: Query<E>): string[];
|
|
50
|
+
/** `SET STATEMENT ... FOR`, which scopes a variable to the statement it prefixes. */
|
|
51
|
+
protected applySettings(sql: string, settings: readonly string[]): string;
|
|
45
52
|
/** The reverse: selecting a `VECTOR` column raw yields that blob, so it is read back as text. */
|
|
46
53
|
protected selectFieldExpr(escapedColumn: string, field: FieldOptions): string;
|
|
47
54
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { relationTermKey } from '../dialect/abstractSqlDialect.js';
|
|
1
2
|
import { jsonPath } from '../dialect/jsonSql.js';
|
|
2
3
|
import { MysqlLikeSqlDialect } from '../dialect/mysqlLikeSqlDialect.js';
|
|
3
4
|
import { getMeta } from '../entity/index.js';
|
|
@@ -18,6 +19,24 @@ export class MariaDialect extends MysqlLikeSqlDialect {
|
|
|
18
19
|
vectorIndexRequiresNotNull: true,
|
|
19
20
|
indexIfNotExists: true,
|
|
20
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* A derived table here reads no column of the statement around it, so the aggregate reads the
|
|
24
|
+
* related table itself, and orders and pages inside `JSON_ARRAYAGG`, which takes both.
|
|
25
|
+
*/
|
|
26
|
+
appendRelationArray(ctx, { entity, query, alias, joins }) {
|
|
27
|
+
const meta = getMeta(entity);
|
|
28
|
+
const terms = this.projection(ctx, entity, query, { prefix: alias, json: true }, joins);
|
|
29
|
+
const sortOpts = { prefix: alias, joins, distinct: query.$distinct };
|
|
30
|
+
const order = this.buildFragment(ctx, (fragmentCtx) => this.sort(fragmentCtx, entity, query.$sort, sortOpts));
|
|
31
|
+
const page = this.buildFragment(ctx, (fragmentCtx) => this.pager(fragmentCtx, query));
|
|
32
|
+
const from = this.buildFragment(ctx, (fragmentCtx) => {
|
|
33
|
+
this.selectRelationJoins(fragmentCtx, meta, alias, joins);
|
|
34
|
+
this.where(fragmentCtx, entity, query.$where, { prefix: alias });
|
|
35
|
+
});
|
|
36
|
+
const object = this.jsonObject(terms.map((term) => [relationTermKey(term), term.sql]));
|
|
37
|
+
const rows = `${query.$distinct ? 'DISTINCT ' : ''}${object}${order}${page}`;
|
|
38
|
+
ctx.append(`COALESCE((SELECT JSON_ARRAYAGG(${rows}) FROM ${this.tableRef(meta, alias).ref}${from}), JSON_ARRAY())`);
|
|
39
|
+
}
|
|
21
40
|
upsertReturning(meta) {
|
|
22
41
|
const returning = this.returningId(meta);
|
|
23
42
|
return returning ? ` ${returning}` : '';
|
|
@@ -61,18 +80,19 @@ export class MariaDialect extends MysqlLikeSqlDialect {
|
|
|
61
80
|
ctx.append(')');
|
|
62
81
|
}
|
|
63
82
|
/**
|
|
64
|
-
* `
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* from `vectorTuningStatements`, which is Postgres's `SET LOCAL` shape.
|
|
83
|
+
* `mhnsw_ef_search` too, where a vector search is tuned. A setting scoped to one statement needs
|
|
84
|
+
* neither a transaction nor a restore, and cannot leak to the next query on this pooled connection,
|
|
85
|
+
* which is why the tuning is not `vectorTuningStatements`, Postgres's `SET LOCAL` shape.
|
|
68
86
|
*/
|
|
69
|
-
|
|
87
|
+
statementSettings(entity, q) {
|
|
70
88
|
// `$candidates` first: `getMeta` would otherwise be resolved on every read, to discover that
|
|
71
89
|
// almost none of them tune anything.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
90
|
+
const tuned = q.$candidates !== undefined && this.tunedVectorIndex(getMeta(entity), q);
|
|
91
|
+
return [...(tuned ? [`mhnsw_ef_search=${q.$candidates}`] : []), ...super.statementSettings(entity, q)];
|
|
92
|
+
}
|
|
93
|
+
/** `SET STATEMENT ... FOR`, which scopes a variable to the statement it prefixes. */
|
|
94
|
+
applySettings(sql, settings) {
|
|
95
|
+
return `SET STATEMENT ${settings.join(', ')} FOR ${sql}`;
|
|
76
96
|
}
|
|
77
97
|
/** The reverse: selecting a `VECTOR` column raw yields that blob, so it is read back as text. */
|
|
78
98
|
selectFieldExpr(escapedColumn, field) {
|
|
@@ -26,11 +26,11 @@ export function splitSqlStatements(sql) {
|
|
|
26
26
|
const masterRegex = /'(?:''|\\['\\]|[^'])*(?:'|(?=$))|"(?:""|\\["\\]|[^"])*(?:"|(?=$))|`(?:``|\\[`\\]|[^`])*(?:`|(?=$))|\$(?<tag>[a-zA-Z0-9_]*)\$[\s\S]*?(?:\$\k<tag>|(?=$))|--.*|\/\*[\s\S]*?(?:\*\/|(?=$))|;/g;
|
|
27
27
|
for (const match of sql.matchAll(masterRegex)) {
|
|
28
28
|
if (match[0] === ';') {
|
|
29
|
-
const stmt = sql.substring(lastIndex, match.index
|
|
29
|
+
const stmt = sql.substring(lastIndex, match.index).trim();
|
|
30
30
|
if (stmt) {
|
|
31
31
|
statements.push(stmt);
|
|
32
32
|
}
|
|
33
|
-
lastIndex =
|
|
33
|
+
lastIndex = match.index + match[0].length;
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
const lastStmt = sql.substring(lastIndex).trim();
|
package/dist/migrate/cli.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import type { AbstractDialect } from '../dialect/index.js';
|
|
3
2
|
import type { ForeignKeyAction } from '../schema/types.js';
|
|
4
|
-
import type { Config } from '../type/index.js';
|
|
3
|
+
import type { Config, MigratorDialect } from '../type/index.js';
|
|
5
4
|
import { Migrator } from './migrator.js';
|
|
6
5
|
import { createSchemaGeneratorAsync } from './schemaGeneratorAsync.js';
|
|
7
6
|
/** Sync helper for SQL dialects only; returns `undefined` for MongoDB - use {@link createSchemaGeneratorAsync}. */
|
|
8
|
-
export declare function getSchemaGenerator(dialect:
|
|
7
|
+
export declare function getSchemaGenerator(dialect: MigratorDialect, defaultForeignKeyAction?: ForeignKeyAction): import("./schemaGenerator.js").SqlSchemaGenerator | undefined;
|
|
9
8
|
export { createSchemaGeneratorAsync };
|
|
10
9
|
export declare function main(args?: string[]): Promise<void>;
|
|
11
10
|
export declare function runUp(migrator: Migrator, args: string[]): Promise<void>;
|
package/dist/migrate/cli.js
CHANGED
|
@@ -34,7 +34,6 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
34
34
|
try {
|
|
35
35
|
const config = await loadConfig(customPath);
|
|
36
36
|
assertCliConfig(config);
|
|
37
|
-
const dialectName = config.pool.dialect.dialectName ?? 'postgres';
|
|
38
37
|
const options = {
|
|
39
38
|
migrationsPath: config.migrationsPath ?? './migrations',
|
|
40
39
|
tableName: config.tableName,
|
|
@@ -43,13 +42,7 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
43
42
|
defaultForeignKeyAction: config.defaultForeignKeyAction,
|
|
44
43
|
};
|
|
45
44
|
const migrator = new Migrator(config.pool, options);
|
|
46
|
-
|
|
47
|
-
const generator = await createSchemaGeneratorAsync(config.pool.dialect, config.defaultForeignKeyAction);
|
|
48
|
-
if (!generator) {
|
|
49
|
-
throw new TypeError(`Could not find a schema generator for dialect: ${dialectName}`);
|
|
50
|
-
}
|
|
51
|
-
migrator.setSchemaGenerator(generator);
|
|
52
|
-
}
|
|
45
|
+
await migrator.ensureSchemaGenerator();
|
|
53
46
|
switch (command) {
|
|
54
47
|
case 'up':
|
|
55
48
|
await runUp(migrator, filteredArgs.slice(1));
|
|
@@ -314,8 +307,8 @@ function printDriftGroup(title, drifts, icon, showSuggestion) {
|
|
|
314
307
|
if (drift.expected && drift.actual) {
|
|
315
308
|
console.log(` Expected: ${drift.expected}, Actual: ${drift.actual}`);
|
|
316
309
|
}
|
|
317
|
-
if (showSuggestion
|
|
318
|
-
console.log(`
|
|
310
|
+
if (showSuggestion) {
|
|
311
|
+
console.log(` -> ${drift.suggestion}`);
|
|
319
312
|
}
|
|
320
313
|
}
|
|
321
314
|
console.log('');
|
|
@@ -365,7 +358,7 @@ Configuration:
|
|
|
365
358
|
Create a uql.config.ts or uql.config.js file in your project root.
|
|
366
359
|
You can also specify a custom config path using --config or -c.
|
|
367
360
|
The CLI requires pool.dialect (dialect id = pool.dialect.dialectName).
|
|
368
|
-
See the repo README section "Driver
|
|
361
|
+
See the repo README section "Driver -> pool -> dialect class".
|
|
369
362
|
|
|
370
363
|
export default {
|
|
371
364
|
pool: new PgQuerierPool({ ... }),
|
|
@@ -16,7 +16,7 @@ const OPTION_SOURCE = {
|
|
|
16
16
|
type: (col) => {
|
|
17
17
|
const columnType = canonicalToColumnType(col.type);
|
|
18
18
|
return [
|
|
19
|
-
|
|
19
|
+
`columnType: ${quoted(columnType)}`,
|
|
20
20
|
...(col.type.length && col.type.category === 'string' ? [`length: ${col.type.length}`] : []),
|
|
21
21
|
...(col.type.precision === undefined ? [] : [`precision: ${col.type.precision}`]),
|
|
22
22
|
...(col.type.precision !== undefined && col.type.scale !== undefined ? [`scale: ${col.type.scale}`] : []),
|
|
@@ -2,15 +2,11 @@ import type { AbstractSqlDialect } from '../../dialect/abstractSqlDialect.js';
|
|
|
2
2
|
import { IndexDdl } from './indexDdl.js';
|
|
3
3
|
import { TableDdl } from './tableDdl.js';
|
|
4
4
|
export { IndexDdl } from './indexDdl.js';
|
|
5
|
+
export { MsSqlIndexDdl } from './mssqlIndexDdl.js';
|
|
5
6
|
export { MsSqlTableDdl } from './mssqlTableDdl.js';
|
|
6
7
|
export { MariaIndexDdl, MySqlIndexDdl, MysqlLikeIndexDdl } from './mysqlIndexDdl.js';
|
|
7
8
|
export { CockroachIndexDdl, PgIndexDdl } from './pgIndexDdl.js';
|
|
8
9
|
export { TableDdl } from './tableDdl.js';
|
|
9
|
-
/**
|
|
10
|
-
* The index DDL a dialect gets, most specific first. `instanceof` rather than the `dialectName`
|
|
11
|
-
* {@link tableDdlFor} reads, because each family's index DDL is typed to its dialect and the narrowing
|
|
12
|
-
* is what hands it one. Anything else gets the portable form, which is SQLite's.
|
|
13
|
-
*/
|
|
14
10
|
export declare function indexDdlFor(dialect: AbstractSqlDialect): IndexDdl;
|
|
15
11
|
/**
|
|
16
12
|
* The table DDL a dialect gets: SQL Server's, or the portable form every other engine takes. By
|
|
@@ -1,40 +1,29 @@
|
|
|
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
1
|
import { IndexDdl } from './indexDdl.js';
|
|
2
|
+
import { MsSqlIndexDdl } from './mssqlIndexDdl.js';
|
|
7
3
|
import { MsSqlTableDdl } from './mssqlTableDdl.js';
|
|
8
|
-
import { MariaIndexDdl, MySqlIndexDdl
|
|
4
|
+
import { MariaIndexDdl, MySqlIndexDdl } from './mysqlIndexDdl.js';
|
|
9
5
|
import { CockroachIndexDdl, PgIndexDdl } from './pgIndexDdl.js';
|
|
10
6
|
import { TableDdl } from './tableDdl.js';
|
|
11
7
|
export { IndexDdl } from './indexDdl.js';
|
|
8
|
+
export { MsSqlIndexDdl } from './mssqlIndexDdl.js';
|
|
12
9
|
export { MsSqlTableDdl } from './mssqlTableDdl.js';
|
|
13
10
|
export { MariaIndexDdl, MySqlIndexDdl, MysqlLikeIndexDdl } from './mysqlIndexDdl.js';
|
|
14
11
|
export { CockroachIndexDdl, PgIndexDdl } from './pgIndexDdl.js';
|
|
15
12
|
export { TableDdl } from './tableDdl.js';
|
|
16
13
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* is what hands it one. Anything else gets the portable form, which is SQLite's.
|
|
14
|
+
* Each engine's index DDL, by the `dialectName` a subclass inherits: by name, so this entry carries no
|
|
15
|
+
* dialect, and exhaustive, so a new engine has to name its own. SQLite's is the portable form.
|
|
20
16
|
*/
|
|
17
|
+
const INDEX_DDL = {
|
|
18
|
+
postgres: PgIndexDdl,
|
|
19
|
+
cockroachdb: CockroachIndexDdl,
|
|
20
|
+
mysql: MySqlIndexDdl,
|
|
21
|
+
mariadb: MariaIndexDdl,
|
|
22
|
+
mssql: MsSqlIndexDdl,
|
|
23
|
+
sqlite: IndexDdl,
|
|
24
|
+
};
|
|
21
25
|
export function indexDdlFor(dialect) {
|
|
22
|
-
|
|
23
|
-
return new CockroachIndexDdl(dialect);
|
|
24
|
-
}
|
|
25
|
-
if (dialect instanceof PgLikeSqlDialect) {
|
|
26
|
-
return new PgIndexDdl(dialect);
|
|
27
|
-
}
|
|
28
|
-
if (dialect instanceof MySqlDialect) {
|
|
29
|
-
return new MySqlIndexDdl(dialect);
|
|
30
|
-
}
|
|
31
|
-
if (dialect instanceof MariaDialect) {
|
|
32
|
-
return new MariaIndexDdl(dialect);
|
|
33
|
-
}
|
|
34
|
-
if (dialect instanceof MysqlLikeSqlDialect) {
|
|
35
|
-
return new MysqlLikeIndexDdl(dialect);
|
|
36
|
-
}
|
|
37
|
-
return new IndexDdl(dialect);
|
|
26
|
+
return new INDEX_DDL[dialect.dialectName](dialect);
|
|
38
27
|
}
|
|
39
28
|
/**
|
|
40
29
|
* The table DDL a dialect gets: SQL Server's, or the portable form every other engine takes. By
|