mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
feat: leftJoinAndMapOne and innerJoinAndMapOne map result to entity (#9354)
* feat: leftJoinAndMapOne and innerJoinAndMapOne now map correctly with QueryBuilder
When joining to a query builder instead of an entity or table name, typeorm now
correctly supports mapping the result to an entity. This introduces a new argument
to the join functions to supply the join attributes with a source of meta data
for the mapping
For example:
const loadedPost = await connection.manager
.createQueryBuilder(Post, "post")
.innerJoinAndMapOne(
"post.tag",
qb => qb.from(Tag, "tag"),
"tag",
"tag.id = post.tagId",
undefined,
// The next argument is new - it helps typeorm know which entity
// to use to complete the mapping for a query builder.
Tag
)
.where("post.id = :id", { id: post.id })
.getOne()
* style: Auto Formatting
* trigger CircleCI
---------
Co-authored-by: Umed Khudoiberdiev <pleerock.me@gmail.com>
Co-authored-by: Dmitry Zotov <dmzt08@gmail.com>
This commit is contained in:
parent
de1228deac
commit
947ffc3432
@ -46,6 +46,11 @@ export class JoinAttribute {
|
||||
*/
|
||||
isMappingMany?: boolean
|
||||
|
||||
/**
|
||||
* Useful when the joined expression is a custom query to support mapping.
|
||||
*/
|
||||
mapAsEntity?: Function | string
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
@ -199,6 +204,11 @@ export class JoinAttribute {
|
||||
if (this.connection.hasMetadata(this.entityOrProperty))
|
||||
return this.connection.getMetadata(this.entityOrProperty)
|
||||
|
||||
// Overriden mapping entity provided for leftJoinAndMapOne with custom query builder
|
||||
if (this.mapAsEntity && this.connection.hasMetadata(this.mapAsEntity)) {
|
||||
return this.connection.getMetadata(this.mapAsEntity)
|
||||
}
|
||||
|
||||
return undefined
|
||||
|
||||
/*if (typeof this.entityOrProperty === "string") { // entityOrProperty is a custom table
|
||||
|
||||
@ -717,6 +717,7 @@ export class SelectQueryBuilder<Entity extends ObjectLiteral>
|
||||
alias: string,
|
||||
condition?: string,
|
||||
parameters?: ObjectLiteral,
|
||||
mapAsEntity?: Function | string,
|
||||
): this
|
||||
|
||||
/**
|
||||
@ -781,6 +782,7 @@ export class SelectQueryBuilder<Entity extends ObjectLiteral>
|
||||
alias: string,
|
||||
condition?: string,
|
||||
parameters?: ObjectLiteral,
|
||||
mapAsEntity?: Function | string,
|
||||
): this {
|
||||
this.addSelect(alias)
|
||||
this.join(
|
||||
@ -791,6 +793,7 @@ export class SelectQueryBuilder<Entity extends ObjectLiteral>
|
||||
parameters,
|
||||
mapToProperty,
|
||||
false,
|
||||
mapAsEntity,
|
||||
)
|
||||
return this
|
||||
}
|
||||
@ -905,6 +908,7 @@ export class SelectQueryBuilder<Entity extends ObjectLiteral>
|
||||
alias: string,
|
||||
condition?: string,
|
||||
parameters?: ObjectLiteral,
|
||||
mapAsEntity?: Function | string,
|
||||
): this
|
||||
|
||||
/**
|
||||
@ -969,6 +973,7 @@ export class SelectQueryBuilder<Entity extends ObjectLiteral>
|
||||
alias: string,
|
||||
condition?: string,
|
||||
parameters?: ObjectLiteral,
|
||||
mapAsEntity?: Function | string,
|
||||
): this {
|
||||
this.addSelect(alias)
|
||||
this.join(
|
||||
@ -979,6 +984,7 @@ export class SelectQueryBuilder<Entity extends ObjectLiteral>
|
||||
parameters,
|
||||
mapToProperty,
|
||||
false,
|
||||
mapAsEntity,
|
||||
)
|
||||
return this
|
||||
}
|
||||
@ -2008,6 +2014,7 @@ export class SelectQueryBuilder<Entity extends ObjectLiteral>
|
||||
parameters?: ObjectLiteral,
|
||||
mapToProperty?: string,
|
||||
isMappingMany?: boolean,
|
||||
mapAsEntity?: Function | string,
|
||||
): void {
|
||||
this.setParameters(parameters || {})
|
||||
|
||||
@ -2016,6 +2023,7 @@ export class SelectQueryBuilder<Entity extends ObjectLiteral>
|
||||
this.expressionMap,
|
||||
)
|
||||
joinAttribute.direction = direction
|
||||
joinAttribute.mapAsEntity = mapAsEntity
|
||||
joinAttribute.mapToProperty = mapToProperty
|
||||
joinAttribute.isMappingMany = isMappingMany
|
||||
joinAttribute.entityOrProperty = entityOrProperty // relationName
|
||||
|
||||
@ -540,6 +540,36 @@ describe("query builder > joins", () => {
|
||||
}),
|
||||
))
|
||||
|
||||
it("should load and map selected data when query builder used as join argument", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const tag = new Tag()
|
||||
tag.name = "audi"
|
||||
await connection.manager.save(tag)
|
||||
|
||||
const post = new Post()
|
||||
post.title = "about China"
|
||||
post.tag = tag
|
||||
await connection.manager.save(post)
|
||||
|
||||
const loadedPost = await connection.manager
|
||||
.createQueryBuilder(Post, "post")
|
||||
.leftJoinAndMapOne(
|
||||
"post.tag",
|
||||
(qb) => qb.from(Tag, "tag"),
|
||||
"tag",
|
||||
"tag.id = post.tagId",
|
||||
undefined,
|
||||
Tag,
|
||||
)
|
||||
.where("post.id = :id", { id: post.id })
|
||||
.getOne()
|
||||
|
||||
expect(loadedPost!.tag).to.not.be.undefined
|
||||
expect(loadedPost!.tag.id).to.be.equal(1)
|
||||
}),
|
||||
))
|
||||
|
||||
it("should load and map selected data when data will given from same entity but with different conditions", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
@ -961,6 +991,36 @@ describe("query builder > joins", () => {
|
||||
}),
|
||||
))
|
||||
|
||||
it("should load and map selected data when query builder used as join argument", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
const tag = new Tag()
|
||||
tag.name = "audi"
|
||||
await connection.manager.save(tag)
|
||||
|
||||
const post = new Post()
|
||||
post.title = "about China"
|
||||
post.tag = tag
|
||||
await connection.manager.save(post)
|
||||
|
||||
const loadedPost = await connection.manager
|
||||
.createQueryBuilder(Post, "post")
|
||||
.innerJoinAndMapOne(
|
||||
"post.tag",
|
||||
(qb) => qb.from(Tag, "tag"),
|
||||
"tag",
|
||||
"tag.id = post.tagId",
|
||||
undefined,
|
||||
Tag,
|
||||
)
|
||||
.where("post.id = :id", { id: post.id })
|
||||
.getOne()
|
||||
|
||||
expect(loadedPost!.tag).to.not.be.undefined
|
||||
expect(loadedPost!.tag.id).to.be.equal(1)
|
||||
}),
|
||||
))
|
||||
|
||||
it("should load and map selected data when data will given from same entity but with different conditions", () =>
|
||||
Promise.all(
|
||||
connections.map(async (connection) => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user