fix: properly handle nullable minDistance and maxDistance in near query (#10622)

Fixes https://github.com/payloadcms/payload/issues/10521
This commit is contained in:
Sasha
2025-01-21 02:18:13 +02:00
committed by GitHub
parent e4fa1718aa
commit 46c1b375b8
3 changed files with 59 additions and 6 deletions

View File

@@ -349,10 +349,11 @@ export const sanitizeQueryValue = ({
$geometry: { type: 'Point', coordinates: [parseFloat(lng), parseFloat(lat)] },
}
if (maxDistance) {
if (maxDistance && !Number.isNaN(Number(maxDistance))) {
formattedValue.$maxDistance = parseFloat(maxDistance)
}
if (minDistance) {
if (minDistance && !Number.isNaN(Number(minDistance))) {
formattedValue.$minDistance = parseFloat(minDistance)
}
}

View File

@@ -319,12 +319,22 @@ export function parseParams({
case 'near': {
const [lng, lat, maxDistance, minDistance] = queryValue as number[]
const geoConstraints: SQL[] = []
let constraint = sql`ST_DWithin(ST_Transform(${table[columnName]}, 3857), ST_Transform(ST_SetSRID(ST_MakePoint(${lng}, ${lat}), 4326), 3857), ${maxDistance})`
if (typeof minDistance === 'number' && !Number.isNaN(minDistance)) {
constraint = sql`${constraint} AND ST_Distance(ST_Transform(${table[columnName]}, 3857), ST_Transform(ST_SetSRID(ST_MakePoint(${lng}, ${lat}), 4326), 3857)) >= ${minDistance}`
if (typeof maxDistance === 'number' && !Number.isNaN(maxDistance)) {
geoConstraints.push(
sql`ST_DWithin(ST_Transform(${table[columnName]}, 3857), ST_Transform(ST_SetSRID(ST_MakePoint(${lng}, ${lat}), 4326), 3857), ${maxDistance})`,
)
}
if (typeof minDistance === 'number' && !Number.isNaN(minDistance)) {
geoConstraints.push(
sql`ST_Distance(ST_Transform(${table[columnName]}, 3857), ST_Transform(ST_SetSRID(ST_MakePoint(${lng}, ${lat}), 4326), 3857)) >= ${minDistance}`,
)
}
if (geoConstraints.length) {
constraints.push(and(...geoConstraints))
}
constraints.push(constraint)
break
}

View File

@@ -1128,6 +1128,48 @@ describe('collections-rest', () => {
expect(resultCount.totalDocs).toBe(1)
})
it('should omit maxDistance and return a document from minDistance', async () => {
if (payload.db.name === 'sqlite') {
return
}
const near = `${lat + 0.01}, ${lng + 0.01}, null, 1500`
const response = await restClient.GET(`/${pointSlug}`, {
query: {
where: {
point: {
near,
},
},
},
})
const result = await response.json()
expect(response.status).toEqual(200)
expect(result.docs).toHaveLength(1)
})
it('should omit maxDistance and not return a document because exceeds minDistance', async () => {
if (payload.db.name === 'sqlite') {
return
}
const near = `${lat + 0.01}, ${lng + 0.01}, null, 1700`
const response = await restClient.GET(`/${pointSlug}`, {
query: {
where: {
point: {
near,
},
},
},
})
const result = await response.json()
expect(response.status).toEqual(200)
expect(result.docs).toHaveLength(0)
})
it('should not return a point far away', async () => {
if (payload.db.name === 'sqlite') {
return