Skip to content

Commit

Permalink
fix: avoid number casting on number values that contain non-digit cha…
Browse files Browse the repository at this point in the history
…racters (#1024)
  • Loading branch information
aberonni authored Nov 8, 2024
1 parent df69631 commit db51a6a
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 6 deletions.
29 changes: 24 additions & 5 deletions src/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,28 @@ export function parseFilterToken(raw?: string): FilterToken | null {
return token
}

export function parseFilter(
function fixColumnFilterValue<T>(column: string, qb: SelectQueryBuilder<T>, isJsonb = false) {
const columnProperties = getPropertiesByColumnName(column)
const virtualProperty = extractVirtualProperty(qb, columnProperties)
const columnType = virtualProperty.type

return (value: string) => {
if ((columnType === Date || isJsonb) && isISODate(value)) {
return new Date(value)
}

if ((columnType === Number || isJsonb) && !Number.isNaN(value)) {
return Number(value)
}

return value
}
}

export function parseFilter<T>(
query: PaginateQuery,
filterableColumns?: { [column: string]: (FilterOperator | FilterSuffix)[] | true },
qb?: SelectQueryBuilder<unknown>
qb?: SelectQueryBuilder<T>
): ColumnsFilters {
const filter: ColumnsFilters = {}
if (!filterableColumns || !query.filter) {
Expand Down Expand Up @@ -284,8 +302,7 @@ export function parseFilter(
findOperator: undefined,
}

const fixValue = (value: string) =>
isISODate(value) ? new Date(value) : Number.isNaN(Number(value)) ? value : Number(value)
const fixValue = fixColumnFilterValue(column, qb)

const columnProperties = getPropertiesByColumnName(column)
const isJsonb = checkIsJsonb(qb, columnProperties.column)
Expand Down Expand Up @@ -315,10 +332,12 @@ export function parseFilter(
const dbColumnName = parts[parts.length - 2]
const jsonColumnName = parts[parts.length - 1]

const jsonFixValue = fixColumnFilterValue(column, qb, true)

const jsonParams = {
comparator: params.comparator,
findOperator: JsonContains({
[jsonColumnName]: fixValue(token.value),
[jsonColumnName]: jsonFixValue(token.value),
//! Below seems to not be possible from my understanding, https://github.com/typeorm/typeorm/pull/9665
//! This limits the functionaltiy to $eq only for json columns, which is a bit of a shame.
//! If this is fixed or changed, we can use the commented line below instead.
Expand Down
2 changes: 1 addition & 1 deletion src/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export function getPropertiesByColumnName(column: string): ColumnProperties {
export function extractVirtualProperty(
qb: SelectQueryBuilder<unknown>,
columnProperties: ColumnProperties
): { isVirtualProperty: boolean; query?: ColumnMetadata['query'] } {
): Partial<ColumnMetadata> {
const metadata = columnProperties.propertyPath
? qb?.expressionMap?.mainAlias?.metadata?.findColumnWithPropertyPath(columnProperties.propertyPath)
?.referencedColumn?.entityMetadata // on relation
Expand Down
52 changes: 52 additions & 0 deletions src/paginate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2911,6 +2911,31 @@ describe('paginate', () => {
)
})

it('with $eq operator', async () => {
const config: PaginateConfig<CatEntity> = {
sortableColumns: ['id'],
filterableColumns: {
lastVetVisit: [FilterOperator.EQ],
},
}
const query: PaginateQuery = {
path: '',
filter: {
lastVetVisit: '$eq:2022-12-21T10:00:00.000Z',
},
}

const result = await paginate<CatEntity>(query, catRepo, config)

expect(result.meta.filter).toStrictEqual({
lastVetVisit: '$eq:2022-12-21T10:00:00.000Z',
})
expect(result.data).toStrictEqual([cats[2]])
expect(result.links.current).toBe(
'?page=1&limit=20&sortBy=id:ASC&filter.lastVetVisit=$eq:2022-12-21T10:00:00.000Z'
)
})

it('with $gte operator', async () => {
const config: PaginateConfig<CatEntity> = {
sortableColumns: ['id'],
Expand Down Expand Up @@ -3009,6 +3034,33 @@ describe('paginate', () => {
})
})

describe('should correctly handle number column filter', () => {
it('with $eq operator and valid number', async () => {
const config: PaginateConfig<CatEntity> = {
sortableColumns: ['id'],
filterableColumns: {
lastVetVisit: [FilterOperator.LT],
},
}
const query: PaginateQuery = {
path: '',
filter: {
lastVetVisit: '$lt:2022-12-20T10:00:00.000Z',
},
}

const result = await paginate<CatEntity>(query, catRepo, config)

expect(result.meta.filter).toStrictEqual({
lastVetVisit: '$lt:2022-12-20T10:00:00.000Z',
})
expect(result.data).toStrictEqual([cats[0]])
expect(result.links.current).toBe(
'?page=1&limit=20&sortBy=id:ASC&filter.lastVetVisit=$lt:2022-12-20T10:00:00.000Z'
)
})
})

if (process.env.DB === 'postgres') {
describe('should return results for an array column', () => {
it.each`
Expand Down

0 comments on commit db51a6a

Please sign in to comment.