uql-orm 0.51.0 → 0.53.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 +5 -5
- package/dist/bunSql/bunSql.util.d.ts +33 -10
- package/dist/bunSql/bunSql.util.js +57 -42
- package/dist/bunSql/bunSqlQuerier.d.ts +13 -8
- package/dist/bunSql/bunSqlQuerier.js +17 -8
- package/dist/bunSql/bunSqlQuerierPool.d.ts +10 -2
- package/dist/bunSql/bunSqlQuerierPool.js +38 -25
- package/dist/bunSql/index.d.ts +1 -3
- package/dist/bunSql/index.js +0 -3
- package/dist/dialect/abstractDialect.d.ts +5 -5
- package/dist/dialect/abstractDialect.js +7 -6
- package/dist/dialect/abstractSqlDialect.d.ts +59 -6
- package/dist/dialect/abstractSqlDialect.js +90 -32
- package/dist/dialect/aliases.d.ts +2 -0
- package/dist/dialect/aliases.js +2 -0
- package/dist/dialect/mergeSqlDialect.d.ts +45 -0
- package/dist/dialect/mergeSqlDialect.js +89 -0
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +0 -1
- package/dist/dialect/mysqlLikeSqlDialect.js +3 -3
- package/dist/dialect/pgLikeSqlDialect.js +3 -2
- package/dist/dialect/vectorSqlDialect.js +2 -1
- package/dist/http/handler.js +3 -12
- package/dist/http/query.js +4 -1
- package/dist/migrate/builder/expressions.js +5 -0
- package/dist/migrate/ddl/index.d.ts +8 -0
- package/dist/migrate/ddl/index.js +11 -0
- package/dist/migrate/ddl/mssqlTableDdl.d.ts +23 -0
- package/dist/migrate/ddl/mssqlTableDdl.js +61 -0
- package/dist/migrate/ddl/tableDdl.d.ts +34 -0
- package/dist/migrate/ddl/tableDdl.js +71 -0
- package/dist/migrate/introspection/index.d.ts +2 -0
- package/dist/migrate/introspection/index.js +2 -0
- package/dist/migrate/introspection/mssqlIntrospector.d.ts +60 -0
- package/dist/migrate/introspection/mssqlIntrospector.js +205 -0
- package/dist/migrate/introspection/registry.d.ts +3 -0
- package/dist/migrate/introspection/registry.js +28 -0
- package/dist/migrate/migrator.js +2 -21
- package/dist/migrate/schemaGenerator.d.ts +8 -10
- package/dist/migrate/schemaGenerator.js +29 -74
- package/dist/mongo/mongoDialect.js +12 -14
- package/dist/mssql/index.d.ts +3 -0
- package/dist/mssql/index.js +3 -0
- package/dist/mssql/mssqlDialect.d.ts +155 -0
- package/dist/mssql/mssqlDialect.js +341 -0
- package/dist/mssql/mssqlQuerier.d.ts +23 -0
- package/dist/mssql/mssqlQuerier.js +137 -0
- package/dist/mssql/mssqlQuerierPool.d.ts +17 -0
- package/dist/mssql/mssqlQuerierPool.js +32 -0
- package/dist/mssql/mssqlWireTypes.d.ts +23 -0
- package/dist/mssql/mssqlWireTypes.js +44 -0
- package/dist/pglite/pgliteQuerier.d.ts +4 -2
- package/dist/pglite/pgliteQuerier.js +7 -2
- package/dist/postgres/pgCursorStream.d.ts +20 -0
- package/dist/postgres/pgCursorStream.js +49 -0
- package/dist/postgres/pgDialect.d.ts +1 -1
- package/dist/postgres/pgDialect.js +1 -1
- package/dist/postgres/postgresWireDriverCapabilities.d.ts +12 -10
- package/dist/postgres/postgresWireDriverCapabilities.js +12 -10
- package/dist/querier/abstractQuerier.js +13 -11
- package/dist/querier/abstractSqlQuerier.js +3 -3
- package/dist/schema/canonicalType.js +96 -113
- package/dist/sqlite/sqliteDialect.js +3 -2
- package/dist/type/dialect.d.ts +24 -5
- package/dist/type/migratorDialect.d.ts +1 -1
- package/dist/type/migratorDialect.js +1 -0
- package/dist/type/query.d.ts +1 -1
- package/dist/type/queryWhere.d.ts +7 -19
- package/dist/type/vector.d.ts +3 -1
- package/dist/util/dialect.util.d.ts +10 -7
- package/dist/util/dialect.util.js +16 -29
- package/dist/util/object.util.d.ts +2 -0
- package/dist/util/object.util.js +4 -0
- package/package.json +13 -3
- package/dist/bunSql/bunSqlCockroachDialect.d.ts +0 -12
- package/dist/bunSql/bunSqlCockroachDialect.js +0 -15
- package/dist/bunSql/bunSqlPostgresDialect.d.ts +0 -11
- package/dist/bunSql/bunSqlPostgresDialect.js +0 -14
- package/dist/bunSql/bunSqliteDialect.d.ts +0 -6
- package/dist/bunSql/bunSqliteDialect.js +0 -6
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { AbstractSqlSchemaIntrospector } from './abstractSqlSchemaIntrospector.js';
|
|
2
|
+
/**
|
|
3
|
+
* SQL Server schema introspector.
|
|
4
|
+
*
|
|
5
|
+
* `INFORMATION_SCHEMA` answers columns and foreign keys, but not indexes: it has no view for them at
|
|
6
|
+
* all, and its `CONSTRAINT_COLUMN_USAGE` conflates a unique index with a unique constraint. Those
|
|
7
|
+
* come from `sys.indexes` instead, which is also the only place the filtered-index predicate and the
|
|
8
|
+
* included columns are readable.
|
|
9
|
+
*/
|
|
10
|
+
export class MsSqlSchemaIntrospector extends AbstractSqlSchemaIntrospector {
|
|
11
|
+
defaultSchemaExpr = 'SCHEMA_NAME()';
|
|
12
|
+
getTableNamesQuery() {
|
|
13
|
+
return /*sql*/ `
|
|
14
|
+
SELECT TABLE_NAME as table_name
|
|
15
|
+
FROM INFORMATION_SCHEMA.TABLES
|
|
16
|
+
WHERE TABLE_SCHEMA = ${this.schemaExpr}
|
|
17
|
+
AND TABLE_TYPE = 'BASE TABLE'
|
|
18
|
+
ORDER BY TABLE_NAME
|
|
19
|
+
`;
|
|
20
|
+
}
|
|
21
|
+
tableExistsQuery() {
|
|
22
|
+
return /*sql*/ `
|
|
23
|
+
SELECT COUNT(*) as count
|
|
24
|
+
FROM INFORMATION_SCHEMA.TABLES
|
|
25
|
+
WHERE TABLE_SCHEMA = ${this.schemaExpr}
|
|
26
|
+
AND TABLE_NAME = @p1
|
|
27
|
+
`;
|
|
28
|
+
}
|
|
29
|
+
parseTableExistsResult(results) {
|
|
30
|
+
return (this.toNumber(results[0]?.count) ?? 0) > 0;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* From `sys` rather than `INFORMATION_SCHEMA`, which has no identity flag and no per-column view of
|
|
34
|
+
* the key or of a unique index. A key column is not also `isUnique`, as on MySQL: only a unique index
|
|
35
|
+
* of its own, other than the key's, makes it so.
|
|
36
|
+
*/
|
|
37
|
+
getColumnsQuery(_tableName) {
|
|
38
|
+
return /*sql*/ `
|
|
39
|
+
SELECT
|
|
40
|
+
c.name as column_name,
|
|
41
|
+
t.name as data_type,
|
|
42
|
+
c.max_length as max_length,
|
|
43
|
+
c.precision as numeric_precision,
|
|
44
|
+
c.scale as numeric_scale,
|
|
45
|
+
c.is_nullable as is_nullable,
|
|
46
|
+
c.is_identity as is_identity,
|
|
47
|
+
d.definition as column_default,
|
|
48
|
+
f.is_primary_key,
|
|
49
|
+
f.is_unique
|
|
50
|
+
FROM sys.columns c
|
|
51
|
+
JOIN sys.objects o ON o.object_id = c.object_id
|
|
52
|
+
JOIN sys.schemas s ON s.schema_id = o.schema_id
|
|
53
|
+
JOIN sys.types t ON t.user_type_id = c.user_type_id
|
|
54
|
+
LEFT JOIN sys.default_constraints d ON d.object_id = c.default_object_id
|
|
55
|
+
OUTER APPLY (
|
|
56
|
+
SELECT
|
|
57
|
+
MAX(CAST(i.is_primary_key AS INT)) as is_primary_key,
|
|
58
|
+
MAX(CASE WHEN i.is_primary_key = 0 AND n.key_columns = 1 THEN 1 ELSE 0 END) as is_unique
|
|
59
|
+
FROM sys.index_columns ic
|
|
60
|
+
JOIN sys.indexes i ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
61
|
+
CROSS APPLY (
|
|
62
|
+
SELECT COUNT(*) as key_columns FROM sys.index_columns k
|
|
63
|
+
WHERE k.object_id = i.object_id AND k.index_id = i.index_id AND k.is_included_column = 0
|
|
64
|
+
) n
|
|
65
|
+
WHERE ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
66
|
+
AND ic.is_included_column = 0 AND i.is_unique = 1
|
|
67
|
+
) f
|
|
68
|
+
WHERE s.name = ${this.schemaExpr} AND o.name = @p1
|
|
69
|
+
ORDER BY c.column_id
|
|
70
|
+
`;
|
|
71
|
+
}
|
|
72
|
+
/** `is_primary_key` is excluded: the key is read separately, the way every other engine reads it. */
|
|
73
|
+
getIndexesQuery(_tableName) {
|
|
74
|
+
return /*sql*/ `
|
|
75
|
+
SELECT
|
|
76
|
+
i.name as index_name,
|
|
77
|
+
i.is_unique as is_unique,
|
|
78
|
+
STRING_AGG(c.name, ',') WITHIN GROUP (ORDER BY ic.key_ordinal) as columns
|
|
79
|
+
FROM sys.indexes i
|
|
80
|
+
JOIN sys.objects o ON o.object_id = i.object_id
|
|
81
|
+
JOIN sys.schemas s ON s.schema_id = o.schema_id
|
|
82
|
+
JOIN sys.index_columns ic ON ic.object_id = i.object_id AND ic.index_id = i.index_id
|
|
83
|
+
JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
|
84
|
+
WHERE s.name = ${this.schemaExpr} AND o.name = @p1
|
|
85
|
+
AND i.is_primary_key = 0 AND i.name IS NOT NULL AND ic.is_included_column = 0
|
|
86
|
+
GROUP BY i.name, i.is_unique
|
|
87
|
+
ORDER BY i.name
|
|
88
|
+
`;
|
|
89
|
+
}
|
|
90
|
+
getForeignKeysQuery(_tableName) {
|
|
91
|
+
return /*sql*/ `
|
|
92
|
+
SELECT
|
|
93
|
+
fk.name as constraint_name,
|
|
94
|
+
STRING_AGG(pc.name, ',') WITHIN GROUP (ORDER BY fkc.constraint_column_id) as columns,
|
|
95
|
+
rt.name as referenced_table,
|
|
96
|
+
STRING_AGG(rc.name, ',') WITHIN GROUP (ORDER BY fkc.constraint_column_id) as referenced_columns,
|
|
97
|
+
fk.delete_referential_action_desc as delete_rule,
|
|
98
|
+
fk.update_referential_action_desc as update_rule
|
|
99
|
+
FROM sys.foreign_keys fk
|
|
100
|
+
JOIN sys.objects o ON o.object_id = fk.parent_object_id
|
|
101
|
+
JOIN sys.schemas s ON s.schema_id = o.schema_id
|
|
102
|
+
JOIN sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
|
|
103
|
+
JOIN sys.columns pc ON pc.object_id = fkc.parent_object_id AND pc.column_id = fkc.parent_column_id
|
|
104
|
+
JOIN sys.objects rt ON rt.object_id = fk.referenced_object_id
|
|
105
|
+
JOIN sys.columns rc ON rc.object_id = fkc.referenced_object_id AND rc.column_id = fkc.referenced_column_id
|
|
106
|
+
WHERE s.name = ${this.schemaExpr} AND o.name = @p1
|
|
107
|
+
GROUP BY fk.name, rt.name, fk.delete_referential_action_desc, fk.update_referential_action_desc
|
|
108
|
+
ORDER BY fk.name
|
|
109
|
+
`;
|
|
110
|
+
}
|
|
111
|
+
getPrimaryKeyQuery(_tableName) {
|
|
112
|
+
return /*sql*/ `
|
|
113
|
+
SELECT c.name as column_name, i.name as constraint_name
|
|
114
|
+
FROM sys.indexes i
|
|
115
|
+
JOIN sys.objects o ON o.object_id = i.object_id
|
|
116
|
+
JOIN sys.schemas s ON s.schema_id = o.schema_id
|
|
117
|
+
JOIN sys.index_columns ic ON ic.object_id = i.object_id AND ic.index_id = i.index_id
|
|
118
|
+
JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
|
119
|
+
WHERE s.name = ${this.schemaExpr} AND o.name = @p1 AND i.is_primary_key = 1
|
|
120
|
+
ORDER BY ic.key_ordinal
|
|
121
|
+
`;
|
|
122
|
+
}
|
|
123
|
+
async mapColumnsResult(_read, _tableName, results) {
|
|
124
|
+
return results.map((row) => {
|
|
125
|
+
const type = row.data_type.toUpperCase();
|
|
126
|
+
const bytes = this.toNumber(row.max_length);
|
|
127
|
+
return {
|
|
128
|
+
name: row.column_name,
|
|
129
|
+
type: bytes === -1 && CHARACTER_TYPES.has(type) ? `${type}(MAX)` : type,
|
|
130
|
+
nullable: Boolean(row.is_nullable),
|
|
131
|
+
defaultValue: this.parseDefaultValue(row.column_default),
|
|
132
|
+
isAutoIncrement: Boolean(row.is_identity),
|
|
133
|
+
isPrimaryKey: Boolean(row.is_primary_key),
|
|
134
|
+
isUnique: Boolean(row.is_unique),
|
|
135
|
+
length: widthOf(type, bytes),
|
|
136
|
+
precision: NUMERIC_TYPES.has(type) ? this.toNumber(row.numeric_precision) : undefined,
|
|
137
|
+
scale: NUMERIC_TYPES.has(type) ? this.toNumber(row.numeric_scale) : undefined,
|
|
138
|
+
};
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
async mapIndexesResult(_read, _tableName, results) {
|
|
142
|
+
return results.map((row) => ({
|
|
143
|
+
name: row.index_name,
|
|
144
|
+
entries: (row.columns ?? '').split(',').map((column) => ({ column })),
|
|
145
|
+
unique: Boolean(row.is_unique),
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
async mapForeignKeysResult(_read, _tableName, results) {
|
|
149
|
+
return results.map((row) => ({
|
|
150
|
+
name: row.constraint_name,
|
|
151
|
+
columns: (row.columns || '').split(','),
|
|
152
|
+
references: { table: row.referenced_table, columns: (row.referenced_columns || '').split(',') },
|
|
153
|
+
// `sys` spells them with an underscore: `SET_NULL`, `NO_ACTION`.
|
|
154
|
+
onDelete: this.normalizeReferentialAction((row.delete_rule || '').replaceAll('_', ' ')),
|
|
155
|
+
onUpdate: this.normalizeReferentialAction((row.update_rule || '').replaceAll('_', ' ')),
|
|
156
|
+
}));
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* A default is stored wrapped in at least one layer of parentheses - `((0))` for a number,
|
|
160
|
+
* `(N'x')` for a string - because the engine reprints it from its own parse tree.
|
|
161
|
+
*/
|
|
162
|
+
parseDefaultValue(defaultValue) {
|
|
163
|
+
if (defaultValue === null || defaultValue === undefined) {
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
let text = defaultValue.trim();
|
|
167
|
+
while (text.startsWith('(') && text.endsWith(')')) {
|
|
168
|
+
text = text.slice(1, -1).trim();
|
|
169
|
+
}
|
|
170
|
+
if (text.toUpperCase() === 'NULL') {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
const unicode = text.startsWith("N'") ? text.slice(1) : text;
|
|
174
|
+
if (unicode.startsWith("'") && unicode.endsWith("'")) {
|
|
175
|
+
return unicode.slice(1, -1).replaceAll("''", "'");
|
|
176
|
+
}
|
|
177
|
+
if (/^-?\d+$/.test(text)) {
|
|
178
|
+
return Number.parseInt(text, 10);
|
|
179
|
+
}
|
|
180
|
+
if (/^-?\d+\.\d+$/.test(text)) {
|
|
181
|
+
return Number.parseFloat(text);
|
|
182
|
+
}
|
|
183
|
+
return text;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/** The types whose `max_length` is a width rather than a fixed storage size. */
|
|
187
|
+
const CHARACTER_TYPES = new Set(['CHAR', 'NCHAR', 'VARCHAR', 'NVARCHAR', 'BINARY', 'VARBINARY']);
|
|
188
|
+
const NUMERIC_TYPES = new Set(['DECIMAL', 'NUMERIC']);
|
|
189
|
+
/**
|
|
190
|
+
* A column's declared width from `max_length`, which is bytes: an `N` type holds two a character, a
|
|
191
|
+
* `VECTOR` is an 8-byte header and four a dimension, and `MAX` is `-1`. Read as bytes, every Unicode
|
|
192
|
+
* column would drift to double its width against the entity that declared it.
|
|
193
|
+
*/
|
|
194
|
+
function widthOf(type, bytes) {
|
|
195
|
+
if (bytes === undefined || bytes < 0) {
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
if (type === 'VECTOR') {
|
|
199
|
+
return (bytes - 8) / 4;
|
|
200
|
+
}
|
|
201
|
+
if (!CHARACTER_TYPES.has(type)) {
|
|
202
|
+
return undefined;
|
|
203
|
+
}
|
|
204
|
+
return type.startsWith('N') ? bytes / 2 : bytes;
|
|
205
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { QuerierPool, SchemaIntrospector } from '../../type/index.js';
|
|
2
|
+
/** The introspector for `dialectName`, or `undefined` where the migrator has none for it. */
|
|
3
|
+
export declare function introspectorFor(dialectName: string, pool: QuerierPool, schema?: string): SchemaIntrospector | undefined;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { MongoSchemaIntrospector } from './mongoIntrospector.js';
|
|
2
|
+
import { MsSqlSchemaIntrospector } from './mssqlIntrospector.js';
|
|
3
|
+
import { MariadbSchemaIntrospector, MysqlSchemaIntrospector } from './mysqlIntrospector.js';
|
|
4
|
+
import { CockroachSchemaIntrospector, PostgresSchemaIntrospector } from './postgresIntrospector.js';
|
|
5
|
+
import { SqliteSchemaIntrospector } from './sqliteIntrospector.js';
|
|
6
|
+
/**
|
|
7
|
+
* Which introspector each engine gets. A table rather than a `switch` so `Migrator` names no
|
|
8
|
+
* constructor and adding an engine touches one line, not a control flow.
|
|
9
|
+
*
|
|
10
|
+
* Every entry is statically imported, so `uql-orm/migrate` still carries all of them; making the
|
|
11
|
+
* table's values dynamic imports would shrink that entry, at the cost of an async
|
|
12
|
+
* `createIntrospector` the constructor cannot await.
|
|
13
|
+
*/
|
|
14
|
+
const INTROSPECTORS = {
|
|
15
|
+
postgres: (pool, schema) => new PostgresSchemaIntrospector(pool, schema),
|
|
16
|
+
cockroachdb: (pool, schema) => new CockroachSchemaIntrospector(pool, schema),
|
|
17
|
+
mysql: (pool, schema) => new MysqlSchemaIntrospector(pool, schema),
|
|
18
|
+
mariadb: (pool, schema) => new MariadbSchemaIntrospector(pool, schema),
|
|
19
|
+
mssql: (pool, schema) => new MsSqlSchemaIntrospector(pool, schema),
|
|
20
|
+
// Neither has schemas to read: SQLite attaches database files and MongoDB takes its database from
|
|
21
|
+
// the connection, so both ignore the argument rather than filtering on it.
|
|
22
|
+
sqlite: (pool) => new SqliteSchemaIntrospector(pool),
|
|
23
|
+
mongodb: (pool) => new MongoSchemaIntrospector(pool),
|
|
24
|
+
};
|
|
25
|
+
/** The introspector for `dialectName`, or `undefined` where the migrator has none for it. */
|
|
26
|
+
export function introspectorFor(dialectName, pool, schema) {
|
|
27
|
+
return INTROSPECTORS[dialectName]?.(pool, schema);
|
|
28
|
+
}
|
package/dist/migrate/migrator.js
CHANGED
|
@@ -8,7 +8,7 @@ import { LoggerWrapper } from '../util/index.js';
|
|
|
8
8
|
import { withQuerierForMigrations, withSqlQuerierForMigrations } from './acquireQuerierForMigrations.js';
|
|
9
9
|
import { buildSqlQuerierMigrationModule, EMPTY_MANUAL_MIGRATION_DOWN_INNER, EMPTY_MANUAL_MIGRATION_UP_INNER, emitSqlRunCalls, } from './codegen/migrationFile.js';
|
|
10
10
|
import { runMongoCommand } from './generator/mongoCommand.js';
|
|
11
|
-
import {
|
|
11
|
+
import { introspectorFor } from './introspection/registry.js';
|
|
12
12
|
import { createSchemaGenerator } from './schemaGenerator.js';
|
|
13
13
|
import { createSchemaGeneratorAsync } from './schemaGeneratorAsync.js';
|
|
14
14
|
import { DatabaseMigrationStorage } from './storage/databaseStorage.js';
|
|
@@ -73,26 +73,7 @@ export class Migrator {
|
|
|
73
73
|
}
|
|
74
74
|
/** `schema` reads one namespace instead of the connection's own; see {@link BaseSqlIntrospector.schema}. */
|
|
75
75
|
createIntrospector(schema) {
|
|
76
|
-
|
|
77
|
-
if (!isKnownMigratorDialect(d)) {
|
|
78
|
-
return undefined;
|
|
79
|
-
}
|
|
80
|
-
switch (d) {
|
|
81
|
-
case 'postgres':
|
|
82
|
-
return new PostgresSchemaIntrospector(this.pool, schema);
|
|
83
|
-
case 'cockroachdb':
|
|
84
|
-
return new CockroachSchemaIntrospector(this.pool, schema);
|
|
85
|
-
case 'mysql':
|
|
86
|
-
return new MysqlSchemaIntrospector(this.pool, schema);
|
|
87
|
-
case 'mariadb':
|
|
88
|
-
return new MariadbSchemaIntrospector(this.pool, schema);
|
|
89
|
-
case 'sqlite':
|
|
90
|
-
return new SqliteSchemaIntrospector(this.pool);
|
|
91
|
-
case 'mongodb':
|
|
92
|
-
return new MongoSchemaIntrospector(this.pool);
|
|
93
|
-
default:
|
|
94
|
-
return undefined;
|
|
95
|
-
}
|
|
76
|
+
return introspectorFor(this.dialectName, this.pool, schema);
|
|
96
77
|
}
|
|
97
78
|
createGenerator() {
|
|
98
79
|
if (!isKnownMigratorDialect(this.dialectName)) {
|
|
@@ -4,7 +4,7 @@ import { type DiffOptions } from '../schema/schemaASTDiffer.js';
|
|
|
4
4
|
import type { CanonicalType, ColumnNode, ForeignKeyAction, IndexNode, TableNode } from '../schema/types.js';
|
|
5
5
|
import type { ColumnSchema, CreateSchemaOptions, DialectFeatures, DropSchemaOptions, EntityMeta, FieldMeta, FieldOptions, ForeignKeySchema, IndexSchema, NamingStrategy, SchemaDiff, SchemaGenerator, SqlDdlGenerator, Type } from '../type/index.js';
|
|
6
6
|
import type { FullColumnDefinition, TableDefinition } from './builder/types.js';
|
|
7
|
-
import { type IndexDdl } from './ddl/index.js';
|
|
7
|
+
import { type IndexDdl, type TableDdl } from './ddl/index.js';
|
|
8
8
|
/**
|
|
9
9
|
* Unified SQL schema generator.
|
|
10
10
|
* Parameterized by dialect to handle Postgres, MySQL, MariaDB, and SQLite.
|
|
@@ -14,6 +14,8 @@ export declare class SqlSchemaGenerator implements SqlDdlGenerator {
|
|
|
14
14
|
protected readonly defaultForeignKeyAction: ForeignKeyAction;
|
|
15
15
|
/** `CREATE INDEX` for this dialect: the migrator's, so a runtime import carries none of it. */
|
|
16
16
|
protected readonly indexDdl: IndexDdl;
|
|
17
|
+
/** The `ALTER TABLE` statements this dialect spells its own way, the migrator's for the same reason. */
|
|
18
|
+
protected readonly tableDdl: TableDdl;
|
|
17
19
|
constructor(dialect: AbstractSqlDialect, defaultForeignKeyAction?: ForeignKeyAction);
|
|
18
20
|
get namingStrategy(): NamingStrategy | undefined;
|
|
19
21
|
get features(): DialectFeatures;
|
|
@@ -97,18 +99,14 @@ export declare class SqlSchemaGenerator implements SqlDdlGenerator {
|
|
|
97
99
|
*/
|
|
98
100
|
generateColumnDefinitionFromSchema(column: ColumnSchema): string;
|
|
99
101
|
/**
|
|
100
|
-
* The one place a column definition is spelled
|
|
101
|
-
*
|
|
102
|
-
*
|
|
102
|
+
* The one place a column definition is spelled, so the `ColumnSchema` and `ColumnNode` paths cannot
|
|
103
|
+
* drift. A key column states `NOT NULL` rather than leave it to the key: SQLite lets a key column hold
|
|
104
|
+
* NULL otherwise, and SQL Server adds no key over a nullable column. `UNIQUE` is left to the key. An
|
|
105
|
+
* enum's `CHECK` comes last, the only place MariaDB takes it.
|
|
103
106
|
*/
|
|
104
107
|
private renderColumn;
|
|
105
|
-
/** ` DEFAULT <sql>`, or nothing where the column declares none. Empty rather than `DEFAULT NULL`
|
|
106
|
-
* so an absent default stays absent - `defaultValue: null` is the way to ask for one. */
|
|
107
|
-
private defaultClause;
|
|
108
108
|
getSqlType(field: FieldMeta): string;
|
|
109
|
-
/**
|
|
110
|
-
* Generate ALTER COLUMN statements (database-specific)
|
|
111
|
-
*/
|
|
109
|
+
/** The statements that alter `column` in place, as this dialect spells them. */
|
|
112
110
|
generateAlterColumnStatements(tableName: string, column: ColumnSchema, newDefinition: string): string[];
|
|
113
111
|
/** The inline ` COMMENT '...'` a column declaration carries, where the engine takes one there. */
|
|
114
112
|
generateColumnComment(comment: string): string;
|
|
@@ -4,10 +4,11 @@ import { areTypesEqual, canonicalToSql, engineType, fieldOptionsToCanonical, isV
|
|
|
4
4
|
import { indexSignature } from '../schema/indexDifferences.js';
|
|
5
5
|
import { buildSchemaAST } from '../schema/schemaASTBuilder.js';
|
|
6
6
|
import { diffRelationshipNodes, diffTable } from '../schema/schemaASTDiffer.js';
|
|
7
|
-
import {
|
|
7
|
+
import { isAutoIncrement, qualifyName } from '../util/index.js';
|
|
8
8
|
import { derivedCheckName, derivedForeignKeyName, derivedPrimaryKeyName } from '../util/sql.util.js';
|
|
9
9
|
import { formatDefaultValue, SqlExpression } from './builder/expressions.js';
|
|
10
|
-
import { indexDdlFor } from './ddl/index.js';
|
|
10
|
+
import { indexDdlFor, tableDdlFor } from './ddl/index.js';
|
|
11
|
+
import { sizedType } from './ddl/tableDdl.js';
|
|
11
12
|
import { columnForeignKey, columnIndex, fullColumnDefinitionToNode, tableDefinitionToNode, } from './generator/definitionToNode.js';
|
|
12
13
|
import { indexNodeToSchema } from './generator/indexNodeToSchema.js';
|
|
13
14
|
/**
|
|
@@ -19,10 +20,13 @@ export class SqlSchemaGenerator {
|
|
|
19
20
|
defaultForeignKeyAction;
|
|
20
21
|
/** `CREATE INDEX` for this dialect: the migrator's, so a runtime import carries none of it. */
|
|
21
22
|
indexDdl;
|
|
23
|
+
/** The `ALTER TABLE` statements this dialect spells its own way, the migrator's for the same reason. */
|
|
24
|
+
tableDdl;
|
|
22
25
|
constructor(dialect, defaultForeignKeyAction = 'NO ACTION') {
|
|
23
26
|
this.dialect = dialect;
|
|
24
27
|
this.defaultForeignKeyAction = defaultForeignKeyAction;
|
|
25
28
|
this.indexDdl = indexDdlFor(dialect);
|
|
29
|
+
this.tableDdl = tableDdlFor(dialect);
|
|
26
30
|
}
|
|
27
31
|
get namingStrategy() {
|
|
28
32
|
return this.dialect.namingStrategy;
|
|
@@ -138,7 +142,6 @@ export class SqlSchemaGenerator {
|
|
|
138
142
|
}
|
|
139
143
|
generateAlterTable(diff) {
|
|
140
144
|
const statements = [];
|
|
141
|
-
const tableName = this.escapeId(diff.tableName);
|
|
142
145
|
// Before the columns, because a key column being added cannot be part of the old key, and after
|
|
143
146
|
// it is dropped the table is free to take the new one below.
|
|
144
147
|
if (diff.primaryKey?.from.length) {
|
|
@@ -154,7 +157,7 @@ export class SqlSchemaGenerator {
|
|
|
154
157
|
if (diff.columnsToAdd?.length) {
|
|
155
158
|
for (const column of diff.columnsToAdd) {
|
|
156
159
|
this.assertColumnAddable(diff.tableName, column);
|
|
157
|
-
statements.push(
|
|
160
|
+
statements.push(this.tableDdl.addColumn(diff.tableName, this.generateColumnDefinitionFromSchema(column)));
|
|
158
161
|
statements.push(...this.generateColumnCommentStatement(diff.tableName, column, diff.schema));
|
|
159
162
|
}
|
|
160
163
|
}
|
|
@@ -169,7 +172,7 @@ export class SqlSchemaGenerator {
|
|
|
169
172
|
// Drop columns
|
|
170
173
|
if (diff.columnsToDrop?.length) {
|
|
171
174
|
for (const columnName of diff.columnsToDrop) {
|
|
172
|
-
statements.push(
|
|
175
|
+
statements.push(...this.tableDdl.dropColumn(diff.tableName, columnName));
|
|
173
176
|
}
|
|
174
177
|
}
|
|
175
178
|
// Add indexes
|
|
@@ -206,7 +209,6 @@ export class SqlSchemaGenerator {
|
|
|
206
209
|
}
|
|
207
210
|
generateAlterTableDown(diff) {
|
|
208
211
|
const statements = [];
|
|
209
|
-
const tableName = this.escapeId(diff.tableName);
|
|
210
212
|
// Constraints first, mirroring the up direction: the up added them last, so the down drops them
|
|
211
213
|
// first, and a column it is about to drop is then free of anything naming it.
|
|
212
214
|
statements.push(...this.dropForeignKeyStatements(diff.tableName, [
|
|
@@ -222,7 +224,7 @@ export class SqlSchemaGenerator {
|
|
|
222
224
|
// Reverse column additions by dropping them
|
|
223
225
|
if (diff.columnsToAdd?.length) {
|
|
224
226
|
for (const column of diff.columnsToAdd) {
|
|
225
|
-
statements.push(
|
|
227
|
+
statements.push(...this.tableDdl.dropColumn(diff.tableName, column.name));
|
|
226
228
|
}
|
|
227
229
|
}
|
|
228
230
|
// Reverse column alterations by restoring original schema
|
|
@@ -273,53 +275,35 @@ export class SqlSchemaGenerator {
|
|
|
273
275
|
* {@link renderColumn}, which is the part that must not be written twice.
|
|
274
276
|
*/
|
|
275
277
|
generateColumnDefinitionFromSchema(column) {
|
|
276
|
-
|
|
277
|
-
if (!type.includes('(')) {
|
|
278
|
-
if (column.precision !== undefined) {
|
|
279
|
-
type += column.scale === undefined ? `(${column.precision})` : `(${column.precision}, ${column.scale})`;
|
|
280
|
-
}
|
|
281
|
-
else if (column.length !== undefined) {
|
|
282
|
-
type += `(${column.length})`;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
return this.renderColumn({ ...column, type });
|
|
278
|
+
return this.renderColumn({ ...column, type: sizedType(column) });
|
|
286
279
|
}
|
|
287
280
|
/**
|
|
288
|
-
* The one place a column definition is spelled
|
|
289
|
-
*
|
|
290
|
-
*
|
|
281
|
+
* The one place a column definition is spelled, so the `ColumnSchema` and `ColumnNode` paths cannot
|
|
282
|
+
* drift. A key column states `NOT NULL` rather than leave it to the key: SQLite lets a key column hold
|
|
283
|
+
* NULL otherwise, and SQL Server adds no key over a nullable column. `UNIQUE` is left to the key. An
|
|
284
|
+
* enum's `CHECK` comes last, the only place MariaDB takes it.
|
|
291
285
|
*/
|
|
292
286
|
renderColumn(column) {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
if (column.
|
|
298
|
-
def += ` GENERATED ALWAYS AS (${column.generatedAs}) STORED`;
|
|
299
|
-
}
|
|
300
|
-
if (!column.nullable && !column.isPrimaryKey) {
|
|
287
|
+
const type = column.generatedAs
|
|
288
|
+
? this.tableDdl.storedGeneratedColumn(column.type, column.generatedAs)
|
|
289
|
+
: column.type;
|
|
290
|
+
let def = `${this.escapeId(column.name)} ${type}`;
|
|
291
|
+
if (!column.nullable) {
|
|
301
292
|
def += ' NOT NULL';
|
|
302
293
|
}
|
|
303
294
|
if (column.isUnique && !column.isPrimaryKey) {
|
|
304
295
|
def += ' UNIQUE';
|
|
305
296
|
}
|
|
297
|
+
def += this.tableDdl.defaultClause(column);
|
|
298
|
+
if (column.comment) {
|
|
299
|
+
def += this.generateColumnComment(column.comment);
|
|
300
|
+
}
|
|
306
301
|
if (column.enum?.length) {
|
|
307
302
|
const values = column.enum.map((value) => this.dialect.escape(value)).join(', ');
|
|
308
303
|
def += ` CHECK (${this.escapeId(column.name)} IN (${values}))`;
|
|
309
304
|
}
|
|
310
|
-
def += this.defaultClause(column);
|
|
311
|
-
if (column.comment) {
|
|
312
|
-
def += this.generateColumnComment(column.comment);
|
|
313
|
-
}
|
|
314
305
|
return def;
|
|
315
306
|
}
|
|
316
|
-
/** ` DEFAULT <sql>`, or nothing where the column declares none. Empty rather than `DEFAULT NULL`
|
|
317
|
-
* so an absent default stays absent - `defaultValue: null` is the way to ask for one. */
|
|
318
|
-
defaultClause(column) {
|
|
319
|
-
return column.defaultValue === undefined
|
|
320
|
-
? ''
|
|
321
|
-
: ` DEFAULT ${formatDefaultValue(column.defaultValue, this.dialect, column.type)}`;
|
|
322
|
-
}
|
|
323
307
|
getSqlType(field) {
|
|
324
308
|
// A foreign key takes the type of the key it points at. A `referencedKey` the target does not
|
|
325
309
|
// have falls through to this column's own options, as the AST builder does with the same case.
|
|
@@ -338,35 +322,9 @@ export class SqlSchemaGenerator {
|
|
|
338
322
|
}
|
|
339
323
|
return this.canonicalTypeToSql(canonical);
|
|
340
324
|
}
|
|
341
|
-
/**
|
|
342
|
-
* Generate ALTER COLUMN statements (database-specific)
|
|
343
|
-
*/
|
|
325
|
+
/** The statements that alter `column` in place, as this dialect spells them. */
|
|
344
326
|
generateAlterColumnStatements(tableName, column, newDefinition) {
|
|
345
|
-
|
|
346
|
-
const colName = this.escapeId(column.name);
|
|
347
|
-
if (this.dialect.alterColumnSyntax === 'none') {
|
|
348
|
-
throw new TypeError(`${this.dialect}: Cannot alter column "${column.name}" - you must recreate the table. ` +
|
|
349
|
-
`This database does not support ALTER COLUMN.`);
|
|
350
|
-
}
|
|
351
|
-
if (this.dialect.alterColumnStrategy === 'separate-clauses') {
|
|
352
|
-
const statements = [];
|
|
353
|
-
// Separate ALTER COLUMN clauses for different changes (Postgres)
|
|
354
|
-
statements.push(`ALTER TABLE ${table} ALTER COLUMN ${colName} TYPE ${column.type};`);
|
|
355
|
-
if (column.nullable) {
|
|
356
|
-
statements.push(`ALTER TABLE ${table} ALTER COLUMN ${colName} DROP NOT NULL;`);
|
|
357
|
-
}
|
|
358
|
-
else {
|
|
359
|
-
statements.push(`ALTER TABLE ${table} ALTER COLUMN ${colName} SET NOT NULL;`);
|
|
360
|
-
}
|
|
361
|
-
if (column.defaultValue !== undefined) {
|
|
362
|
-
statements.push(`ALTER TABLE ${table} ALTER COLUMN ${colName} SET${this.defaultClause(column)};`);
|
|
363
|
-
}
|
|
364
|
-
else {
|
|
365
|
-
statements.push(`ALTER TABLE ${table} ALTER COLUMN ${colName} DROP DEFAULT;`);
|
|
366
|
-
}
|
|
367
|
-
return statements;
|
|
368
|
-
}
|
|
369
|
-
return [`ALTER TABLE ${table} ${this.dialect.alterColumnSyntax} ${newDefinition};`];
|
|
327
|
+
return this.tableDdl.alterColumn(tableName, column, newDefinition);
|
|
370
328
|
}
|
|
371
329
|
/** The inline ` COMMENT '...'` a column declaration carries, where the engine takes one there. */
|
|
372
330
|
generateColumnComment(comment) {
|
|
@@ -627,10 +585,7 @@ export class SqlSchemaGenerator {
|
|
|
627
585
|
return this.generateCreateTableFromNode(tableNode, options);
|
|
628
586
|
}
|
|
629
587
|
generateRenameTableSql(oldName, newName) {
|
|
630
|
-
|
|
631
|
-
return `RENAME TABLE ${this.escapeId(oldName)} TO ${this.escapeId(newName)};`;
|
|
632
|
-
}
|
|
633
|
-
return `ALTER TABLE ${this.escapeId(oldName)} RENAME TO ${this.escapeId(newName)};`;
|
|
588
|
+
return this.tableDdl.renameTable(oldName, newName);
|
|
634
589
|
}
|
|
635
590
|
/**
|
|
636
591
|
* `ADD COLUMN`, plus the constraint and index the column declares.
|
|
@@ -643,7 +598,7 @@ export class SqlSchemaGenerator {
|
|
|
643
598
|
generateAddColumnSql(tableName, column) {
|
|
644
599
|
this.assertColumnAddable(tableName, column);
|
|
645
600
|
const colSql = this.generateColumnFromNode(fullColumnDefinitionToNode(column, tableName));
|
|
646
|
-
const statements = [
|
|
601
|
+
const statements = [this.tableDdl.addColumn(tableName, colSql)];
|
|
647
602
|
const foreignKey = columnForeignKey(column);
|
|
648
603
|
if (foreignKey) {
|
|
649
604
|
statements.push(...this.addForeignKeyStatements(tableName, [foreignKey]));
|
|
@@ -660,10 +615,10 @@ export class SqlSchemaGenerator {
|
|
|
660
615
|
return this.generateAlterColumnStatements(tableName, { ...this.columnNodeToSchema(node), name: columnName }, this.generateColumnFromNode(node)).join('\n');
|
|
661
616
|
}
|
|
662
617
|
generateDropColumnSql(tableName, columnName) {
|
|
663
|
-
return
|
|
618
|
+
return this.tableDdl.dropColumn(tableName, columnName).join('\n');
|
|
664
619
|
}
|
|
665
620
|
generateRenameColumnSql(tableName, oldName, newName) {
|
|
666
|
-
return
|
|
621
|
+
return this.tableDdl.renameColumn(tableName, oldName, newName);
|
|
667
622
|
}
|
|
668
623
|
/**
|
|
669
624
|
* `CONSTRAINT <name> FOREIGN KEY (...) REFERENCES ... ON DELETE ... ON UPDATE ...`.
|
|
@@ -4,7 +4,7 @@ import { COUNT_ALIAS, REL_NESTED_KEY, REL_TEMP_PREFIX, sortCountField } from '..
|
|
|
4
4
|
import { resolveQueryJoins, resolveSortableJoin } from '../dialect/queryJoins.js';
|
|
5
5
|
import { assertSoleId, getMeta, soleIdOf } from '../entity/index.js';
|
|
6
6
|
import { QueryRaw } from '../type/queryRaw.js';
|
|
7
|
-
import { asSelectMap, assertAggregateColumns, assertNonNegativeInteger,
|
|
7
|
+
import { asSelectMap, assertAggregateColumns, assertNonNegativeInteger, columnFamily, entityName, fillOnFields, filterFieldKeys, findVectorIndex, findVectorSort, getKeys, getRelationRequestSummary, hasKeys, isJsonUpdateOp, isOperatorMap, isOperatorObject, isVectorSearch, normalizeScalarFieldSelection, parentJoins, parseGroupMap, parseRelationSize, parseSortByCount, someKey, targetKeyColumns, } from '../util/index.js';
|
|
8
8
|
/** Default {@link DialectFeatures} for MongoDB; shared by {@link MongoDialect} and its schema generator. */
|
|
9
9
|
export const mongoDialectFeatures = {
|
|
10
10
|
explicitJsonCast: false,
|
|
@@ -14,7 +14,6 @@ export const mongoDialectFeatures = {
|
|
|
14
14
|
indexIfNotExists: false,
|
|
15
15
|
schemas: false, // the connection picks the database, and a collection name takes no dot
|
|
16
16
|
dropTableCascade: false,
|
|
17
|
-
renameColumn: false,
|
|
18
17
|
foreignKeyAlter: false,
|
|
19
18
|
primaryKeyAlter: false,
|
|
20
19
|
generatedColumnAdd: false,
|
|
@@ -22,7 +21,9 @@ export const mongoDialectFeatures = {
|
|
|
22
21
|
vectorIndexRequiresNotNull: false,
|
|
23
22
|
vectorSupportsLength: false,
|
|
24
23
|
supportsTimestamptz: false,
|
|
25
|
-
|
|
24
|
+
stringSizing: 'bounded-text',
|
|
25
|
+
supportsUnsigned: false,
|
|
26
|
+
serverSideCursors: false,
|
|
26
27
|
};
|
|
27
28
|
/** What `toWireId` converts: the hex spelling of an `ObjectId`, and nothing looser. */
|
|
28
29
|
const HEX_24 = /^[0-9a-f]{24}$/i;
|
|
@@ -67,7 +68,7 @@ export class MongoDialect extends AbstractDialect {
|
|
|
67
68
|
where(entity, where = {}, opts = {}) {
|
|
68
69
|
const meta = getMeta(entity);
|
|
69
70
|
// Filters are applied once, here at the scope entry point; recursion uses `renderFilter`.
|
|
70
|
-
return this.renderFilter(entity, this.
|
|
71
|
+
return this.renderFilter(entity, this.scopedWhere(meta, where, opts));
|
|
71
72
|
}
|
|
72
73
|
/**
|
|
73
74
|
* A `$where` that may constrain relations, split into the `$lookup` stages it needs and the `$match`
|
|
@@ -79,7 +80,7 @@ export class MongoDialect extends AbstractDialect {
|
|
|
79
80
|
whereWithRelations(entity, where = {}, opts = {}) {
|
|
80
81
|
const meta = getMeta(entity);
|
|
81
82
|
const lookups = { stages: [], temps: [] };
|
|
82
|
-
const filter = this.renderFilter(entity, this.
|
|
83
|
+
const filter = this.renderFilter(entity, this.scopedWhere(meta, where, opts), opts, lookups);
|
|
83
84
|
return { stages: lookups.stages, filter, unset: lookups.temps };
|
|
84
85
|
}
|
|
85
86
|
/** Whether a `$where` constrains any relation, and so needs the aggregation path rather than a cursor. */
|
|
@@ -88,9 +89,9 @@ export class MongoDialect extends AbstractDialect {
|
|
|
88
89
|
return false;
|
|
89
90
|
}
|
|
90
91
|
const meta = getMeta(entity);
|
|
91
|
-
const whereMap =
|
|
92
|
+
const whereMap = where;
|
|
92
93
|
return someKey(whereMap, (key) => MongoDialect.isGroupOp(key)
|
|
93
|
-
? (whereMap[key] ?? []).some((it) => this.constrainsRelations(entity, it))
|
|
94
|
+
? (whereMap[key] ?? []).some((it) => !(it instanceof QueryRaw) && this.constrainsRelations(entity, it))
|
|
94
95
|
: Boolean(meta.relations[key]));
|
|
95
96
|
}
|
|
96
97
|
/**
|
|
@@ -100,9 +101,8 @@ export class MongoDialect extends AbstractDialect {
|
|
|
100
101
|
*/
|
|
101
102
|
renderFilter(entity, where = {}, opts, lookups) {
|
|
102
103
|
const meta = getMeta(entity);
|
|
103
|
-
const whereMap = buildQueryWhereAsMap(meta, where);
|
|
104
104
|
const filter = {};
|
|
105
|
-
for (const [rawKey, rawVal] of Object.entries(
|
|
105
|
+
for (const [rawKey, rawVal] of Object.entries(where)) {
|
|
106
106
|
let key = rawKey;
|
|
107
107
|
let val = rawVal;
|
|
108
108
|
if (MongoDialect.isGroupOp(key)) {
|
|
@@ -152,8 +152,6 @@ export class MongoDialect extends AbstractDialect {
|
|
|
152
152
|
const { join, negate } = MongoDialect.GROUP_OPS[key];
|
|
153
153
|
const parts = MongoDialect.groupClauses(key, val)
|
|
154
154
|
.map((filterIt) => {
|
|
155
|
-
// A `QueryRaw` here would recurse forever: `buildQueryWhereAsMap` re-wraps it as
|
|
156
|
-
// `{ $and: [raw] }`, which lands back on this branch.
|
|
157
155
|
this.assertNoRaw(filterIt);
|
|
158
156
|
return this.renderFilter(entity, filterIt, opts, lookups);
|
|
159
157
|
})
|
|
@@ -187,7 +185,7 @@ export class MongoDialect extends AbstractDialect {
|
|
|
187
185
|
// `withDeleted()` or `hardDelete` on the parent must not un-hide trashed rows of the target, the
|
|
188
186
|
// same rule the SQL dialects' relation subqueries follow.
|
|
189
187
|
const targetCondition = (sizeVal === undefined ? val : {});
|
|
190
|
-
const targetScope = this.renderFilter(relEntity, this.
|
|
188
|
+
const targetScope = this.renderFilter(relEntity, this.scopedWhere(relMeta, targetCondition), opts);
|
|
191
189
|
lookups.temps.push(temp);
|
|
192
190
|
lookups.stages.push(this.relationLookup(meta, relOpts, relMeta, relEntity, targetScope, temp, tail, opts));
|
|
193
191
|
return sizeVal === undefined
|
|
@@ -218,7 +216,7 @@ export class MongoDialect extends AbstractDialect {
|
|
|
218
216
|
junctionLookup(meta, relOpts, relMeta, targetScope, temp, tail, opts) {
|
|
219
217
|
const throughEntity = relOpts.through();
|
|
220
218
|
const throughMeta = getMeta(throughEntity);
|
|
221
|
-
const junctionScope = this.renderFilter(throughEntity, this.
|
|
219
|
+
const junctionScope = this.renderFilter(throughEntity, this.scopedWhere(throughMeta, {}), opts);
|
|
222
220
|
const nested = REL_NESTED_KEY;
|
|
223
221
|
// Both ends are one column here - each `$lookup` matches one field against `_id` - so both sides
|
|
224
222
|
// must be sole-keyed. Sliced rather than indexed positionally: `references[1]` is the parent's
|
|
@@ -490,7 +488,7 @@ export class MongoDialect extends AbstractDialect {
|
|
|
490
488
|
const relEntity = relOpts.entity();
|
|
491
489
|
const relMeta = getMeta(relEntity);
|
|
492
490
|
const temp = sortCountField(key);
|
|
493
|
-
const targetScope = this.renderFilter(relEntity, this.
|
|
491
|
+
const targetScope = this.renderFilter(relEntity, this.scopedWhere(relMeta, {}), opts);
|
|
494
492
|
const tail = [{ $count: COUNT_ALIAS }];
|
|
495
493
|
stages.push(this.relationLookup(meta, relOpts, relMeta, relEntity, targetScope, temp, tail, opts), {
|
|
496
494
|
$addFields: { [temp]: { $ifNull: [{ $arrayElemAt: [`$${temp}.${COUNT_ALIAS}`, 0] }, 0] } },
|