feat: support dot notation syntax for nested relations (#739)
This commit is contained in:
parent
2e376ad656
commit
6f6b4da9a9
@ -710,7 +710,7 @@ describe('paginate', () => {
|
|||||||
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&search=Garfield')
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&search=Garfield')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should load nested relations', async () => {
|
it('should load nested relations (object notation)', async () => {
|
||||||
const config: PaginateConfig<CatEntity> = {
|
const config: PaginateConfig<CatEntity> = {
|
||||||
relations: { home: { pillows: true } },
|
relations: { home: { pillows: true } },
|
||||||
sortableColumns: ['id', 'name'],
|
sortableColumns: ['id', 'name'],
|
||||||
@ -743,6 +743,39 @@ describe('paginate', () => {
|
|||||||
expect(result.data[0].home.pillows).toStrictEqual(cat.home.pillows)
|
expect(result.data[0].home.pillows).toStrictEqual(cat.home.pillows)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should load nested relations (array notation)', async () => {
|
||||||
|
const config: PaginateConfig<CatEntity> = {
|
||||||
|
relations: ['home.pillows'],
|
||||||
|
sortableColumns: ['id', 'name'],
|
||||||
|
searchableColumns: ['name'],
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
search: 'Garfield',
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatEntity>(query, catRepo, config)
|
||||||
|
|
||||||
|
const cat = clone(cats[1])
|
||||||
|
const catHomesClone = clone(catHomes[1])
|
||||||
|
const catHomePillowsClone3 = clone(catHomePillows[3])
|
||||||
|
delete catHomePillowsClone3.home
|
||||||
|
const catHomePillowsClone4 = clone(catHomePillows[4])
|
||||||
|
delete catHomePillowsClone4.home
|
||||||
|
const catHomePillowsClone5 = clone(catHomePillows[5])
|
||||||
|
delete catHomePillowsClone5.home
|
||||||
|
|
||||||
|
catHomesClone.countCat = cats.filter((cat) => cat.id === catHomesClone.cat.id).length
|
||||||
|
catHomesClone.pillows = [catHomePillowsClone3, catHomePillowsClone4, catHomePillowsClone5]
|
||||||
|
cat.home = catHomesClone
|
||||||
|
delete cat.home.cat
|
||||||
|
|
||||||
|
expect(result.meta.search).toStrictEqual('Garfield')
|
||||||
|
expect(result.data).toStrictEqual([cat])
|
||||||
|
expect(result.data[0].home).toBeDefined()
|
||||||
|
expect(result.data[0].home.pillows).toStrictEqual(cat.home.pillows)
|
||||||
|
})
|
||||||
|
|
||||||
it('should throw an error when nonexistent relation loaded', async () => {
|
it('should throw an error when nonexistent relation loaded', async () => {
|
||||||
const config: PaginateConfig<CatEntity> = {
|
const config: PaginateConfig<CatEntity> = {
|
||||||
relations: <any>['homee'],
|
relations: <any>['homee'],
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
FindOptionsRelations,
|
FindOptionsRelations,
|
||||||
ObjectLiteral,
|
ObjectLiteral,
|
||||||
FindOptionsUtils,
|
FindOptionsUtils,
|
||||||
|
FindOptionsRelationByString,
|
||||||
} from 'typeorm'
|
} from 'typeorm'
|
||||||
import { PaginateQuery } from './decorator'
|
import { PaginateQuery } from './decorator'
|
||||||
import { ServiceUnavailableException, Logger } from '@nestjs/common'
|
import { ServiceUnavailableException, Logger } from '@nestjs/common'
|
||||||
@ -28,6 +29,7 @@ import {
|
|||||||
getQueryUrlComponents,
|
getQueryUrlComponents,
|
||||||
} from './helper'
|
} from './helper'
|
||||||
import { addFilter, FilterOperator, FilterSuffix } from './filter'
|
import { addFilter, FilterOperator, FilterSuffix } from './filter'
|
||||||
|
import { OrmUtils } from 'typeorm/util/OrmUtils'
|
||||||
|
|
||||||
const logger: Logger = new Logger('nestjs-paginate')
|
const logger: Logger = new Logger('nestjs-paginate')
|
||||||
|
|
||||||
@ -61,7 +63,7 @@ export enum PaginationType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface PaginateConfig<T> {
|
export interface PaginateConfig<T> {
|
||||||
relations?: FindOptionsRelations<T> | RelationColumn<T>[]
|
relations?: FindOptionsRelations<T> | RelationColumn<T>[] | FindOptionsRelationByString
|
||||||
sortableColumns: Column<T>[]
|
sortableColumns: Column<T>[]
|
||||||
nullSort?: 'first' | 'last'
|
nullSort?: 'first' | 'last'
|
||||||
searchableColumns?: Column<T>[]
|
searchableColumns?: Column<T>[]
|
||||||
@ -123,16 +125,9 @@ export async function paginate<T extends ObjectLiteral>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.relations) {
|
if (config.relations) {
|
||||||
// relations: ["relation"]
|
const relations = Array.isArray(config.relations)
|
||||||
if (Array.isArray(config.relations)) {
|
? OrmUtils.propertyPathsToTruthyObject(config.relations)
|
||||||
config.relations.forEach((relation) => {
|
: config.relations
|
||||||
queryBuilder.leftJoinAndSelect(
|
|
||||||
`${queryBuilder.alias}.${relation}`,
|
|
||||||
`${queryBuilder.alias}_${relation}_rel`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// relations: {relation:true}
|
|
||||||
const createQueryBuilderRelations = (
|
const createQueryBuilderRelations = (
|
||||||
prefix: string,
|
prefix: string,
|
||||||
relations: FindOptionsRelations<T> | RelationColumn<T>[],
|
relations: FindOptionsRelations<T> | RelationColumn<T>[],
|
||||||
@ -148,16 +143,11 @@ export async function paginate<T extends ObjectLiteral>(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (typeof relationSchema === 'object') {
|
if (typeof relationSchema === 'object') {
|
||||||
createQueryBuilderRelations(
|
createQueryBuilderRelations(relationName, relationSchema, `${alias ?? prefix}_${relationName}_rel`)
|
||||||
relationName,
|
|
||||||
relationSchema,
|
|
||||||
`${alias ?? prefix}_${relationName}_rel`
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
createQueryBuilderRelations(queryBuilder.alias, config.relations)
|
createQueryBuilderRelations(queryBuilder.alias, relations)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let nullSort: 'NULLS LAST' | 'NULLS FIRST' | undefined = undefined
|
let nullSort: 'NULLS LAST' | 'NULLS FIRST' | undefined = undefined
|
||||||
|
Loading…
Reference in New Issue
Block a user