From 99558185030aee171f5981a20577309cea02e28c Mon Sep 17 00:00:00 2001 From: Sasha <64744993+r1tsuu@users.noreply.github.com> Date: Tue, 22 Apr 2025 21:26:13 +0300 Subject: [PATCH] fix(db-postgres): sort by distance when the `near` operator is used (#12185) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/payloadcms/payload/issues/12090, in MongoDB the documents are sorted by distance automatically whenever the `near` operation is used, which we have in the docs: > When querying using the near operator, the returned documents will be sorted by nearest first. This fixes this incosistensty between Postgres and MongoDB. ⚠️ This change potentially can cause to produce different results, if you used the `near` operator without `sort: 'pointFieldName'`. --- .../src/queries/buildAndOrConditions.ts | 4 +++ packages/drizzle/src/queries/buildQuery.ts | 27 ++++++++++--------- packages/drizzle/src/queries/parseParams.ts | 8 +++++- test/collections-rest/int.spec.ts | 1 - 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/packages/drizzle/src/queries/buildAndOrConditions.ts b/packages/drizzle/src/queries/buildAndOrConditions.ts index 759eb843d5..63c8fb4b67 100644 --- a/packages/drizzle/src/queries/buildAndOrConditions.ts +++ b/packages/drizzle/src/queries/buildAndOrConditions.ts @@ -3,12 +3,14 @@ import type { FlattenedField, Where } from 'payload' import type { DrizzleAdapter, GenericColumn } from '../types.js' import type { BuildQueryJoinAliases } from './buildQuery.js' +import type { QueryContext } from './parseParams.js' import { parseParams } from './parseParams.js' export function buildAndOrConditions({ adapter, aliasTable, + context, fields, joins, locale, @@ -21,6 +23,7 @@ export function buildAndOrConditions({ adapter: DrizzleAdapter aliasTable?: Table collectionSlug?: string + context: QueryContext fields: FlattenedField[] globalSlug?: string joins: BuildQueryJoinAliases @@ -41,6 +44,7 @@ export function buildAndOrConditions({ const result = parseParams({ adapter, aliasTable, + context, fields, joins, locale, diff --git a/packages/drizzle/src/queries/buildQuery.ts b/packages/drizzle/src/queries/buildQuery.ts index a072a07e8d..9b5326b9cc 100644 --- a/packages/drizzle/src/queries/buildQuery.ts +++ b/packages/drizzle/src/queries/buildQuery.ts @@ -3,6 +3,7 @@ import type { PgTableWithColumns } from 'drizzle-orm/pg-core' import type { FlattenedField, Sort, Where } from 'payload' import type { DrizzleAdapter, GenericColumn, GenericTable } from '../types.js' +import type { QueryContext } from './parseParams.js' import { buildOrderBy } from './buildOrderBy.js' import { parseParams } from './parseParams.js' @@ -52,24 +53,14 @@ const buildQuery = function buildQuery({ id: adapter.tables[tableName].id, } - const orderBy = buildOrderBy({ - adapter, - aliasTable, - fields, - joins, - locale, - parentIsLocalized, - selectFields, - sort, - tableName, - }) - let where: SQL + const context: QueryContext = { sort } if (incomingWhere && Object.keys(incomingWhere).length > 0) { where = parseParams({ adapter, aliasTable, + context, fields, joins, locale, @@ -81,6 +72,18 @@ const buildQuery = function buildQuery({ }) } + const orderBy = buildOrderBy({ + adapter, + aliasTable, + fields, + joins, + locale, + parentIsLocalized, + selectFields, + sort: context.sort, + tableName, + }) + return { joins, orderBy, diff --git a/packages/drizzle/src/queries/parseParams.ts b/packages/drizzle/src/queries/parseParams.ts index d03876f3ae..90bba4136e 100644 --- a/packages/drizzle/src/queries/parseParams.ts +++ b/packages/drizzle/src/queries/parseParams.ts @@ -1,5 +1,5 @@ import type { SQL, Table } from 'drizzle-orm' -import type { FlattenedField, Operator, Where } from 'payload' +import type { FlattenedField, Operator, Sort, Where } from 'payload' import { and, isNotNull, isNull, ne, notInArray, or, sql } from 'drizzle-orm' import { PgUUID } from 'drizzle-orm/pg-core' @@ -14,9 +14,12 @@ import { buildAndOrConditions } from './buildAndOrConditions.js' import { getTableColumnFromPath } from './getTableColumnFromPath.js' import { sanitizeQueryValue } from './sanitizeQueryValue.js' +export type QueryContext = { sort: Sort } + type Args = { adapter: DrizzleAdapter aliasTable?: Table + context: QueryContext fields: FlattenedField[] joins: BuildQueryJoinAliases locale?: string @@ -30,6 +33,7 @@ type Args = { export function parseParams({ adapter, aliasTable, + context, fields, joins, locale, @@ -57,6 +61,7 @@ export function parseParams({ const builtConditions = buildAndOrConditions({ adapter, aliasTable, + context, fields, joins, locale, @@ -342,6 +347,7 @@ export function parseParams({ ) } if (geoConstraints.length) { + context.sort = relationOrPath constraints.push(and(...geoConstraints)) } break diff --git a/test/collections-rest/int.spec.ts b/test/collections-rest/int.spec.ts index 58cff5a117..3bc84072fb 100644 --- a/test/collections-rest/int.spec.ts +++ b/test/collections-rest/int.spec.ts @@ -1218,7 +1218,6 @@ describe('collections-rest', () => { .GET(`/${pointSlug}`, { query: { limit: 5, - sort: 'point', where: { point: { // querying large enough range to include all docs