fix(db-postgres): sort by localized fields (#8839)
### What? Fixes https://github.com/payloadcms/payload/issues/5152 issue related to sorting by a localized field with SQLite / Postgres database adapters. ### Why? It was an incorrect behaviour. ### How? Modifies the `getTableColumnFromPath` file to have correct join conditions. Previously if you had this structure in the _locales table _locale title parent en A 1 es B 1 we sorted by everything that's here, but we need to sort only by the passed locale. Additionally fixes a typescript error in `dev.ts` that I added here https://github.com/payloadcms/payload/pull/8834 Also, removes the condition with `joins.length` in `countDistinct`. It was there as for this issue https://github.com/payloadcms/payload/issues/4889 because sorting by a localized property caused duplication. This can simnifically improve performance for `.find` with nested querying/sorting on large data sets, because `count(*)` is faster than `count(DISTINCT id)`
This commit is contained in:
@@ -3,7 +3,7 @@ import { type Payload, type Where } from 'payload'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
import type { NextRESTClient } from '../helpers/NextRESTClient.js'
|
||||
import type { LocalizedPost, WithLocalizedRelationship } from './payload-types.js'
|
||||
import type { LocalizedPost, LocalizedSort, WithLocalizedRelationship } from './payload-types.js'
|
||||
|
||||
import { idToString } from '../helpers/idToString.js'
|
||||
import { initPayloadInt } from '../helpers/initPayloadInt.js'
|
||||
@@ -369,6 +369,7 @@ describe('Localization', () => {
|
||||
|
||||
describe('Localized Sort Count', () => {
|
||||
const expectedTotalDocs = 5
|
||||
const posts: LocalizedSort[] = []
|
||||
beforeAll(async () => {
|
||||
for (let i = 1; i <= expectedTotalDocs; i++) {
|
||||
const post = await payload.create({
|
||||
@@ -380,6 +381,8 @@ describe('Localization', () => {
|
||||
locale: englishLocale,
|
||||
})
|
||||
|
||||
posts.push(post)
|
||||
|
||||
await payload.update({
|
||||
id: post.id,
|
||||
collection: localizedSortSlug,
|
||||
@@ -419,6 +422,118 @@ describe('Localization', () => {
|
||||
expect(sortByTitleQuery.totalDocs).toEqual(expectedTotalDocs)
|
||||
expect(sortByDateQuery.totalDocs).toEqual(expectedTotalDocs)
|
||||
})
|
||||
|
||||
it('should return correct order when sorted by localized fields', async () => {
|
||||
const { docs: docsAsc } = await payload.find({ collection: localizedSortSlug, sort: 'title' })
|
||||
docsAsc.forEach((doc, i) => {
|
||||
expect(posts[i].id).toBe(doc.id)
|
||||
})
|
||||
|
||||
const { docs: docsDesc } = await payload.find({
|
||||
collection: localizedSortSlug,
|
||||
sort: '-title',
|
||||
})
|
||||
docsDesc.forEach((doc, i) => {
|
||||
expect(posts.at(posts.length - i - 1).id).toBe(doc.id)
|
||||
})
|
||||
|
||||
// Test with words
|
||||
const randomWords = [
|
||||
'sunset',
|
||||
'whisper',
|
||||
'lighthouse',
|
||||
'harmony',
|
||||
'crystal',
|
||||
'thunder',
|
||||
'meadow',
|
||||
'voyage',
|
||||
'echo',
|
||||
'quicksand',
|
||||
]
|
||||
|
||||
const randomWordsSpanish = [
|
||||
'atardecer',
|
||||
'susurro',
|
||||
'faro',
|
||||
'armonía',
|
||||
'cristal',
|
||||
'trueno',
|
||||
'pradera',
|
||||
'viaje',
|
||||
'eco',
|
||||
'arenas movedizas',
|
||||
]
|
||||
|
||||
expect(randomWords).toHaveLength(randomWordsSpanish.length)
|
||||
|
||||
const randomWordsPosts: (number | string)[] = []
|
||||
|
||||
for (let i = 0; i < randomWords.length; i++) {
|
||||
const en = randomWords[i]
|
||||
const post = await payload.create({ collection: 'localized-sort', data: { title: en } })
|
||||
const es = randomWordsSpanish[i]
|
||||
await payload.update({
|
||||
collection: 'localized-sort',
|
||||
data: { title: es },
|
||||
id: post.id,
|
||||
locale: 'es',
|
||||
})
|
||||
|
||||
randomWordsPosts.push(post.id)
|
||||
}
|
||||
|
||||
const ascSortedWordsEn = randomWords.toSorted((a, b) => a.localeCompare(b))
|
||||
const descSortedWordsEn = randomWords.toSorted((a, b) => b.localeCompare(a))
|
||||
|
||||
const q = { id: { in: randomWordsPosts } }
|
||||
|
||||
const { docs: randomWordsEnAsc } = await payload.find({
|
||||
collection: localizedSortSlug,
|
||||
sort: 'title',
|
||||
where: q,
|
||||
})
|
||||
randomWordsEnAsc.forEach((doc, i) => {
|
||||
expect(ascSortedWordsEn[i]).toBe(doc.title)
|
||||
})
|
||||
|
||||
const { docs: randomWordsEnDesc } = await payload.find({
|
||||
collection: localizedSortSlug,
|
||||
sort: '-title',
|
||||
where: q,
|
||||
})
|
||||
|
||||
randomWordsEnDesc.forEach((doc, i) => {
|
||||
expect(descSortedWordsEn[i]).toBe(doc.title)
|
||||
})
|
||||
|
||||
// Test sorting for Spanish locale
|
||||
const ascSortedWordsEs = randomWordsSpanish.toSorted((a, b) => a.localeCompare(b))
|
||||
const descSortedWordsEs = randomWordsSpanish.toSorted((a, b) => b.localeCompare(a))
|
||||
|
||||
// Fetch sorted words in Spanish (ascending)
|
||||
const { docs: randomWordsEsAsc } = await payload.find({
|
||||
collection: localizedSortSlug,
|
||||
sort: 'title',
|
||||
where: q,
|
||||
locale: 'es',
|
||||
})
|
||||
|
||||
randomWordsEsAsc.forEach((doc, i) => {
|
||||
expect(ascSortedWordsEs[i]).toBe(doc.title)
|
||||
})
|
||||
|
||||
// Fetch sorted words in Spanish (descending)
|
||||
const { docs: randomWordsEsDesc } = await payload.find({
|
||||
collection: localizedSortSlug,
|
||||
sort: '-title',
|
||||
where: q,
|
||||
locale: 'es',
|
||||
})
|
||||
|
||||
randomWordsEsDesc.forEach((doc, i) => {
|
||||
expect(descSortedWordsEs[i]).toBe(doc.title)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Localized Relationship', () => {
|
||||
|
||||
Reference in New Issue
Block a user