fix: #1204
This commit is contained in:
@@ -70,7 +70,7 @@ async function find<T extends TypeWithID = any>(incomingArgs: Arguments): Promis
|
|||||||
// Access
|
// Access
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|
||||||
const queryToBuild: { where?: Where} = {
|
const queryToBuild: { where?: Where } = {
|
||||||
where: {
|
where: {
|
||||||
and: [],
|
and: [],
|
||||||
},
|
},
|
||||||
@@ -128,7 +128,13 @@ async function find<T extends TypeWithID = any>(incomingArgs: Arguments): Promis
|
|||||||
// Find
|
// Find
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|
||||||
const [sortProperty, sortOrder] = buildSortParam(args.sort, collectionConfig.timestamps);
|
const [sortProperty, sortOrder] = buildSortParam({
|
||||||
|
sort: args.sort,
|
||||||
|
config: payload.config,
|
||||||
|
fields: collectionConfig.fields,
|
||||||
|
timestamps: collectionConfig.timestamps,
|
||||||
|
locale,
|
||||||
|
});
|
||||||
|
|
||||||
const optionsToExecute = {
|
const optionsToExecute = {
|
||||||
page: page || 1,
|
page: page || 1,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { buildSortParam } from '../../mongoose/buildSortParam';
|
|||||||
import { PaginatedDocs } from '../../mongoose/types';
|
import { PaginatedDocs } from '../../mongoose/types';
|
||||||
import { TypeWithVersion } from '../../versions/types';
|
import { TypeWithVersion } from '../../versions/types';
|
||||||
import { afterRead } from '../../fields/hooks/afterRead';
|
import { afterRead } from '../../fields/hooks/afterRead';
|
||||||
|
import { buildVersionCollectionFields } from '../../versions/buildCollectionFields';
|
||||||
|
|
||||||
export type Arguments = {
|
export type Arguments = {
|
||||||
collection: Collection
|
collection: Collection
|
||||||
@@ -46,7 +47,7 @@ async function findVersions<T extends TypeWithVersion<T> = any>(args: Arguments)
|
|||||||
// Access
|
// Access
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|
||||||
const queryToBuild: { where?: Where} = {};
|
const queryToBuild: { where?: Where } = {};
|
||||||
let useEstimatedCount = false;
|
let useEstimatedCount = false;
|
||||||
|
|
||||||
if (where) {
|
if (where) {
|
||||||
@@ -89,7 +90,13 @@ async function findVersions<T extends TypeWithVersion<T> = any>(args: Arguments)
|
|||||||
// Find
|
// Find
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|
||||||
const [sortProperty, sortOrder] = buildSortParam(args.sort || '-updatedAt', true);
|
const [sortProperty, sortOrder] = buildSortParam({
|
||||||
|
sort: args.sort || '-updatedAt',
|
||||||
|
fields: buildVersionCollectionFields(collectionConfig),
|
||||||
|
timestamps: true,
|
||||||
|
config: payload.config,
|
||||||
|
locale,
|
||||||
|
});
|
||||||
|
|
||||||
const optionsToExecute = {
|
const optionsToExecute = {
|
||||||
page: page || 1,
|
page: page || 1,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { buildSortParam } from '../../mongoose/buildSortParam';
|
|||||||
import { TypeWithVersion } from '../../versions/types';
|
import { TypeWithVersion } from '../../versions/types';
|
||||||
import { SanitizedGlobalConfig } from '../config/types';
|
import { SanitizedGlobalConfig } from '../config/types';
|
||||||
import { afterRead } from '../../fields/hooks/afterRead';
|
import { afterRead } from '../../fields/hooks/afterRead';
|
||||||
|
import { buildVersionGlobalFields } from '../../versions/buildGlobalFields';
|
||||||
|
|
||||||
export type Arguments = {
|
export type Arguments = {
|
||||||
globalConfig: SanitizedGlobalConfig
|
globalConfig: SanitizedGlobalConfig
|
||||||
@@ -44,7 +45,7 @@ async function findVersions<T extends TypeWithVersion<T> = any>(args: Arguments)
|
|||||||
// Access
|
// Access
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|
||||||
const queryToBuild: { where?: Where} = {};
|
const queryToBuild: { where?: Where } = {};
|
||||||
let useEstimatedCount = false;
|
let useEstimatedCount = false;
|
||||||
|
|
||||||
if (where) {
|
if (where) {
|
||||||
@@ -87,7 +88,13 @@ async function findVersions<T extends TypeWithVersion<T> = any>(args: Arguments)
|
|||||||
// Find
|
// Find
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|
||||||
const [sortProperty, sortOrder] = buildSortParam(args.sort || '-updatedAt', true);
|
const [sortProperty, sortOrder] = buildSortParam({
|
||||||
|
sort: args.sort || '-updatedAt',
|
||||||
|
fields: buildVersionGlobalFields(globalConfig),
|
||||||
|
timestamps: true,
|
||||||
|
config: payload.config,
|
||||||
|
locale,
|
||||||
|
});
|
||||||
|
|
||||||
const optionsToExecute = {
|
const optionsToExecute = {
|
||||||
page: page || 1,
|
page: page || 1,
|
||||||
|
|||||||
@@ -1,4 +1,16 @@
|
|||||||
export const buildSortParam = (sort: string, timestamps: boolean) => {
|
import { Config } from '../config/types';
|
||||||
|
import { getLocalizedSortProperty } from './getLocalizedSortProperty';
|
||||||
|
import { Field } from '../fields/config/types';
|
||||||
|
|
||||||
|
type Args = {
|
||||||
|
sort: string
|
||||||
|
config: Config
|
||||||
|
fields: Field[]
|
||||||
|
timestamps: boolean
|
||||||
|
locale: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const buildSortParam = ({ sort, config, fields, timestamps, locale }: Args): [string, string] => {
|
||||||
let sortProperty: string;
|
let sortProperty: string;
|
||||||
let sortOrder = 'desc';
|
let sortOrder = 'desc';
|
||||||
|
|
||||||
@@ -15,7 +27,16 @@ export const buildSortParam = (sort: string, timestamps: boolean) => {
|
|||||||
sortOrder = 'asc';
|
sortOrder = 'asc';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sortProperty === 'id') sortProperty = '_id';
|
if (sortProperty === 'id') {
|
||||||
|
sortProperty = '_id';
|
||||||
|
} else {
|
||||||
|
sortProperty = getLocalizedSortProperty({
|
||||||
|
segments: sortProperty.split('.'),
|
||||||
|
config,
|
||||||
|
fields,
|
||||||
|
locale,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return [sortProperty, sortOrder];
|
return [sortProperty, sortOrder];
|
||||||
};
|
};
|
||||||
|
|||||||
182
src/mongoose/getLocalizedSortProperty.spec.ts
Normal file
182
src/mongoose/getLocalizedSortProperty.spec.ts
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
import { Config } from '../config/types';
|
||||||
|
import { getLocalizedSortProperty } from './getLocalizedSortProperty';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
localization: {
|
||||||
|
locales: ['en', 'es'],
|
||||||
|
},
|
||||||
|
} as Config;
|
||||||
|
|
||||||
|
describe('get localized sort property', () => {
|
||||||
|
it('passes through a non-localized sort property', () => {
|
||||||
|
const result = getLocalizedSortProperty({
|
||||||
|
segments: ['title'],
|
||||||
|
config,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
locale: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toStrictEqual('title');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('properly localizes an un-localized sort property', () => {
|
||||||
|
const result = getLocalizedSortProperty({
|
||||||
|
segments: ['title'],
|
||||||
|
config,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
type: 'text',
|
||||||
|
localized: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
locale: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toStrictEqual('title.en');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps specifically asked-for localized sort properties', () => {
|
||||||
|
const result = getLocalizedSortProperty({
|
||||||
|
segments: ['title', 'es'],
|
||||||
|
config,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
type: 'text',
|
||||||
|
localized: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
locale: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toStrictEqual('title.es');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('properly localizes nested sort properties', () => {
|
||||||
|
const result = getLocalizedSortProperty({
|
||||||
|
segments: ['group', 'title'],
|
||||||
|
config,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'group',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
type: 'text',
|
||||||
|
localized: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
locale: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toStrictEqual('group.title.en');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps requested locale with nested sort properties', () => {
|
||||||
|
const result = getLocalizedSortProperty({
|
||||||
|
segments: ['group', 'title', 'es'],
|
||||||
|
config,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'group',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
type: 'text',
|
||||||
|
localized: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
locale: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toStrictEqual('group.title.es');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('properly localizes field within row', () => {
|
||||||
|
const result = getLocalizedSortProperty({
|
||||||
|
segments: ['title'],
|
||||||
|
config,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'row',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
type: 'text',
|
||||||
|
localized: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
locale: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toStrictEqual('title.en');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('properly localizes field within named tab', () => {
|
||||||
|
const result = getLocalizedSortProperty({
|
||||||
|
segments: ['tab', 'title'],
|
||||||
|
config,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'tabs',
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
name: 'tab',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
type: 'text',
|
||||||
|
localized: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
locale: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toStrictEqual('tab.title.en');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('properly localizes field within unnamed tab', () => {
|
||||||
|
const result = getLocalizedSortProperty({
|
||||||
|
segments: ['title'],
|
||||||
|
config,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'tabs',
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
label: 'Tab',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
type: 'text',
|
||||||
|
localized: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
locale: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toStrictEqual('title.en');
|
||||||
|
});
|
||||||
|
});
|
||||||
89
src/mongoose/getLocalizedSortProperty.ts
Normal file
89
src/mongoose/getLocalizedSortProperty.ts
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import { Config } from '../config/types';
|
||||||
|
import { Field, fieldAffectsData, fieldIsPresentationalOnly } from '../fields/config/types';
|
||||||
|
import flattenTopLevelFields from '../utilities/flattenTopLevelFields';
|
||||||
|
|
||||||
|
type Args = {
|
||||||
|
segments: string[]
|
||||||
|
config: Config
|
||||||
|
fields: Field[]
|
||||||
|
locale: string
|
||||||
|
result?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getLocalizedSortProperty = ({
|
||||||
|
segments: incomingSegments,
|
||||||
|
config,
|
||||||
|
fields: incomingFields,
|
||||||
|
locale,
|
||||||
|
result: incomingResult,
|
||||||
|
}: Args): string => {
|
||||||
|
// If localization is not enabled, accept exactly
|
||||||
|
// what is sent in
|
||||||
|
if (!config.localization) {
|
||||||
|
return incomingSegments.join('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flatten incoming fields (row, etc)
|
||||||
|
const fields = flattenTopLevelFields(incomingFields);
|
||||||
|
|
||||||
|
const segments = [...incomingSegments];
|
||||||
|
|
||||||
|
// Retrieve first segment, and remove from segments
|
||||||
|
const firstSegment = segments.shift();
|
||||||
|
|
||||||
|
// Attempt to find a matched field
|
||||||
|
const matchedField = fields.find((field) => fieldAffectsData(field) && field.name === firstSegment);
|
||||||
|
|
||||||
|
if (matchedField && !fieldIsPresentationalOnly(matchedField)) {
|
||||||
|
let nextFields: Field[];
|
||||||
|
const remainingSegments = [...segments];
|
||||||
|
let localizedSegment = matchedField.name;
|
||||||
|
|
||||||
|
if (matchedField.localized) {
|
||||||
|
// Check to see if next segment is a locale
|
||||||
|
if (segments.length > 0) {
|
||||||
|
const nextSegmentIsLocale = config.localization.locales.includes(remainingSegments[0]);
|
||||||
|
|
||||||
|
// If next segment is locale, remove it from remaining segments
|
||||||
|
// and use it to localize the current segment
|
||||||
|
if (nextSegmentIsLocale) {
|
||||||
|
const nextSegment = remainingSegments.shift();
|
||||||
|
localizedSegment = `${matchedField.name}.${nextSegment}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If no more segments, but field is localized, use default locale
|
||||||
|
localizedSegment = `${matchedField.name}.${locale}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are subfields, pass them through
|
||||||
|
if (matchedField.type === 'tab' || matchedField.type === 'group' || matchedField.type === 'array') {
|
||||||
|
nextFields = matchedField.fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchedField.type === 'blocks') {
|
||||||
|
nextFields = matchedField.blocks.reduce((flattenedBlockFields, block) => {
|
||||||
|
return [
|
||||||
|
...flattenedBlockFields,
|
||||||
|
...block.fields.filter((blockField) => (fieldAffectsData(blockField) && (blockField.name !== 'blockType' && blockField.name !== 'blockName')) || !fieldAffectsData(blockField)),
|
||||||
|
];
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = incomingResult ? `${incomingResult}.${localizedSegment}` : localizedSegment;
|
||||||
|
|
||||||
|
if (nextFields) {
|
||||||
|
return getLocalizedSortProperty({
|
||||||
|
segments: remainingSegments,
|
||||||
|
config,
|
||||||
|
fields: nextFields,
|
||||||
|
locale,
|
||||||
|
result,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return incomingSegments.join('.');
|
||||||
|
};
|
||||||
@@ -30,7 +30,7 @@ const flattenFields = (fields: Field[], keepPresentationalFields?: boolean): (Fi
|
|||||||
...field.tabs.reduce((tabFields, tab) => {
|
...field.tabs.reduce((tabFields, tab) => {
|
||||||
return [
|
return [
|
||||||
...tabFields,
|
...tabFields,
|
||||||
...(tabHasName(tab) ? [tab] : flattenFields(tab.fields, keepPresentationalFields)),
|
...(tabHasName(tab) ? [{ ...tab, type: 'tab' }] : flattenFields(tab.fields, keepPresentationalFields)),
|
||||||
];
|
];
|
||||||
}, []),
|
}, []),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ export default buildConfig({
|
|||||||
name: 'title',
|
name: 'title',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
localized: true,
|
localized: true,
|
||||||
|
index: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'description',
|
name: 'description',
|
||||||
|
|||||||
Reference in New Issue
Block a user