diff --git a/README.md b/README.md index d3f9be7..acadf4e 100644 --- a/README.md +++ b/README.md @@ -194,6 +194,7 @@ const paginateConfig: PaginateConfig { * 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 { 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> { 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 }) } } diff --git a/src/helper.ts b/src/helper.ts index 8b507a9..6695c0a 100644 --- a/src/helper.ts +++ b/src/helper.ts @@ -61,6 +61,25 @@ export function extractVirtualProperty( ) } +export function includesAllPrimaryKeyColumns(qb: SelectQueryBuilder, 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, + columnProperties: ColumnProperties +): boolean { + if (!qb || !columnProperties) { + return false + } + return !!qb.expressionMap.mainAlias?.metadata?.hasColumnWithPropertyPath(columnProperties.propertyName) +} + export function checkIsRelation(qb: SelectQueryBuilder, propertyPath: string): boolean { if (!qb || !propertyPath) { return false diff --git a/src/paginate.spec.ts b/src/paginate.spec.ts index c5c7a38..89a2447 100644 --- a/src/paginate.spec.ts +++ b/src/paginate.spec.ts @@ -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 = { + sortableColumns: ['id', 'name'], + select: ['name'], + } + const query: PaginateQuery = { + path: '', + } + + const result = await paginate(query, catRepo, config) + + expect(result.data).toStrictEqual(cats) + }) + it('should return all items even if deleted', async () => { const config: PaginateConfig = { sortableColumns: ['id'], diff --git a/src/paginate.ts b/src/paginate.ts index 52efb1b..59e4c71 100644 --- a/src/paginate.ts +++ b/src/paginate.ts @@ -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( } // 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 }, [])