Skip to content

Commit

Permalink
fix: Remove extra saving on serialization which breaks the chain (#9465)
Browse files Browse the repository at this point in the history
**What**
The extra serialization check hapen to break the serialization chain by reusing already serialized entities when they have been serialized from a different parents sequence
  • Loading branch information
adrien2p authored Oct 5, 2024
1 parent cc77ca1 commit ffc35f2
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 12 deletions.
109 changes: 109 additions & 0 deletions packages/core/utils/src/dal/mikro-orm/__fixtures__/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {
Cascade,
Collection,
Entity,
ManyToMany,
ManyToOne,
OneToMany,
PrimaryKey,
Expand All @@ -9,6 +11,104 @@ import {
} from "@mikro-orm/core"
import { Searchable } from "../decorators/searchable"

@Entity()
class Product {
@PrimaryKey()
id: string

@Property()
name: string

@OneToMany(() => ProductOption, (o) => o.product, {
cascade: ["soft-remove"] as any,
})
options = new Collection<ProductOption>(this)

@OneToMany(() => ProductVariant, (variant) => variant.product, {
cascade: ["soft-remove"] as any,
})
variants = new Collection<ProductVariant>(this)
}

@Entity()
class ProductOption {
@PrimaryKey()
id: string

@Property()
name: string

@ManyToOne(() => Product, {
persist: false,
nullable: true,
})
product: Product | null

@OneToMany(() => ProductOptionValue, (value) => value.option, {
cascade: [Cascade.PERSIST, "soft-remove" as any],
})
values = new Collection<ProductOptionValue>(this)
}

@Entity()
class ProductOptionValue {
@PrimaryKey()
id: string

@Property()
name: string

@ManyToOne(() => ProductOption, {
columnType: "text",
fieldName: "option_id",
mapToPk: true,
nullable: true,
onDelete: "cascade",
})
option_id: string | null

@ManyToOne(() => ProductOption, {
nullable: true,
persist: false,
})
option: ProductOption | null

@ManyToMany(() => ProductVariant, (variant) => variant.options)
variants = new Collection<ProductVariant>(this)
}

@Entity()
class ProductVariant {
@PrimaryKey()
id: string

@Property()
name: string

@ManyToOne(() => Product, {
columnType: "text",
nullable: true,
onDelete: "cascade",
fieldName: "product_id",
mapToPk: true,
})
product_id: string | null

@ManyToOne(() => Product, {
persist: false,
nullable: true,
})
product: Product | null

@ManyToMany(() => ProductOptionValue, "variants", {
owner: true,
pivotTable: "product_variant_option",
joinColumn: "variant_id",
inverseJoinColumn: "option_value_id",
})
options = new Collection<ProductOptionValue>(this)
}

// Circular dependency one level
@Entity()
class RecursiveEntity1 {
Expand Down Expand Up @@ -114,6 +214,11 @@ class DeepRecursiveEntity1 {
@Property({ nullable: true })
deleted_at: Date | null

@OneToMany(() => DeepRecursiveEntity3, (entity3) => entity3.entity1, {
cascade: ["soft-remove"] as any,
})
entity3 = new Collection<DeepRecursiveEntity3>(this)

@OneToMany(() => DeepRecursiveEntity2, (entity2) => entity2.entity1, {
cascade: ["soft-remove"] as any,
})
Expand Down Expand Up @@ -349,4 +454,8 @@ export {
RecursiveEntity2,
SearchableEntity1,
SearchableEntity2,
Product,
ProductOption,
ProductOptionValue,
ProductVariant,
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,24 @@ import { MikroORM } from "@mikro-orm/core"
import {
Entity1WithUnDecoratedProp,
Entity2WithUnDecoratedProp,
Product,
ProductOption,
ProductOptionValue,
ProductVariant,
} from "../__fixtures__/utils"
import { mikroOrmSerializer } from "../mikro-orm-serializer"

describe("mikroOrmSerializer", () => {
beforeEach(async () => {
await MikroORM.init({
entities: [Entity1WithUnDecoratedProp, Entity2WithUnDecoratedProp],
entities: [
Entity1WithUnDecoratedProp,
Entity2WithUnDecoratedProp,
Product,
ProductOption,
ProductOptionValue,
ProductVariant,
],
dbName: "test",
type: "postgresql",
})
Expand Down Expand Up @@ -119,4 +130,70 @@ describe("mikroOrmSerializer", () => {
],
})
})

it(`should properly serialize nested relations and sibling to not return parents into children`, async () => {
const productOptionValue = new ProductOptionValue()
productOptionValue.id = "1"
productOptionValue.name = "Product option value 1"
productOptionValue.option_id = "1"

const productOptions = new ProductOption()
productOptions.id = "1"
productOptions.name = "Product option 1"
productOptions.values.add(productOptionValue)

const productVariant = new ProductVariant()
productVariant.id = "1"
productVariant.name = "Product variant 1"
productVariant.options.add(productOptionValue)

const product = new Product()
product.id = "1"
product.name = "Product 1"
product.options.add(productOptions)
product.variants.add(productVariant)

const serialized = await mikroOrmSerializer(product)

expect(serialized).toEqual({
id: "1",
options: [
{
id: "1",
values: [
{
id: "1",
variants: [
{
id: "1",
name: "Product variant 1",
},
],
name: "Product option value 1",
option_id: "1",
},
],
name: "Product option 1",
},
],
variants: [
{
id: "1",
options: [
{
id: "1",
name: "Product option value 1",
option_id: "1",
option: {
id: "1",
name: "Product option 1",
},
},
],
name: "Product variant 1",
},
],
name: "Product 1",
})
})
})
12 changes: 1 addition & 11 deletions packages/core/utils/src/dal/mikro-orm/mikro-orm-serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,6 @@ export class EntitySerializer {
root.visited.add(entity)
}

// Virtually augment the serialization context
root.visitedSerialized ??= new Map()
const primaryKeysValues = Array.from(keys)
.map((key) => entity[key])
.join("-")

if (root.visitedSerialized.has(primaryKeysValues)) {
return root.visitedSerialized.get(primaryKeysValues)
}

;[...keys]
/** Medusa Custom properties filtering **/
.filter((prop) =>
Expand Down Expand Up @@ -242,7 +232,7 @@ export class EntitySerializer {
parents_
))
)
root.visitedSerialized.set(primaryKeysValues, ret)

return ret
}

Expand Down

0 comments on commit ffc35f2

Please sign in to comment.