@mikro-orm/sql 7.1.15-dev.14 → 7.1.15-dev.16

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.
@@ -915,8 +915,11 @@ export class AbstractSqlDriver extends DatabaseDriver {
915
915
  if (!options.upsert && options.unionWhere?.length) {
916
916
  where = (await this.applyUnionWhere(meta, where, options, true));
917
917
  }
918
- // a TPT table declaring the version property is bumped even when only other tables of the hierarchy changed
919
- if (Utils.hasObjectKeys(data) || (meta.inheritanceType === 'tpt' && meta.ownsVersionProperty())) {
918
+ if (options.upsert && meta.tptParent) {
919
+ res = await this.nativeUpdateMany(entityName, [where], [data], options);
920
+ }
921
+ else if (Utils.hasObjectKeys(data) || (meta.inheritanceType === 'tpt' && meta.ownsVersionProperty())) {
922
+ // a TPT table declaring the version property is bumped even when only other tables of the hierarchy changed
920
923
  const qb = this.createQueryBuilder(entityName, options.ctx, 'write', options.convertCustomTypes, options.loggerContext).withSchema(this.getSchemaName(meta, options));
921
924
  qb.setAbortOptions(pickAbortOptions(options));
922
925
  if (options.upsert) {
@@ -958,13 +961,38 @@ export class AbstractSqlDriver extends DatabaseDriver {
958
961
  options.convertCustomTypes ??= true;
959
962
  const meta = this.metadata.get(entityName);
960
963
  if (options.upsert) {
964
+ if (meta.tptParent) {
965
+ // TPT parent tables go first, the PK they provide is the conflict target of this table
966
+ await this.nativeUpdateMany(meta.tptParent.class, where, data, options);
967
+ for (const [i, row] of data.entries()) {
968
+ if (meta.primaryKeys.some(pk => row[pk] == null)) {
969
+ const found = await this.findOne(meta.tptParent.class, where[i], {
970
+ fields: meta.primaryKeys,
971
+ ctx: options.ctx,
972
+ connectionType: 'write',
973
+ schema: options.schema,
974
+ });
975
+ meta.primaryKeys.forEach(pk => (row[pk] = found?.[pk]));
976
+ }
977
+ }
978
+ options = { ...options, onConflictFields: meta.primaryKeys, onConflictWhere: undefined };
979
+ }
961
980
  const uniqueFields = options.onConflictFields ??
962
981
  (Utils.isPlainObject(where[0])
963
982
  ? Object.keys(where[0]).flatMap(key => Utils.splitPrimaryKeys(key))
964
983
  : meta.primaryKeys);
965
984
  const qb = this.createQueryBuilder(entityName, options.ctx, 'write', options.convertCustomTypes, options.loggerContext).withSchema(this.getSchemaName(meta, options));
966
985
  qb.setAbortOptions(pickAbortOptions(options));
967
- const returning = getOnConflictReturningFields(meta, data[0], uniqueFields, options);
986
+ let returning = getOnConflictReturningFields(meta, data[0], uniqueFields, options);
987
+ if (meta.inheritanceType === 'tpt') {
988
+ // each TPT table only carries its own columns, the entity is reloaded instead of mapping the returned rows
989
+ const own = (key) => meta.primaryKeys.includes(key) ||
990
+ this.getTableProps(meta).some(prop => prop.name === key.split('.')[0]);
991
+ data = data.map(row => Object.fromEntries(Object.entries(row).filter(([key]) => own(key))));
992
+ options.onConflictMergeFields = options.onConflictMergeFields?.filter(f => own(f));
993
+ options.onConflictExcludeFields = options.onConflictExcludeFields?.filter(f => own(f));
994
+ returning = [];
995
+ }
968
996
  qb.insert(data)
969
997
  .onConflict(uniqueFields)
970
998
  .returning(returning);
@@ -978,7 +1006,8 @@ export class AbstractSqlDriver extends DatabaseDriver {
978
1006
  if (options.onConflictWhere) {
979
1007
  qb.where(options.onConflictWhere);
980
1008
  }
981
- return this.rethrow(qb.execute('run', false));
1009
+ const res = await this.rethrow(qb.execute('run', false));
1010
+ return meta.inheritanceType === 'tpt' ? { ...res, row: undefined, rows: [] } : res;
982
1011
  }
983
1012
  const collections = options.processCollections ? data.map(d => this.extractManyToMany(meta, d)) : [];
984
1013
  const keys = new Set();
@@ -1067,7 +1096,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
1067
1096
  sql += `, `;
1068
1097
  }
1069
1098
  sql = sql.substring(0, sql.length - 2) + ' where ';
1070
- const pkProps = meta.primaryKeys.concat(...meta.concurrencyCheckKeys);
1099
+ const pkProps = meta.primaryKeys.concat(...meta.getOwnConcurrencyCheckKeys());
1071
1100
  const pks = Utils.flatten(pkProps.map(pk => meta.properties[pk].fieldNames));
1072
1101
  const useTupleIn = pks.length <= 1 || this.platform.allowsComparingTuples();
1073
1102
  const condTemplate = useTupleIn
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/sql",
3
- "version": "7.1.15-dev.14",
3
+ "version": "7.1.15-dev.16",
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.1.14"
54
54
  },
55
55
  "peerDependencies": {
56
- "@mikro-orm/core": "7.1.15-dev.14"
56
+ "@mikro-orm/core": "7.1.15-dev.16"
57
57
  },
58
58
  "engines": {
59
59
  "node": ">= 22.17.0"
@@ -904,6 +904,8 @@ export class QueryBuilder {
904
904
  if (this.type === QueryType.INSERT) {
905
905
  const returningProps = meta.hydrateProps
906
906
  .filter(prop => prop.returning || (prop.persist !== false && ((prop.primary && prop.autoincrement) || prop.defaultRaw)))
907
+ // a TPT table can only return its own columns
908
+ .filter(prop => meta.inheritanceType !== 'tpt' || prop.primary || meta.ownProps.some(p => p.name === prop.name))
907
909
  .filter(prop => !data || !(prop.name in data));
908
910
  if (returningProps.length > 0) {
909
911
  qb.returning(Utils.flatten(returningProps.map(prop => prop.fieldNames)));