fix: fixed filtering by entity field that is neither in relations and not loaded eagerly (#770)

This commit is contained in:
Vitalii Samofal 2023-10-04 08:20:18 +01:00 committed by GitHub
parent 098a21d225
commit 5f64f1ccbf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 104 additions and 4 deletions

View File

@ -1,5 +1,5 @@
import { Repository, In, DataSource, TypeORMError, Like } from 'typeorm'
import { Paginated, paginate, PaginateConfig, NO_PAGINATION } from './paginate'
import { DataSource, In, Like, Repository, TypeORMError } from 'typeorm'
import { NO_PAGINATION, paginate, PaginateConfig, Paginated } from './paginate'
import { PaginateQuery } from './decorator'
import { HttpException } from '@nestjs/common'
import { CatEntity, CutenessLevel } from './__tests__/cat.entity'
@ -8,13 +8,13 @@ import { CatHomeEntity } from './__tests__/cat-home.entity'
import { CatHomePillowEntity } from './__tests__/cat-home-pillow.entity'
import { clone } from 'lodash'
import {
parseFilterToken,
FilterComparator,
FilterOperator,
FilterSuffix,
isOperator,
isSuffix,
OperatorSymbolToFunction,
parseFilterToken,
} from './filter'
import { ToyShopEntity } from './__tests__/toy-shop.entity'
import { ToyShopAddressEntity } from './__tests__/toy-shop-address.entity'
@ -1036,6 +1036,66 @@ describe('paginate', () => {
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.cat.name=$not:Milo')
})
it('should be possible to filter by relation without loading it', async () => {
const config: PaginateConfig<CatToyEntity> = {
relations: ['cat'],
sortableColumns: ['id'],
where: { cat: { toys: { name: catToys[0].name } } },
}
const query: PaginateQuery = {
path: '',
}
const result = await paginate<CatToyEntity>(query, catToyRepo, config)
expect(result.data.length).toStrictEqual(3)
})
it('should be possible to filter by relation without loading it 4th level', async () => {
const config: PaginateConfig<CatToyEntity> = {
relations: ['cat'],
sortableColumns: ['id'],
where: { cat: { toys: { shop: { address: { address: Like('%123%') } } } } },
}
const query: PaginateQuery = {
path: '',
}
const result = await paginate<CatToyEntity>(query, catToyRepo, config)
expect(result.data.length).toStrictEqual(3)
})
it('should be possible to filter by relation without loading it 4th level with load eager', async () => {
const config: PaginateConfig<CatToyEntity> = {
loadEagerRelations: true,
sortableColumns: ['id'],
where: { cat: { toys: { shop: { address: { address: Like('%123%') } } } } },
}
const query: PaginateQuery = {
path: '',
}
const result = await paginate<CatToyEntity>(query, catToyRepo, config)
expect(result.data.length).toStrictEqual(3)
})
it('should be possible to filter by relation without including any relations', async () => {
const config: PaginateConfig<CatToyEntity> = {
loadEagerRelations: false,
sortableColumns: ['id'],
where: { cat: { toys: { shop: { address: { address: Like('%123%') } } } } },
}
const query: PaginateQuery = {
path: '',
}
const result = await paginate<CatToyEntity>(query, catToyRepo, config)
expect(result.data.length).toStrictEqual(3)
})
it('should return result based on filter on one-to-many relation', async () => {
const config: PaginateConfig<CatEntity> = {
relations: ['toys'],

View File

@ -122,9 +122,49 @@ function flattenWhereAndTransform<T>(
isEmbedded,
virtualQuery
)
return queryBuilder['createWhereConditionExpression'](
const whereClause = queryBuilder['createWhereConditionExpression'](
queryBuilder['getWherePredicateCondition'](alias, value)
)
const allJoinedTables = queryBuilder.expressionMap.joinAttributes.reduce(
(acc, attr) => {
acc[attr.alias.name] = true
return acc
},
{} as Record<string, boolean>
)
const allTablesInPath = property.column.split('.').slice(0, -1)
const tablesToJoin = allTablesInPath.map((table, idx) => {
if (idx === 0) {
return table
}
return [...allTablesInPath.slice(0, idx), table].join('.')
})
tablesToJoin.forEach((table) => {
const pathSplit = table.split('.')
const fullPath =
pathSplit.length === 1
? ''
: `_${pathSplit
.slice(0, -1)
.map((p) => p + '_rel')
.join('_')}`
const tableName = pathSplit[pathSplit.length - 1]
const tableAliasWithProperty = `${queryBuilder.alias}${fullPath}.${tableName}`
const joinTableAlias = `${queryBuilder.alias}${fullPath}_${tableName}_rel`
const baseTableAlias = allJoinedTables[joinTableAlias]
if (baseTableAlias) {
return
} else {
queryBuilder.leftJoin(tableAliasWithProperty, joinTableAlias)
}
})
return whereClause
}
}
})