@mikro-orm/core 7.2.2-dev.6 → 7.2.2-dev.7

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/EntityManager.js CHANGED
@@ -994,13 +994,14 @@ export class EntityManager {
994
994
  });
995
995
  const uniqueFields = options.onConflictFields ??
996
996
  (Utils.isPlainObject(where) ? Object.keys(where) : meta.primaryKeys);
997
- const returning = getOnConflictReturningFields(meta, data, uniqueFields, options);
997
+ const platform = this.getPlatform();
998
+ const returning = getOnConflictReturningFields(meta, data, uniqueFields, options, platform);
998
999
  if (options.onConflictWhere && !ret.row) {
999
1000
  returning.push(...Object.keys(data));
1000
1001
  }
1001
1002
  if (options.onConflictAction === 'ignore' ||
1002
1003
  !helper(entity).hasPrimaryKey() ||
1003
- (returning.length > 0 && !(this.getPlatform().usesReturningStatement() && ret.row))) {
1004
+ (returning.length > 0 && !((platform.usesReturningStatement() || platform.usesOutputStatement()) && ret.row))) {
1004
1005
  const where = {};
1005
1006
  if (Array.isArray(uniqueFields)) {
1006
1007
  for (const prop of uniqueFields) {
@@ -1230,11 +1231,13 @@ export class EntityManager {
1230
1231
  // (onConflictWhere can suppress writes, leaving some rows out)
1231
1232
  // oxfmt-ignore
1232
1233
  const uniqueFields = options.onConflictFields ?? (Utils.isPlainObject(allWhere[0]) ? Object.keys(allWhere[0]).flatMap(key => Utils.splitPrimaryKeys(key)) : meta.primaryKeys);
1233
- const returning = getOnConflictReturningFields(meta, data[0], uniqueFields, options);
1234
+ const platform = this.getPlatform();
1235
+ const returning = getOnConflictReturningFields(meta, data[0], uniqueFields, options, platform);
1234
1236
  if (options.onConflictWhere && res.rows?.length !== allData.length) {
1235
1237
  returning.push(...meta.comparableProps.filter(p => !p.lazy && !p.embeddable).map(p => p.name));
1236
1238
  }
1237
- const reloadFields = returning.length > 0 && !(this.getPlatform().usesReturningStatement() && res.rows?.length === data.length);
1239
+ const reloadFields = returning.length > 0 &&
1240
+ !((platform.usesReturningStatement() || platform.usesOutputStatement()) && res.rows?.length === data.length);
1238
1241
  if (options.onConflictAction === 'ignore' || (!res.rows?.length && loadPK.size > 0) || reloadFields) {
1239
1242
  const unique = meta.hydrateProps.filter(p => !p.lazy).map(p => p.name);
1240
1243
  const add = new Set(propIndex !== false && propIndex >= 0
@@ -267,7 +267,7 @@ export declare class UniversalPropertyOptionsBuilder<in out Value, in out Option
267
267
  autoincrement: false;
268
268
  }, IncludeKeys>, IncludeKeys>;
269
269
  /**
270
- * Add the property to the `returning` statement.
270
+ * Add the property to the `returning` clause of inserts, updates and upserts, reloading the database value into the entity.
271
271
  */
272
272
  returning(returning?: boolean): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
273
273
  /**
@@ -88,7 +88,7 @@ export class UniversalPropertyOptionsBuilder {
88
88
  return this.assignOptions({ autoincrement });
89
89
  }
90
90
  /**
91
- * Add the property to the `returning` statement.
91
+ * Add the property to the `returning` clause of inserts, updates and upserts, reloading the database value into the entity.
92
92
  */
93
93
  returning(returning = true) {
94
94
  return this.assignOptions({ returning });
@@ -128,6 +128,8 @@ export declare class MetadataDiscovery {
128
128
  private initRelation;
129
129
  /** Resolves the `through` option of a virtual to-one relation into a read-only formula property. */
130
130
  private initThroughRelation;
131
+ /** `returning` is only honoured for physical columns that can be hydrated back into the entity. */
132
+ private initReturning;
131
133
  private initColumnType;
132
134
  private getMappedType;
133
135
  private getPrefix;
@@ -174,6 +174,7 @@ export class MetadataDiscovery {
174
174
  this.initRelation(p);
175
175
  this.initThroughRelation(m, p);
176
176
  this.initColumnType(p);
177
+ this.initReturning(p);
177
178
  });
178
179
  forEachProp((m, p) => this.initIndexes(m, p));
179
180
  filtered.forEach(meta => this.autoWireBidirectionalProperties(meta));
@@ -2129,6 +2130,16 @@ export class MetadataDiscovery {
2129
2130
  prop.persist = false;
2130
2131
  prop.formula = columns => this.#platform.getThroughRelationFormula(prop, columns);
2131
2132
  }
2133
+ /** `returning` is only honoured for physical columns that can be hydrated back into the entity. */
2134
+ initReturning(prop) {
2135
+ const owning = prop.kind === ReferenceKind.SCALAR ||
2136
+ prop.kind === ReferenceKind.MANY_TO_ONE ||
2137
+ (prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner) ||
2138
+ (prop.kind === ReferenceKind.EMBEDDED && prop.object);
2139
+ if (prop.returning && (!owning || prop.persist === false || prop.hydrate === false || prop.formula)) {
2140
+ prop.returning = false;
2141
+ }
2142
+ }
2132
2143
  initColumnType(prop) {
2133
2144
  this.initUnsigned(prop);
2134
2145
  // Get the target properties for FK relations - use targetKey property if specified, otherwise PKs
@@ -175,7 +175,7 @@ export interface PropertyOptions<Owner> {
175
175
  */
176
176
  autoincrement?: boolean;
177
177
  /**
178
- * Add the property to the `returning` statement.
178
+ * Add the property to the `returning` clause of inserts, updates and upserts, reloading the database value into the entity.
179
179
  */
180
180
  returning?: boolean;
181
181
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
- "version": "7.2.2-dev.6",
3
+ "version": "7.2.2-dev.7",
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",
package/utils/Utils.js CHANGED
@@ -153,7 +153,7 @@ export function parseJsonSafe(value) {
153
153
  /** Collection of general-purpose utility methods used throughout the ORM. */
154
154
  export class Utils {
155
155
  static PK_SEPARATOR = '~~~';
156
- static #ORM_VERSION = '7.2.2-dev.6';
156
+ static #ORM_VERSION = '7.2.2-dev.7';
157
157
  /** Default session variable name backing an RLS filter argument (`current_setting('mikro.<filter>.<arg>')`). */
158
158
  static getRlsSettingName(filterName, argName) {
159
159
  return `mikro.${filterName}.${argName}`;
@@ -1,6 +1,7 @@
1
1
  import type { EntityData, EntityKey, EntityMetadata, FilterQuery } from '../typings.js';
2
2
  import type { UpsertOptions } from '../drivers/IDatabaseDriver.js';
3
3
  import { type Raw } from '../utils/RawQueryFragment.js';
4
+ import type { Platform } from '../platforms/Platform.js';
4
5
  /** @internal */
5
6
  export declare function getOnConflictFields<T>(meta: EntityMetadata<T> | undefined, data: EntityData<T>, uniqueFields: (keyof T)[] | Raw, options: UpsertOptions<T>): (keyof T)[];
6
7
  /**
@@ -12,7 +13,7 @@ export declare function getOnConflictFields<T>(meta: EntityMetadata<T> | undefin
12
13
  */
13
14
  export declare function getOnCreateGeneratedFields<T extends object>(meta: EntityMetadata<T>, data: T | EntityData<T>): EntityKey<T>[];
14
15
  /** @internal */
15
- export declare function getOnConflictReturningFields<T, P extends string>(meta: EntityMetadata<T> | undefined, data: EntityData<T>, uniqueFields: (keyof T)[] | Raw, options: UpsertOptions<T, P>): (keyof T)[] | '*';
16
+ export declare function getOnConflictReturningFields<T, P extends string>(meta: EntityMetadata<T> | undefined, data: EntityData<T>, uniqueFields: (keyof T)[] | Raw, options: UpsertOptions<T, P>, platform?: Platform): (keyof T)[] | '*';
16
17
  /** @internal */
17
18
  export declare function getWhereCondition<T extends object>(meta: EntityMetadata<T>, onConflictFields: (keyof T)[] | Raw | undefined, data: EntityData<T>, where: FilterQuery<T>): {
18
19
  where: FilterQuery<T>;
@@ -89,11 +89,15 @@ export function getOnCreateGeneratedFields(meta, data) {
89
89
  .map(prop => prop.name);
90
90
  }
91
91
  /** @internal */
92
- export function getOnConflictReturningFields(meta, data, uniqueFields, options) {
92
+ export function getOnConflictReturningFields(meta, data, uniqueFields, options, platform) {
93
93
  /* v8 ignore next */
94
94
  if (!meta) {
95
95
  return '*';
96
96
  }
97
+ // props with explicit `returning` hint are reloaded even when supplied, as the database might normalize them
98
+ const returning = platform?.usesReturningStatement() || platform?.usesOutputStatement()
99
+ ? meta.props.filter(p => p.returning).map(p => p.name)
100
+ : [];
97
101
  const keys = meta.comparableProps
98
102
  .filter(p => {
99
103
  if (p.lazy || p.embeddable) {
@@ -112,17 +116,17 @@ export function getOnConflictReturningFields(meta, data, uniqueFields, options)
112
116
  keys.push(meta.versionProperty);
113
117
  }
114
118
  if (options.onConflictAction === 'ignore') {
115
- return keys;
119
+ return Utils.unique([...keys, ...returning]);
116
120
  }
117
121
  if (options.onConflictMergeFields) {
118
122
  const onConflictMergeFields = expandFields(meta, options.onConflictMergeFields);
119
- return keys.filter(key => !onConflictMergeFields.includes(key));
123
+ return Utils.unique([...keys.filter(key => !onConflictMergeFields.includes(key)), ...returning]);
120
124
  }
121
125
  if (options.onConflictExcludeFields) {
122
126
  const onConflictExcludeFields = expandFields(meta, options.onConflictExcludeFields);
123
- return [...new Set(keys.concat(...onConflictExcludeFields))];
127
+ return Utils.unique([...keys, ...onConflictExcludeFields, ...returning]);
124
128
  }
125
- return keys.filter(key => !(key in data));
129
+ return Utils.unique([...keys.filter(key => !(key in data)), ...returning]);
126
130
  }
127
131
  function getPropertyValue(obj, key) {
128
132
  if (!key.includes('.')) {