@mikro-orm/core 7.1.13-dev.8 → 7.1.13-dev.9

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
@@ -1,4 +1,4 @@
1
- import { getOnConflictReturningFields, getWhereCondition, resetUntouchedCollections } from './utils/upsert-utils.js';
1
+ import { getOnConflictReturningFields, getOnCreateGeneratedFields, getWhereCondition, resetUntouchedCollections, } from './utils/upsert-utils.js';
2
2
  import { Utils } from './utils/Utils.js';
3
3
  import { Cursor } from './utils/Cursor.js';
4
4
  import { QueryHelper } from './utils/QueryHelper.js';
@@ -793,6 +793,7 @@ export class EntityManager {
793
793
  }
794
794
  const meta = this.metadata.get(entityName);
795
795
  const convertCustomTypes = !Utils.isEntity(data);
796
+ let generatedFields = [];
796
797
  if (Utils.isEntity(data)) {
797
798
  entity = data;
798
799
  if (helper(entity).__managed && helper(entity).__em === em && !this.config.get('upsertManaged')) {
@@ -800,6 +801,7 @@ export class EntityManager {
800
801
  return entity;
801
802
  }
802
803
  where = helper(entity).getPrimaryKey();
804
+ generatedFields = getOnCreateGeneratedFields(meta, entity);
803
805
  em.#entityFactory.assignDefaultValues(entity, meta);
804
806
  data = em.#comparator.prepareEntity(entity);
805
807
  }
@@ -812,6 +814,7 @@ export class EntityManager {
812
814
  return em.assign(exists, data);
813
815
  }
814
816
  }
817
+ generatedFields = getOnCreateGeneratedFields(meta, data);
815
818
  em.#entityFactory.assignDefaultValues(data, meta, true);
816
819
  for (const key of Object.keys(data)) {
817
820
  const prop = meta.properties[key];
@@ -820,6 +823,10 @@ export class EntityManager {
820
823
  }
821
824
  }
822
825
  }
826
+ // `onCreate` generated values are for the insert clause only, they must not overwrite an existing row
827
+ if (generatedFields.length > 0 && !options.onConflictMergeFields) {
828
+ options.onConflictExcludeFields = [...(options.onConflictExcludeFields ?? []), ...generatedFields];
829
+ }
823
830
  where = getWhereCondition(meta, options.onConflictFields, data, where).where;
824
831
  data = QueryHelper.processObjectParams(data);
825
832
  validateParams(data, 'insert data');
@@ -939,6 +946,7 @@ export class EntityManager {
939
946
  }
940
947
  const meta = this.metadata.get(entityName);
941
948
  const convertCustomTypes = !Utils.isEntity(data[0]);
949
+ const generatedFields = new Set();
942
950
  const allData = [];
943
951
  const allWhere = [];
944
952
  const entities = new Map();
@@ -956,6 +964,7 @@ export class EntityManager {
956
964
  continue;
957
965
  }
958
966
  where = helper(entity).getPrimaryKey();
967
+ getOnCreateGeneratedFields(meta, entity).forEach(field => generatedFields.add(field));
959
968
  em.#entityFactory.assignDefaultValues(entity, meta);
960
969
  entitiesByAllDataIdx.set(allData.length, entity);
961
970
  row = em.#comparator.prepareEntity(entity);
@@ -972,6 +981,7 @@ export class EntityManager {
972
981
  continue;
973
982
  }
974
983
  }
984
+ getOnCreateGeneratedFields(meta, row).forEach(field => generatedFields.add(field));
975
985
  em.#entityFactory.assignDefaultValues(row, meta, true);
976
986
  for (const key of Object.keys(row)) {
977
987
  const prop = meta.properties[key];
@@ -1000,6 +1010,10 @@ export class EntityManager {
1000
1010
  if (entities.size === data.length) {
1001
1011
  return [...entities.keys()];
1002
1012
  }
1013
+ // `onCreate` generated values are for the insert clause only, they must not overwrite existing rows
1014
+ if (generatedFields.size > 0 && !options.onConflictMergeFields) {
1015
+ options.onConflictExcludeFields = [...(options.onConflictExcludeFields ?? []), ...generatedFields];
1016
+ }
1003
1017
  if (em.eventManager.hasListeners(EventType.beforeUpsert, meta)) {
1004
1018
  for (const dto of data) {
1005
1019
  const entity = entitiesByData.get(dto) ?? dto;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
- "version": "7.1.13-dev.8",
3
+ "version": "7.1.13-dev.9",
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.1.13-dev.8';
156
+ static #ORM_VERSION = '7.1.13-dev.9';
157
157
  /**
158
158
  * Checks if the argument is instance of `Object`. Returns false for arrays.
159
159
  */
@@ -1,8 +1,16 @@
1
- import type { EntityData, EntityMetadata, FilterQuery } from '../typings.js';
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
4
  /** @internal */
5
5
  export declare function getOnConflictFields<T>(meta: EntityMetadata<T> | undefined, data: EntityData<T>, uniqueFields: (keyof T)[] | Raw, options: UpsertOptions<T>): (keyof T)[];
6
+ /**
7
+ * Detects properties that will get their value generated by an `onCreate` hook during the upsert,
8
+ * i.e. those with an `onCreate` hook and no value provided. Such values are meant for the insert
9
+ * clause only and must not overwrite an existing row via the `on conflict do update set` clause.
10
+ * The property filter mirrors `EntityFactory.assignDefaultValues`.
11
+ * @internal
12
+ */
13
+ export declare function getOnCreateGeneratedFields<T extends object>(meta: EntityMetadata<T>, data: T | EntityData<T>): EntityKey<T>[];
6
14
  /** @internal */
7
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)[] | '*';
8
16
  /** @internal */
@@ -72,6 +72,22 @@ export function getOnConflictFields(meta, data, uniqueFields, options) {
72
72
  }
73
73
  return keys;
74
74
  }
75
+ /**
76
+ * Detects properties that will get their value generated by an `onCreate` hook during the upsert,
77
+ * i.e. those with an `onCreate` hook and no value provided. Such values are meant for the insert
78
+ * clause only and must not overwrite an existing row via the `on conflict do update set` clause.
79
+ * The property filter mirrors `EntityFactory.assignDefaultValues`.
80
+ * @internal
81
+ */
82
+ export function getOnCreateGeneratedFields(meta, data) {
83
+ return meta.props
84
+ .filter(prop => prop.onCreate &&
85
+ !prop.embedded &&
86
+ ![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) &&
87
+ !(prop.getter && !prop.setter) &&
88
+ data[prop.name] == null)
89
+ .map(prop => prop.name);
90
+ }
75
91
  /** @internal */
76
92
  export function getOnConflictReturningFields(meta, data, uniqueFields, options) {
77
93
  /* v8 ignore next */