fix: add check on primary key columns to avoid select exception (#507)
This commit is contained in:
parent
6193ea28df
commit
c2c6eaf44e
@ -194,6 +194,7 @@ const paginateConfig: PaginateConfig<CatEntity> {
|
||||
* Type: TypeORM partial selection
|
||||
* Default: None
|
||||
* https://typeorm.io/select-query-builder#partial-selection
|
||||
* Note: You must include the primary key in the selection.
|
||||
*/
|
||||
select: ['name', 'color'],
|
||||
|
||||
@ -266,7 +267,7 @@ const paginateConfig: PaginateConfig<CatEntity> {
|
||||
Eager loading should work with typeorm's eager property out the box. Like so
|
||||
|
||||
```typescript
|
||||
import { Entity, OneToMany } from 'typeorm';
|
||||
import { Entity, OneToMany } from 'typeorm'
|
||||
|
||||
@Entity()
|
||||
export class CatEntity {
|
||||
@ -295,7 +296,7 @@ class CatService {
|
||||
public findAll(query: PaginateQuery): Promise<Paginated<CatEntity>> {
|
||||
return paginate(query, this.catsRepository, {
|
||||
sortableColumns: ['id', 'name', 'color', 'age'],
|
||||
loadEagerRelations: true // set this property as true to enable the eager loading
|
||||
loadEagerRelations: true, // set this property as true to enable the eager loading
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,25 @@ export function extractVirtualProperty(
|
||||
)
|
||||
}
|
||||
|
||||
export function includesAllPrimaryKeyColumns(qb: SelectQueryBuilder<unknown>, propertyPath: string[]): boolean {
|
||||
if (!qb || !propertyPath) {
|
||||
return false
|
||||
}
|
||||
return qb.expressionMap.mainAlias?.metadata?.primaryColumns
|
||||
.map((column) => column.propertyPath)
|
||||
.every((column) => propertyPath.includes(column))
|
||||
}
|
||||
|
||||
export function hasColumnWithPropertyPath(
|
||||
qb: SelectQueryBuilder<unknown>,
|
||||
columnProperties: ColumnProperties
|
||||
): boolean {
|
||||
if (!qb || !columnProperties) {
|
||||
return false
|
||||
}
|
||||
return !!qb.expressionMap.mainAlias?.metadata?.hasColumnWithPropertyPath(columnProperties.propertyName)
|
||||
}
|
||||
|
||||
export function checkIsRelation(qb: SelectQueryBuilder<unknown>, propertyPath: string): boolean {
|
||||
if (!qb || !propertyPath) {
|
||||
return false
|
||||
|
@ -1871,6 +1871,20 @@ describe('paginate', () => {
|
||||
expect(result.links.current).toBe('?page=1&limit=20&sortBy=countCat:ASC&filter.countCat=$gt:0')
|
||||
})
|
||||
|
||||
it("should return all columns if select doesn't contain all primary columns", async () => {
|
||||
const config: PaginateConfig<CatEntity> = {
|
||||
sortableColumns: ['id', 'name'],
|
||||
select: ['name'],
|
||||
}
|
||||
const query: PaginateQuery = {
|
||||
path: '',
|
||||
}
|
||||
|
||||
const result = await paginate<CatEntity>(query, catRepo, config)
|
||||
|
||||
expect(result.data).toStrictEqual(cats)
|
||||
})
|
||||
|
||||
it('should return all items even if deleted', async () => {
|
||||
const config: PaginateConfig<CatEntity> = {
|
||||
sortableColumns: ['id'],
|
||||
|
@ -23,6 +23,8 @@ import {
|
||||
positiveNumberOrDefault,
|
||||
RelationColumn,
|
||||
SortBy,
|
||||
hasColumnWithPropertyPath,
|
||||
includesAllPrimaryKeyColumns,
|
||||
} from './helper'
|
||||
import { FilterOperator, FilterSuffix } from './operator'
|
||||
import { addFilter } from './filter'
|
||||
@ -208,15 +210,18 @@ export async function paginate<T extends ObjectLiteral>(
|
||||
}
|
||||
|
||||
// When we partial select the columns (main or relation) we must add the primary key column otherwise
|
||||
// typeorm will not be able to map the result TODO: write it in the docs
|
||||
// typeorm will not be able to map the result.
|
||||
const selectParams = config.select || query.select
|
||||
if (selectParams?.length > 0) {
|
||||
if (selectParams?.length > 0 && includesAllPrimaryKeyColumns(queryBuilder, selectParams)) {
|
||||
const cols: string[] = selectParams.reduce((cols, currentCol) => {
|
||||
if (query.select?.includes(currentCol) ?? true) {
|
||||
const columnProperties = getPropertiesByColumnName(currentCol)
|
||||
const isRelation = checkIsRelation(queryBuilder, columnProperties.propertyPath)
|
||||
// here we can avoid to manually fix and add the query of virtual columns
|
||||
cols.push(fixColumnAlias(columnProperties, queryBuilder.alias, isRelation))
|
||||
const { isVirtualProperty } = extractVirtualProperty(queryBuilder, columnProperties)
|
||||
if (hasColumnWithPropertyPath(queryBuilder, columnProperties) || isVirtualProperty) {
|
||||
// here we can avoid to manually fix and add the query of virtual columns
|
||||
cols.push(fixColumnAlias(columnProperties, queryBuilder.alias, isRelation))
|
||||
}
|
||||
}
|
||||
return cols
|
||||
}, [])
|
||||
|
Loading…
Reference in New Issue
Block a user