@mikro-orm/sql 7.2.2-dev.9 → 7.3.0-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.
|
@@ -419,7 +419,11 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
419
419
|
if ((col.udt_name === 'geometry' || col.udt_name === 'geography') && col.format_type) {
|
|
420
420
|
type = col.format_type;
|
|
421
421
|
}
|
|
422
|
-
|
|
422
|
+
// pgvector stores the dimension in atttypmod for all three of its vector types
|
|
423
|
+
if (['vector', 'halfvec', 'sparsevec'].includes(type) &&
|
|
424
|
+
col.length == null &&
|
|
425
|
+
col.custom_length != null &&
|
|
426
|
+
col.custom_length !== -1) {
|
|
423
427
|
col.length = col.custom_length;
|
|
424
428
|
}
|
|
425
429
|
if (col.length != null && !type.endsWith(`(${col.length})`) && !['text', 'date'].includes(type)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/sql",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.3.0-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",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@mikro-orm/core": "^7.2.1"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@mikro-orm/core": "7.
|
|
56
|
+
"@mikro-orm/core": "7.3.0-dev.0"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">= 22.17.0"
|
|
@@ -127,7 +127,7 @@ export declare class NativeQueryBuilder implements Subquery {
|
|
|
127
127
|
as(alias: string): this;
|
|
128
128
|
toRaw(): RawQueryFragment;
|
|
129
129
|
protected compileSelect(): void;
|
|
130
|
-
/** Whether this COUNT query needs a subquery wrapper
|
|
130
|
+
/** Whether this COUNT query needs a subquery wrapper: multi-column distinct, or `distinct on` (keeps the null group). */
|
|
131
131
|
protected needsCountSubquery(): boolean;
|
|
132
132
|
protected getFields(countSubquery?: boolean): string;
|
|
133
133
|
protected compileInsert(): void;
|
|
@@ -330,12 +330,12 @@ export class NativeQueryBuilder {
|
|
|
330
330
|
this.parts.push(`)${asKeyword}${this.quote('dcnt')}`);
|
|
331
331
|
}
|
|
332
332
|
}
|
|
333
|
-
/** Whether this COUNT query needs a subquery wrapper
|
|
333
|
+
/** Whether this COUNT query needs a subquery wrapper: multi-column distinct, or `distinct on` (keeps the null group). */
|
|
334
334
|
needsCountSubquery() {
|
|
335
335
|
return (this.type === QueryType.COUNT &&
|
|
336
336
|
!!this.options.distinct &&
|
|
337
|
-
this.options.select.length > 1 &&
|
|
338
|
-
|
|
337
|
+
((this.options.select.length > 1 && !this.platform.supportsMultiColumnCountDistinct()) ||
|
|
338
|
+
!!this.options.distinctOn));
|
|
339
339
|
}
|
|
340
340
|
getFields(countSubquery) {
|
|
341
341
|
if (!this.options.select || this.options.select.length === 0) {
|
package/query/QueryBuilder.js
CHANGED
|
@@ -257,7 +257,11 @@ export class QueryBuilder {
|
|
|
257
257
|
if (field) {
|
|
258
258
|
this.#state.fields = Utils.asArray(field);
|
|
259
259
|
}
|
|
260
|
-
else if (
|
|
260
|
+
else if (this.#state.distinctOn) {
|
|
261
|
+
this.#state.fields = this.#state.distinctOn;
|
|
262
|
+
distinct = true;
|
|
263
|
+
}
|
|
264
|
+
else if (distinct || this.#state.flags.has(QueryFlag.DISTINCT) || this.hasToManyJoins()) {
|
|
261
265
|
this.#state.fields = this.mainAlias.meta.primaryKeys;
|
|
262
266
|
}
|
|
263
267
|
else {
|
|
@@ -1566,7 +1570,7 @@ export class QueryBuilder {
|
|
|
1566
1570
|
return;
|
|
1567
1571
|
}
|
|
1568
1572
|
if (prop?.embedded || (prop?.kind === ReferenceKind.EMBEDDED && prop.object)) {
|
|
1569
|
-
const name = prop.embeddedPath?.join('.') ?? prop.fieldNames[0];
|
|
1573
|
+
const name = prop.formula ? prop.name : (prop.embeddedPath?.join('.') ?? prop.fieldNames[0]);
|
|
1570
1574
|
const aliased = this.#state.aliases[a] ? `${a}.${name}` : name;
|
|
1571
1575
|
ret.push(getFieldName(aliased, customAlias));
|
|
1572
1576
|
return;
|
|
@@ -1581,11 +1585,11 @@ export class QueryBuilder {
|
|
|
1581
1585
|
}
|
|
1582
1586
|
const nest = (prop) => {
|
|
1583
1587
|
for (const childProp of Object.values(prop.embeddedProps)) {
|
|
1584
|
-
if (childProp.persist === false) {
|
|
1588
|
+
if (childProp.persist === false && !childProp.formula) {
|
|
1585
1589
|
continue;
|
|
1586
1590
|
}
|
|
1587
1591
|
if (childProp.fieldNames && (childProp.kind !== ReferenceKind.EMBEDDED || childProp.object)) {
|
|
1588
|
-
const name = childProp.fieldNames[0];
|
|
1592
|
+
const name = childProp.formula ? childProp.name : childProp.fieldNames[0];
|
|
1589
1593
|
ret.push(getFieldName(this.#state.aliases[a] ? `${a}.${name}` : name));
|
|
1590
1594
|
}
|
|
1591
1595
|
else {
|
|
@@ -1666,7 +1670,8 @@ export class QueryBuilder {
|
|
|
1666
1670
|
return `${currentAlias}.${embeddedProp.fieldNames[0]}`;
|
|
1667
1671
|
}
|
|
1668
1672
|
}
|
|
1669
|
-
|
|
1673
|
+
const name = embeddedProp?.formula ? embeddedProp.name : (embeddedProp?.fieldNames?.[0] ?? propName);
|
|
1674
|
+
return `${currentAlias}.${name}`;
|
|
1670
1675
|
}
|
|
1671
1676
|
// Handle relations - auto-join if not the last part
|
|
1672
1677
|
if (prop.kind === ReferenceKind.MANY_TO_ONE ||
|
|
@@ -1759,6 +1764,9 @@ export class QueryBuilder {
|
|
|
1759
1764
|
case QueryType.COUNT: {
|
|
1760
1765
|
const fields = this.#state.fields.map(f => this.helper.mapper(f, this.type, undefined, undefined, schema));
|
|
1761
1766
|
qb.count(fields, this.#state.flags.has(QueryFlag.DISTINCT));
|
|
1767
|
+
if (this.#state.distinctOn && this.#state.flags.has(QueryFlag.DISTINCT)) {
|
|
1768
|
+
qb.distinctOn(this.prepareFields(this.#state.distinctOn, 'where', schema));
|
|
1769
|
+
}
|
|
1762
1770
|
this.helper.processJoins(qb, this.#state.joins, joinSchema, schemaOverride);
|
|
1763
1771
|
break;
|
|
1764
1772
|
}
|
|
@@ -2322,7 +2330,10 @@ export class QueryBuilder {
|
|
|
2322
2330
|
const fieldName = this.helper.mapper(field, this.type, undefined, null);
|
|
2323
2331
|
// virtual fields (e.g. `qb.as(...)`) have no column to reference inside `min()`; inline their
|
|
2324
2332
|
// expression instead, as a select alias is not resolvable there on some dialects (e.g. PostgreSQL)
|
|
2325
|
-
const virtual = !prop
|
|
2333
|
+
const virtual = (!prop || prop.persist === false) &&
|
|
2334
|
+
!prop?.formula &&
|
|
2335
|
+
!prop?.hasConvertToJSValueSQL &&
|
|
2336
|
+
!pks.includes(fieldName)
|
|
2326
2337
|
? this.resolveVirtualField(f, fieldName)
|
|
2327
2338
|
: undefined;
|
|
2328
2339
|
const expr = virtual ? virtual.expr : this.platform.quoteIdentifier(fieldName);
|
|
@@ -112,7 +112,7 @@ export class QueryBuilderHelper {
|
|
|
112
112
|
const aliasPrefix = isTableNameAliasRequired ? resolvedAlias + '.' : '';
|
|
113
113
|
const fkIdx2 = prop?.fieldNames.findIndex(name => name === f) ?? -1;
|
|
114
114
|
const fkIdx = fkIdx2 === -1 ? 0 : fkIdx2;
|
|
115
|
-
if (a === prop?.embedded?.[0]) {
|
|
115
|
+
if (a === prop?.embedded?.[0] && !prop.formula) {
|
|
116
116
|
return aliasPrefix + prop.fieldNames[fkIdx];
|
|
117
117
|
}
|
|
118
118
|
const noPrefix = prop?.persist === false;
|
|
@@ -120,12 +120,13 @@ export class QueryBuilderHelper {
|
|
|
120
120
|
return raw(this.prefix(field, isTableNameAliasRequired));
|
|
121
121
|
}
|
|
122
122
|
if (prop?.formula) {
|
|
123
|
-
const
|
|
123
|
+
const formulaAlias = isTableAlias ? a : this.#alias;
|
|
124
|
+
const alias2 = this.#platform.quoteIdentifier(formulaAlias).toString();
|
|
124
125
|
const aliasName = alias === undefined ? prop.fieldNames[0] : alias;
|
|
125
126
|
const as = aliasName === null ? '' : ` as ${this.#platform.quoteIdentifier(aliasName)}`;
|
|
126
127
|
const meta = this.#aliasMap[a]?.meta ?? this.#metadata.get(this.#entityName);
|
|
127
128
|
const table = this.createFormulaTable(alias2, meta, schema);
|
|
128
|
-
const columns = meta.createColumnMappingObject(p => this.getTPTAliasForProperty(p.name,
|
|
129
|
+
const columns = meta.createColumnMappingObject(p => this.getTPTAliasForProperty(p.name, formulaAlias), alias2);
|
|
129
130
|
let value = this.#driver.evaluateFormula(prop.formula, columns, table);
|
|
130
131
|
if (!this.isTableNameAliasRequired(type)) {
|
|
131
132
|
value = value.replaceAll(alias2 + '.', '');
|