Skip to content

Commit

Permalink
fix: Create correct children with STI
Browse files Browse the repository at this point in the history
This commit fixes the `create` function for EntityManager and Repository
to create entities of correct type when using Single Table Inheritance.
Refactors the otherwise repeated code into a new function on
EntityMetadata.
  • Loading branch information
felix-gohla committed May 24, 2022
1 parent a799d9f commit 2e53d6f
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 37 deletions.
43 changes: 33 additions & 10 deletions src/metadata/EntityMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -829,31 +829,54 @@ export class EntityMetadata {
relationsAndValues.push([
relation,
subValue,
this.getInverseEntityMetadata(subValue, relation),
EntityMetadata.getInverseEntityMetadata(
subValue,
relation,
),
]),
)
} else if (value) {
relationsAndValues.push([
relation,
value,
this.getInverseEntityMetadata(value, relation),
EntityMetadata.getInverseEntityMetadata(value, relation),
])
}
})
return relationsAndValues
}

private getInverseEntityMetadata(
/**
* In the case of SingleTableInheritance, find the correct child metadata
* for a given value.
*
* @param value The value to find the metadata for.
* @returns The found metadata for the child entity or the base metadata if no child was found.
*/
findChildMetadata(value: any): EntityMetadata {
// Check for single table inheritance and find the correct metadata in that case.
// Goal is to use the correct discriminator as we could have a repository
// for an (abstract) base class and thus the target would not match.
if (
this.inheritancePattern === "STI" &&
this.childEntityMetadatas.length > 0
) {
return this.childEntityMetadatas.find(
(meta) => value.constructor === meta.target,
) || this
}
return this
}

// -------------------------------------------------------------------------
// Private Static Methods
// -------------------------------------------------------------------------

private static getInverseEntityMetadata(
value: any,
relation: RelationMetadata,
): EntityMetadata {
const childEntityMetadata =
relation.inverseEntityMetadata.childEntityMetadatas.find(
(metadata) => metadata.target === value.constructor,
)
return childEntityMetadata
? childEntityMetadata
: relation.inverseEntityMetadata
return relation.inverseEntityMetadata.findChildMetadata(value)
}

// -------------------------------------------------------------------------
Expand Down
21 changes: 3 additions & 18 deletions src/persistence/EntityPersistExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,24 +81,9 @@ export class EntityPersistExecutor {
if (entityTarget === Object)
throw new CannotDetermineEntityError(this.mode)

let metadata = this.connection.getMetadata(entityTarget)

// Check for single table inheritance and find the correct metadata in that case.
// Goal is to use the correct discriminator as we could have a repository
// for an (abstract) base class and thus the target would not match.
if (
metadata.inheritancePattern === "STI" &&
metadata.childEntityMetadatas.length > 0
) {
const matchingChildMetadata =
metadata.childEntityMetadatas.find(
(meta) =>
entity.constructor === meta.target,
)
if (matchingChildMetadata) {
metadata = matchingChildMetadata
}
}
let metadata = this.connection
.getMetadata(entityTarget)
.findChildMetadata(entity)

subjects.push(
new Subject({
Expand Down
29 changes: 20 additions & 9 deletions src/query-builder/transformer/PlainObjectToNewEntityTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,20 +82,24 @@ export class PlainObjectToNewEntityTransformer {
)
})

const inverseEntityMetadata =
relation.inverseEntityMetadata.findChildMetadata(
objectRelatedValueItem,
)

// if such item already exist then merge new data into it, if its not we create a new entity and merge it into the array
if (!objectRelatedValueEntity) {
objectRelatedValueEntity =
relation.inverseEntityMetadata.create(
undefined,
{ fromDeserializer: true },
)
inverseEntityMetadata.create(undefined, {
fromDeserializer: true,
})
entityRelatedValue.push(objectRelatedValueEntity)
}

this.groupAndTransform(
objectRelatedValueEntity,
objectRelatedValueItem,
relation.inverseEntityMetadata,
inverseEntityMetadata,
getLazyRelationsPromiseValue,
)
})
Expand All @@ -110,18 +114,25 @@ export class PlainObjectToNewEntityTransformer {
return
}

const inverseEntityMetadata =
relation.inverseEntityMetadata.findChildMetadata(
objectRelatedValue,
)

if (!entityRelatedValue) {
entityRelatedValue =
relation.inverseEntityMetadata.create(undefined, {
entityRelatedValue = inverseEntityMetadata.create(
undefined,
{
fromDeserializer: true,
})
},
)
relation.setEntityValue(entity, entityRelatedValue)
}

this.groupAndTransform(
entityRelatedValue,
objectRelatedValue,
relation.inverseEntityMetadata,
inverseEntityMetadata,
getLazyRelationsPromiseValue,
)
}
Expand Down

0 comments on commit 2e53d6f

Please sign in to comment.