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