@mikro-orm/sql 7.1.5-dev.9 → 7.1.6-dev.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/AbstractSqlDriver.js +19 -0
- package/dialects/postgresql/PostgreSqlSchemaHelper.js +6 -4
- package/package.json +3 -3
- package/query/ObjectCriteriaNode.js +5 -1
- package/query/QueryBuilderHelper.js +4 -3
- package/schema/DatabaseSchema.js +3 -2
- package/schema/SchemaHelper.d.ts +11 -0
- package/schema/SchemaHelper.js +18 -0
- package/schema/SqlSchemaGenerator.js +1 -1
- package/typings.d.ts +5 -2
package/AbstractSqlDriver.js
CHANGED
|
@@ -1248,6 +1248,11 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
1248
1248
|
if (owners.length === 0) {
|
|
1249
1249
|
return {};
|
|
1250
1250
|
}
|
|
1251
|
+
// The pivot order is recomputed via `getPivotOrderBy`, so the parent `populateOrderBy` must not leak
|
|
1252
|
+
// into the pivot subquery — its keys reference the parent entity, not the pivot (GH #7910).
|
|
1253
|
+
if (options?.populateOrderBy != null) {
|
|
1254
|
+
options = { ...options, populateOrderBy: undefined };
|
|
1255
|
+
}
|
|
1251
1256
|
const pivotMeta = this.metadata.get(prop.pivotEntity);
|
|
1252
1257
|
if (prop.discriminatorColumn && QueryHelper.isUnionTargetPolymorphic(prop)) {
|
|
1253
1258
|
return this.loadFromUnionTargetPolymorphicPivotTable(prop, owners, where, orderBy, ctx, options, pivotJoin);
|
|
@@ -2209,6 +2214,20 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
2209
2214
|
const join = qb.getJoinForPath(path, { matchPopulateJoins: true });
|
|
2210
2215
|
const propAlias = qb.getAliasForJoinPath(join ?? path, { matchPopulateJoins: true }) ?? parentAlias;
|
|
2211
2216
|
if (!join) {
|
|
2217
|
+
// an owner to-one relation that is not joined (e.g. ordering a populated collection by such
|
|
2218
|
+
// a relation's primary key) can be ordered by its local FK columns, matching the `select-in`
|
|
2219
|
+
// and `balanced` strategies instead of silently dropping the clause
|
|
2220
|
+
if (prop.owner &&
|
|
2221
|
+
[ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) &&
|
|
2222
|
+
Utils.isPlainObject(childOrder)) {
|
|
2223
|
+
for (const childField of Utils.getObjectQueryKeys(childOrder)) {
|
|
2224
|
+
const idx = prop.referencedPKs.indexOf(childField);
|
|
2225
|
+
const order = childOrder[childField];
|
|
2226
|
+
if (idx !== -1 && order) {
|
|
2227
|
+
orderBy.push({ [`${parentAlias}.${prop.joinColumns[idx]}`]: order });
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2212
2231
|
continue;
|
|
2213
2232
|
}
|
|
2214
2233
|
if (join &&
|
|
@@ -603,7 +603,8 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
603
603
|
.map(p => {
|
|
604
604
|
const dir = p.direction === 'in' ? '' : `${p.direction.toUpperCase()} `;
|
|
605
605
|
const def = p.defaultRaw ? ` default ${p.defaultRaw}` : '';
|
|
606
|
-
|
|
606
|
+
const name = p.name ? `${this.platform.quoteIdentifier(p.name)} ` : '';
|
|
607
|
+
return `${dir}${name}${p.type}${def}`;
|
|
607
608
|
})
|
|
608
609
|
.join(', ');
|
|
609
610
|
}
|
|
@@ -614,15 +615,16 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
614
615
|
return signature.split(/,(?![^()]*\))/).map(part => {
|
|
615
616
|
const trimmed = part.trim();
|
|
616
617
|
// INOUT before IN/OUT, with required trailing space so identifiers like `input` aren't
|
|
617
|
-
// mis-parsed as a direction keyword.
|
|
618
|
-
|
|
618
|
+
// mis-parsed as a direction keyword. The name is optional — `pg_get_function_arguments`
|
|
619
|
+
// omits it for unnamed parameters (e.g. `text`), leaving just the type.
|
|
620
|
+
const match = /^(?:(INOUT|VARIADIC|IN|OUT)\s+)?(?:(?:"((?:[^"]|"")+)"|([\w$]+))\s+)?(.+?)(?:\s+default\s+.+)?$/i.exec(trimmed);
|
|
619
621
|
/* v8 ignore next 3: defensive guard for unexpected `pg_get_function_arguments` output shapes */
|
|
620
622
|
if (!match) {
|
|
621
623
|
throw new Error(`Could not parse PostgreSQL routine parameter signature: ${JSON.stringify(trimmed)}`);
|
|
622
624
|
}
|
|
623
625
|
const dirRaw = (match[1] ?? 'in').toLowerCase();
|
|
624
626
|
const direction = dirRaw === 'inout' ? 'inout' : dirRaw === 'out' ? 'out' : 'in';
|
|
625
|
-
const name = match[2] != null ? match[2].replaceAll('""', '"') : match[3];
|
|
627
|
+
const name = match[2] != null ? match[2].replaceAll('""', '"') : (match[3] ?? '');
|
|
626
628
|
return {
|
|
627
629
|
name,
|
|
628
630
|
type: match[4].trim(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/sql",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.6-dev.0",
|
|
4
4
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"data-mapper",
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"kysely": "0.29.2"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@mikro-orm/core": "^7.1.
|
|
53
|
+
"@mikro-orm/core": "^7.1.5"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@mikro-orm/core": "7.1.
|
|
56
|
+
"@mikro-orm/core": "7.1.6-dev.0"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">= 22.17.0"
|
|
@@ -39,7 +39,11 @@ export class ObjectCriteriaNode extends CriteriaNode {
|
|
|
39
39
|
throw new Error('Mixing collection operators with other filters is not allowed.');
|
|
40
40
|
}
|
|
41
41
|
const payload = this.payload[key].unwrap();
|
|
42
|
-
|
|
42
|
+
// entities with a fixed schema must resolve the `from` table's own schema in the subquery,
|
|
43
|
+
// otherwise a nested operator inherits the root entity's schema (GH #7894); for wildcard or
|
|
44
|
+
// schema-less entities the schema is resolved dynamically and needs to be carried over
|
|
45
|
+
const fixedSchema = parentMeta.schema && parentMeta.schema !== '*';
|
|
46
|
+
const qb2 = qb.clone(true, fixedSchema ? undefined : ['schema']);
|
|
43
47
|
const joinAlias = qb2.getNextAlias(this.prop.targetMeta.class);
|
|
44
48
|
const sub = qb2
|
|
45
49
|
.from(parentMeta.class)
|
|
@@ -600,6 +600,8 @@ export class QueryBuilderHelper {
|
|
|
600
600
|
}
|
|
601
601
|
return `(${tmp.join(', ')})`;
|
|
602
602
|
}
|
|
603
|
+
// array custom types (e.g. `$contains`/`$overlap` on `string[]` columns) are converted to a single
|
|
604
|
+
// array literal, so we emit a single bound parameter — not one per element wrapped in a tuple
|
|
603
605
|
if (prop?.customType instanceof ArrayType) {
|
|
604
606
|
const item = prop.customType.convertToDatabaseValue(value, this.#platform, {
|
|
605
607
|
fromQuery: true,
|
|
@@ -607,10 +609,9 @@ export class QueryBuilderHelper {
|
|
|
607
609
|
mode: 'query',
|
|
608
610
|
});
|
|
609
611
|
params.push(item);
|
|
612
|
+
return '?';
|
|
610
613
|
}
|
|
611
|
-
|
|
612
|
-
value.forEach(p => params.push(p));
|
|
613
|
-
}
|
|
614
|
+
value.forEach(p => params.push(p));
|
|
614
615
|
return `(${value.map(() => '?').join(', ')})`;
|
|
615
616
|
}
|
|
616
617
|
if (value === null) {
|
package/schema/DatabaseSchema.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ReferenceKind, isRaw, } from '@mikro-orm/core';
|
|
2
2
|
import { DatabaseTable } from './DatabaseTable.js';
|
|
3
|
+
import { normalizeViewDefinition } from './SchemaHelper.js';
|
|
3
4
|
import { getTablePartitioning } from './partitioning.js';
|
|
4
5
|
/**
|
|
5
6
|
* @internal
|
|
@@ -364,7 +365,7 @@ export class DatabaseSchema {
|
|
|
364
365
|
}
|
|
365
366
|
static getViewDefinition(meta, em, platform) {
|
|
366
367
|
if (typeof meta.expression === 'string') {
|
|
367
|
-
return meta.expression;
|
|
368
|
+
return normalizeViewDefinition(meta.expression);
|
|
368
369
|
}
|
|
369
370
|
// Expression is a function, need to evaluate it
|
|
370
371
|
/* v8 ignore next */
|
|
@@ -378,7 +379,7 @@ export class DatabaseSchema {
|
|
|
378
379
|
}
|
|
379
380
|
/* v8 ignore next */
|
|
380
381
|
if (typeof result === 'string') {
|
|
381
|
-
return result;
|
|
382
|
+
return normalizeViewDefinition(result);
|
|
382
383
|
}
|
|
383
384
|
/* v8 ignore next */
|
|
384
385
|
if (isRaw(result)) {
|
package/schema/SchemaHelper.d.ts
CHANGED
|
@@ -6,6 +6,17 @@ import type { DatabaseSchema } from './DatabaseSchema.js';
|
|
|
6
6
|
import type { DatabaseTable } from './DatabaseTable.js';
|
|
7
7
|
/** Flattens `;\n` boundaries so the schema-generator's statement splitter doesn't break the routine DDL apart. Other whitespace is preserved. */
|
|
8
8
|
export declare function stripStatementNewlines(body: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Strips SQL line comments and blank lines from a view definition. Comments are dropped by the
|
|
11
|
+
* database on `create view` anyway, and a `--` comment would otherwise comment out the rest of the
|
|
12
|
+
* definition once newlines are collapsed; blank lines act as statement separators in the
|
|
13
|
+
* schema-generator's statement splitter, which would break the view DDL apart.
|
|
14
|
+
*
|
|
15
|
+
* Comment stripping is not string-literal aware, so a `--` inside a string literal (or `a--b` style
|
|
16
|
+
* arithmetic) is treated as a comment — an accepted tradeoff to avoid a full SQL tokenizer.
|
|
17
|
+
* @see https://github.com/mikro-orm/mikro-orm/issues/7875
|
|
18
|
+
*/
|
|
19
|
+
export declare function normalizeViewDefinition(definition: string): string;
|
|
9
20
|
/** Base class for database-specific schema helpers. Provides SQL generation for DDL operations. */
|
|
10
21
|
export declare abstract class SchemaHelper {
|
|
11
22
|
protected readonly platform: AbstractSqlPlatform;
|
package/schema/SchemaHelper.js
CHANGED
|
@@ -3,6 +3,24 @@ import { isRaw, Utils, } from '@mikro-orm/core';
|
|
|
3
3
|
export function stripStatementNewlines(body) {
|
|
4
4
|
return body.replace(/;[\t ]*\r?\n/g, '; ');
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* Strips SQL line comments and blank lines from a view definition. Comments are dropped by the
|
|
8
|
+
* database on `create view` anyway, and a `--` comment would otherwise comment out the rest of the
|
|
9
|
+
* definition once newlines are collapsed; blank lines act as statement separators in the
|
|
10
|
+
* schema-generator's statement splitter, which would break the view DDL apart.
|
|
11
|
+
*
|
|
12
|
+
* Comment stripping is not string-literal aware, so a `--` inside a string literal (or `a--b` style
|
|
13
|
+
* arithmetic) is treated as a comment — an accepted tradeoff to avoid a full SQL tokenizer.
|
|
14
|
+
* @see https://github.com/mikro-orm/mikro-orm/issues/7875
|
|
15
|
+
*/
|
|
16
|
+
export function normalizeViewDefinition(definition) {
|
|
17
|
+
return definition
|
|
18
|
+
.replace(/--[^\n]*/g, '')
|
|
19
|
+
.split('\n')
|
|
20
|
+
.filter(line => line.trim() !== '')
|
|
21
|
+
.join('\n')
|
|
22
|
+
.trim();
|
|
23
|
+
}
|
|
6
24
|
/** Base class for database-specific schema helpers. Provides SQL generation for DDL operations. */
|
|
7
25
|
export class SchemaHelper {
|
|
8
26
|
platform;
|
|
@@ -130,7 +130,7 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator {
|
|
|
130
130
|
await this.execute(this.helper.disableForeignKeysSQL());
|
|
131
131
|
}
|
|
132
132
|
const schema = options?.schema ?? this.config.get('schema', this.platform.getDefaultSchemaName());
|
|
133
|
-
for (const meta of this.
|
|
133
|
+
for (const meta of this.getOrderedMetadataForClear(schema).reverse()) {
|
|
134
134
|
try {
|
|
135
135
|
await this.driver
|
|
136
136
|
.createQueryBuilder(meta.class, this.em?.getTransactionContext(), 'write', false)
|
package/typings.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Generated, Kysely } from 'kysely';
|
|
2
|
-
import type { CheckCallback, DeferMode, Dictionary, EntityName, EntityProperty, EntitySchemaWithMeta, FilterQuery, GroupOperator, IndexColumnOptions, InferEntityName, Opt, Primary, PrimaryProperty, QueryFlag, QueryOrderMap, RawQueryFragment, RoutineIgnoreField, Scalar, Type } from '@mikro-orm/core';
|
|
2
|
+
import type { CheckCallback, DeferMode, Dictionary, EntityName, EntityProperty, EntitySchemaWithMeta, ExtractDefineEntityProperties, FilterQuery, GroupOperator, IndexColumnOptions, InferEntityName, Opt, Primary, PrimaryProperty, QueryFlag, QueryOrderMap, RawQueryFragment, RoutineIgnoreField, Scalar, Type } from '@mikro-orm/core';
|
|
3
3
|
import type { JoinType, QueryType } from './query/enums.js';
|
|
4
4
|
import type { DatabaseSchema } from './schema/DatabaseSchema.js';
|
|
5
5
|
import type { DatabaseTable } from './schema/DatabaseTable.js';
|
|
@@ -307,7 +307,10 @@ export interface ICriteriaNode<T extends object> {
|
|
|
307
307
|
getPivotPath(path: string): string;
|
|
308
308
|
}
|
|
309
309
|
export type MaybeReturnType<T> = T extends (...args: any[]) => infer R ? R : T;
|
|
310
|
-
export type InferEntityProperties<Schema> = Schema extends EntitySchemaWithMeta<any, any, any,
|
|
310
|
+
export type InferEntityProperties<Schema> = Schema extends EntitySchemaWithMeta<any, any, any, infer Base, infer Properties> ? MergeInheritedProperties<Base, Properties> : never;
|
|
311
|
+
type MergeInheritedProperties<Base, Properties extends Record<string, any>> = [
|
|
312
|
+
ExtractDefineEntityProperties<Base>
|
|
313
|
+
] extends [infer BaseProps extends Record<string, any>] ? [BaseProps] extends [never] ? Properties : Omit<BaseProps, keyof Properties> & Properties : Properties;
|
|
311
314
|
export type InferKyselyDB<TEntities extends {
|
|
312
315
|
name: string;
|
|
313
316
|
}, TOptions extends MikroKyselyPluginOptions = {}> = MapValueAsTable<MapTableName<TEntities, TOptions>, TOptions>;
|