test: add tests for self relationships (#10071)

Initially I thought that we will have to add special checks to allow relationships referencing itself. However, it turned out that not to be the case. Instead, it had more to do with how self relationships are defined in Mikro ORM.

In case of `belongsTo` relationship we have to define the other side as well either as a `hasMany` or `hasOne`. For example:

** The following code will fail, because no children are defined for the parent**
```ts
const user = model.define("user", {
  id: model.number(),
  username: model.text(),
  parent: model.belongsTo(() => user)
})
```

** Addition of children relationship will make things work**
```ts
const user = model.define("user", {
  id: model.number(),
  username: model.text(),
  parent: model.belongsTo(() => user, { mappedBy: "children" }),
  children: model.hasMany(() => user, { mappedBy: "parent" }),
})
```

We can see the similar setup here with our `ProductCategory` MikroORM entity. https://github.com/medusajs/medusa/blob/develop/packages/modules/product/src/models/product-category.ts#L87-L94

@adrien2p Correct me if I am wrong. But I have added the tests for now so that we know the behavior of self relationships
This commit is contained in:
Harminder Virk
2024-11-13 22:50:27 +05:30
committed by GitHub
parent 0ea57659e8
commit 98bf8c9006

View File

@@ -4702,6 +4702,236 @@ describe("Entity builder", () => {
},
})
})
test("define entity with relationship to itself via hasMany", () => {
const user = model.define("user", {
id: model.number(),
username: model.text(),
parent: model.belongsTo(() => user, { mappedBy: "children" }),
children: model.hasMany(() => user, { mappedBy: "parent" }),
})
const [User] = toMikroOrmEntities([user])
expectTypeOf(new User()).toMatchTypeOf<{
id: number
username: string
deleted_at: Date | null
parent: {
id: number
username: string
deleted_at: Date | null
}
children: {
id: number
username: string
deleted_at: Date | null
}[]
}>()
const metaData = MetadataStorage.getMetadataFromDecorator(User)
expect(metaData.className).toEqual("User")
expect(metaData.path).toEqual("User")
expect(metaData.properties).toEqual({
id: {
reference: "scalar",
type: "number",
columnType: "integer",
name: "id",
fieldName: "id",
nullable: false,
getter: false,
setter: false,
},
username: {
reference: "scalar",
type: "string",
columnType: "text",
name: "username",
fieldName: "username",
nullable: false,
getter: false,
setter: false,
},
parent: {
name: "parent",
reference: "m:1",
entity: "User",
persist: false,
nullable: false,
},
parent_id: {
name: "parent_id",
reference: "m:1",
entity: "User",
columnType: "text",
fieldName: "parent_id",
mapToPk: true,
nullable: false,
onDelete: undefined,
isForeignKey: true,
},
children: {
cascade: undefined,
entity: "User",
mappedBy: "parent",
name: "children",
orphanRemoval: true,
reference: "1:m",
},
created_at: {
reference: "scalar",
type: "date",
columnType: "timestamptz",
name: "created_at",
fieldName: "created_at",
defaultRaw: "now()",
onCreate: expect.any(Function),
nullable: false,
getter: false,
setter: false,
},
updated_at: {
reference: "scalar",
type: "date",
columnType: "timestamptz",
name: "updated_at",
fieldName: "updated_at",
defaultRaw: "now()",
onCreate: expect.any(Function),
onUpdate: expect.any(Function),
nullable: false,
getter: false,
setter: false,
},
deleted_at: {
reference: "scalar",
type: "date",
columnType: "timestamptz",
name: "deleted_at",
fieldName: "deleted_at",
nullable: true,
getter: false,
setter: false,
},
})
})
test("define relationship with self via hasOne", () => {
const user = model.define("user", {
id: model.number(),
username: model.text(),
parent: model.belongsTo(() => user, { mappedBy: "child" }),
child: model.hasOne(() => user, { mappedBy: "parent" }),
})
const [User] = toMikroOrmEntities([user])
expectTypeOf(new User()).toMatchTypeOf<{
id: number
username: string
deleted_at: Date | null
parent: {
id: number
username: string
deleted_at: Date | null
}
child: {
id: number
username: string
deleted_at: Date | null
}
}>()
const metaData = MetadataStorage.getMetadataFromDecorator(User)
expect(metaData.className).toEqual("User")
expect(metaData.path).toEqual("User")
expect(metaData.properties).toEqual({
id: {
reference: "scalar",
type: "number",
columnType: "integer",
name: "id",
fieldName: "id",
nullable: false,
getter: false,
setter: false,
},
username: {
reference: "scalar",
type: "string",
columnType: "text",
name: "username",
fieldName: "username",
nullable: false,
getter: false,
setter: false,
},
parent: {
name: "parent",
mappedBy: "child",
reference: "1:1",
entity: "User",
nullable: false,
onDelete: undefined,
owner: true,
},
parent_id: {
name: "parent_id",
type: "string",
columnType: "text",
isForeignKey: true,
persist: false,
reference: "scalar",
getter: false,
setter: false,
nullable: false,
},
child: {
cascade: undefined,
entity: "User",
mappedBy: "parent",
name: "child",
nullable: false,
reference: "1:1",
},
created_at: {
reference: "scalar",
type: "date",
columnType: "timestamptz",
name: "created_at",
fieldName: "created_at",
defaultRaw: "now()",
onCreate: expect.any(Function),
nullable: false,
getter: false,
setter: false,
},
updated_at: {
reference: "scalar",
type: "date",
columnType: "timestamptz",
name: "updated_at",
fieldName: "updated_at",
defaultRaw: "now()",
onCreate: expect.any(Function),
onUpdate: expect.any(Function),
nullable: false,
getter: false,
setter: false,
},
deleted_at: {
reference: "scalar",
type: "date",
columnType: "timestamptz",
name: "deleted_at",
fieldName: "deleted_at",
nullable: true,
getter: false,
setter: false,
},
})
})
})
describe("Entity builder | manyToMany", () => {