Skip to content

Commit

Permalink
fix: Fix TypeORM helper entity normalization robustness on relation w…
Browse files Browse the repository at this point in the history
…ith string data type (#959)
  • Loading branch information
ktutnik committed Jun 6, 2021
1 parent d267166 commit fb4a744
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 4 deletions.
12 changes: 8 additions & 4 deletions packages/typeorm/src/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,23 @@ function normalizeEntityNoCache(type: Class) {
}
const relations = storage.filterRelations(type)
for (const col of relations) {
const rawType: Class = (col as any).type()
const target = col.target as Function
if (typeof col.type === "string")
throw new Error(`Relation property ${target.name}.${col.propertyName} uses unsupported data type`)
const rawType: Class = col.type()
if (col.relationType === "many-to-many" || col.relationType === "one-to-many") {
const inverseProperty = inverseSideParser(col.inverseSideProperty as any)
const inverse = col.inverseSideProperty!
const inverseProperty = typeof inverse === "string" ? inverse : inverseSideParser(inverse)
const decorators = [
reflect.type(x => [rawType]),
entity.relation({ inverseProperty }),
authorize.readonly(),
authorize.writeonly()
]
Reflect.decorate(decorators, (col.target as Function).prototype, col.propertyName, void 0)
Reflect.decorate(decorators, target.prototype, col.propertyName, void 0)
}
else {
Reflect.decorate([reflect.type(x => rawType), entity.relation()], (col.target as Function).prototype, col.propertyName, void 0)
Reflect.decorate([reflect.type(x => rawType), entity.relation()], target.prototype, col.propertyName, void 0)
}
}
return { success: true }
Expand Down
57 changes: 57 additions & 0 deletions tests/behavior/typeorm/__snapshots__/typeorm.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,55 @@ Array [
]
`;

exports[`TypeOrm Facility Should able to reflect one to many relation with string inverse property 1`] = `
MyEntity {
"children": Array [
Child {
"id": 1,
"name": "Poo",
},
],
"id": 1,
"name": "Mimi",
}
`;

exports[`TypeOrm Facility Should able to reflect one to many relation with string inverse property 2`] = `
Array [
Object {
"name": "id",
"type": Number,
},
Object {
"name": "name",
"type": String,
},
Object {
"name": "children",
"type": Array [
Child,
],
},
]
`;

exports[`TypeOrm Facility Should able to reflect one to many relation with string inverse property 3`] = `
Array [
Object {
"name": "id",
"type": Number,
},
Object {
"name": "name",
"type": String,
},
Object {
"name": "entity",
"type": MyEntity,
},
]
`;

exports[`TypeOrm Facility Should able to reflect one to many with braced inverse entity 1`] = `
MyEntity {
"children": Array [
Expand Down Expand Up @@ -342,6 +391,14 @@ Array [
]
`;

exports[`TypeOrm Facility Should throw error when provided string type relation 1`] = `
Array [
Array [
[Error: Relation property Parent.entity uses unsupported data type],
],
]
`;

exports[`TypeOrm Update relation with ID Should able to update relation on one to many 1`] = `
Parent {
"child": Array [
Expand Down
54 changes: 54 additions & 0 deletions tests/behavior/typeorm/typeorm.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,36 @@ describe("TypeOrm", () => {
expect(extract(MyEntity)).toMatchSnapshot()
expect(extract(Child)).toMatchSnapshot()
})
it("Should able to reflect one to many relation with string inverse property", async () => {
@Entity()
class MyEntity {
@PrimaryGeneratedColumn()
id: number = 123
@Column()
name: string
@OneToMany(x => Child, "entity")
children: Child[]
}
@Entity()
class Child {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@ManyToOne(x => MyEntity, "children")
entity: MyEntity
}
await createApp([MyEntity, Child])
const parentRepo = getManager().getRepository(MyEntity)
const repo = getManager().getRepository(Child)
const parent = await parentRepo.insert({ name: "Mimi" })
const inserted = await repo.insert({ name: "Poo" })
await parentRepo.createQueryBuilder().relation("children").of(parent.raw).add(inserted.raw)
const result = await parentRepo.findOne(parent.raw, { relations: ["children"] })
expect(result).toMatchSnapshot()
expect(extract(MyEntity)).toMatchSnapshot()
expect(extract(Child)).toMatchSnapshot()
})
it("Should able to reflect one to many with curly braced inverse entity", async () => {
@Entity()
class MyEntity {
Expand Down Expand Up @@ -287,6 +317,29 @@ describe("TypeOrm", () => {
delete process.env.TYPEORM_ENTITIES
delete process.env.TYPEORM_SYNCHRONIZE
})
it("Should throw error when provided string type relation", async () => {
@Entity()
class Parent {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@OneToOne("MyEntity", "parent")
entity: any
}
@Entity()
class MyEntity {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@OneToOne("Parent")
@JoinColumn()
parent: Parent
}
const mock = await expectError(createApp([MyEntity, Parent]))
expect(mock.mock.calls).toMatchSnapshot()
})
})
describe("Update relation with ID", () => {
function createApp(entities: (string | Function)[], controller: Class) {
Expand Down Expand Up @@ -621,4 +674,5 @@ describe("TypeOrm", () => {
expect(body).toMatchSnapshot()
})
})

})

0 comments on commit fb4a744

Please sign in to comment.