@mikro-orm/core 7.2.2-dev.16 → 7.2.2-dev.17

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
@@ -1134,9 +1134,10 @@ export class EntityManager {
1134
1134
  const generatedFields = new Set();
1135
1135
  const allData = [];
1136
1136
  const allWhere = [];
1137
+ const dataIndexes = [];
1138
+ const result = [];
1137
1139
  const entities = new Map();
1138
1140
  const entitiesByData = new Map();
1139
- const entitiesByAllDataIdx = new Map();
1140
1141
  for (let i = 0; i < data.length; i++) {
1141
1142
  let row = data[i];
1142
1143
  let where;
@@ -1144,14 +1145,12 @@ export class EntityManager {
1144
1145
  const entity = row;
1145
1146
  if (helper(entity).__managed && helper(entity).__em === em && !this.config.get('upsertManaged')) {
1146
1147
  em.#entityFactory.mergeData(meta, entity, row, { initialized: true });
1147
- entities.set(entity, row);
1148
- entitiesByData.set(row, entity);
1148
+ result[i] = entity;
1149
1149
  continue;
1150
1150
  }
1151
1151
  where = helper(entity).getPrimaryKey();
1152
1152
  getOnCreateGeneratedFields(meta, entity).forEach(field => generatedFields.add(field));
1153
1153
  em.#entityFactory.assignDefaultValues(entity, meta);
1154
- entitiesByAllDataIdx.set(allData.length, entity);
1155
1154
  row = em.#comparator.prepareEntity(entity);
1156
1155
  }
1157
1156
  else {
@@ -1161,8 +1160,7 @@ export class EntityManager {
1161
1160
  const exists = em.#unitOfWork.getById(entityName, where, options.schema);
1162
1161
  if (exists) {
1163
1162
  em.assign(exists, row);
1164
- entities.set(exists, row);
1165
- entitiesByData.set(row, exists);
1163
+ result[i] = exists;
1166
1164
  continue;
1167
1165
  }
1168
1166
  }
@@ -1195,22 +1193,25 @@ export class EntityManager {
1195
1193
  validateParams(row, 'insert data');
1196
1194
  allData.push(row);
1197
1195
  allWhere.push(where);
1196
+ dataIndexes.push(i);
1198
1197
  }
1199
- if (entities.size === data.length) {
1200
- return [...entities.keys()];
1198
+ if (allData.length === 0) {
1199
+ return [...new Set(result)];
1201
1200
  }
1202
1201
  // `onCreate` generated values are for the insert clause only, they must not overwrite existing rows
1203
1202
  if (generatedFields.size > 0 && !options.onConflictMergeFields) {
1204
1203
  options.onConflictExcludeFields = [...(options.onConflictExcludeFields ?? []), ...generatedFields];
1205
1204
  }
1206
1205
  if (em.eventManager.hasListeners(EventType.beforeUpsert, meta)) {
1207
- for (const dto of data) {
1208
- const entity = entitiesByData.get(dto) ?? dto;
1206
+ for (const index of dataIndexes) {
1207
+ const entity = data[index];
1209
1208
  await em.eventManager.dispatchEvent(EventType.beforeUpsert, { entity, em, meta }, meta);
1210
1209
  }
1211
- for (const [idx, entity] of entitiesByAllDataIdx) {
1212
- allData[idx] = em.#comparator.prepareEntity(entity);
1213
- }
1210
+ dataIndexes.forEach((index, idx) => {
1211
+ if (Utils.isEntity(data[index])) {
1212
+ allData[idx] = em.#comparator.prepareEntity(data[index]);
1213
+ }
1214
+ });
1214
1215
  }
1215
1216
  const res = await em.withSessionContext(options.ctx ?? em.#transactionContext, ctx => em.driver.nativeUpdateMany(entityName, allWhere, allData, {
1216
1217
  upsert: true,
@@ -1218,15 +1219,16 @@ export class EntityManager {
1218
1219
  ...options,
1219
1220
  ctx,
1220
1221
  }));
1221
- entities.clear();
1222
- entitiesByData.clear();
1223
1222
  const loadPK = new Map();
1224
1223
  allData.forEach((row, i) => {
1225
- em.#unitOfWork.getChangeSetPersister().mapReturnedValues(Utils.isEntity(data[i]) ? data[i] : null, Utils.isEntity(data[i]) ? {} : data[i],
1224
+ // Managed inputs skipped by the SQL batch still occupy positions in `data`.
1225
+ const index = dataIndexes[i];
1226
+ const item = data[index];
1227
+ em.#unitOfWork.getChangeSetPersister().mapReturnedValues(Utils.isEntity(item) ? item : null, Utils.isEntity(item) ? {} : item,
1226
1228
  // A suppressed conflict omits its row; positional mapping would hydrate a different entity.
1227
1229
  res.rows?.length === allData.length ? res.rows[i] : undefined, meta, true);
1228
- const entity = Utils.isEntity(data[i])
1229
- ? data[i]
1230
+ const entity = Utils.isEntity(item)
1231
+ ? item
1230
1232
  : em.#entityFactory.create(entityName, row, {
1231
1233
  refresh: true,
1232
1234
  initialized: true,
@@ -1237,18 +1239,19 @@ export class EntityManager {
1237
1239
  }
1238
1240
  entities.set(entity, row);
1239
1241
  entitiesByData.set(row, entity);
1242
+ result[index] = entity;
1240
1243
  });
1241
1244
  // skip the reload only when RETURNING brought back a row for every input
1242
1245
  // (onConflictWhere can suppress writes, leaving some rows out)
1243
1246
  // oxfmt-ignore
1244
1247
  const uniqueFields = options.onConflictFields ?? (Utils.isPlainObject(allWhere[0]) ? Object.keys(allWhere[0]).flatMap(key => Utils.splitPrimaryKeys(key)) : meta.primaryKeys);
1245
1248
  const platform = this.getPlatform();
1246
- const returning = getOnConflictReturningFields(meta, data[0], uniqueFields, options, platform);
1249
+ const returning = getOnConflictReturningFields(meta, data[dataIndexes[0]], uniqueFields, options, platform);
1247
1250
  if (options.onConflictWhere && res.rows?.length !== allData.length) {
1248
1251
  returning.push(...meta.comparableProps.filter(p => !p.lazy && !p.embeddable).map(p => p.name));
1249
1252
  }
1250
1253
  const reloadFields = returning.length > 0 &&
1251
- !((platform.usesReturningStatement() || platform.usesOutputStatement()) && res.rows?.length === data.length);
1254
+ !((platform.usesReturningStatement() || platform.usesOutputStatement()) && res.rows?.length === allData.length);
1252
1255
  if (options.onConflictAction === 'ignore' || (!res.rows?.length && loadPK.size > 0) || reloadFields) {
1253
1256
  const unique = meta.hydrateProps.filter(p => !p.lazy).map(p => p.name);
1254
1257
  const add = new Set(propIndex !== false && propIndex >= 0
@@ -1258,7 +1261,8 @@ export class EntityManager {
1258
1261
  Utils.keys(cond).forEach(key => add.add(key));
1259
1262
  }
1260
1263
  const where = { $or: [] };
1261
- data.forEach((item, idx) => {
1264
+ dataIndexes.forEach((index, idx) => {
1265
+ const item = data[index];
1262
1266
  where.$or[idx] = {};
1263
1267
  const props = Array.isArray(uniqueFields) ? uniqueFields : Object.keys(item);
1264
1268
  props.forEach(prop => {
@@ -1328,7 +1332,7 @@ export class EntityManager {
1328
1332
  await em.eventManager.dispatchEvent(EventType.afterUpsert, { entity, em, meta }, meta);
1329
1333
  }
1330
1334
  }
1331
- return [...entities.keys()];
1335
+ return [...new Set(result)];
1332
1336
  }
1333
1337
  /**
1334
1338
  * Runs your callback wrapped inside a database transaction.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
- "version": "7.2.2-dev.16",
3
+ "version": "7.2.2-dev.17",
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.16';
156
+ static #ORM_VERSION = '7.2.2-dev.17';
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}`;