From 2ca526bd22acc7e72483a95132b438395cd574ee Mon Sep 17 00:00:00 2001 From: Dan Ribbens Date: Mon, 15 Aug 2022 16:54:23 -0400 Subject: [PATCH] chore: simplifies index creation --- src/mongoose/buildSchema.ts | 43 ++++++++++++++++++-------- test/fields/collections/Point/index.ts | 3 +- test/fields/int.spec.ts | 30 ++++++++++++++++-- 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/src/mongoose/buildSchema.ts b/src/mongoose/buildSchema.ts index 709fa31812..dd66529371 100644 --- a/src/mongoose/buildSchema.ts +++ b/src/mongoose/buildSchema.ts @@ -2,7 +2,7 @@ /* eslint-disable class-methods-use-this */ /* eslint-disable @typescript-eslint/no-use-before-define */ /* eslint-disable no-use-before-define */ -import { IndexOptions, Schema, SchemaOptions } from 'mongoose'; +import { IndexOptions, Schema, SchemaOptions, SchemaTypeOptions } from 'mongoose'; import { SanitizedConfig } from '../config/types'; import { ArrayField, Block, BlockField, CheckboxField, CodeField, CollapsibleField, DateField, EmailField, Field, fieldAffectsData, fieldIsPresentationalOnly, GroupField, NonPresentationalField, NumberField, PointField, RadioField, RelationshipField, RichTextField, RowField, SelectField, TabsField, TextareaField, TextField, UploadField } from '../fields/config/types'; @@ -15,12 +15,17 @@ export type BuildSchemaOptions = { type FieldSchemaGenerator = (field: Field, schema: Schema, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions) => void; -const formatBaseSchema = (field: NonPresentationalField, buildSchemaOptions: BuildSchemaOptions) => ({ - sparse: field.unique && field.localized, - unique: (!buildSchemaOptions.disableUnique && field.unique) || false, - required: false, - index: field.index || field.unique || false, -}); +const formatBaseSchema = (field: NonPresentationalField, buildSchemaOptions: BuildSchemaOptions) => { + const schema: SchemaTypeOptions = { + unique: (!buildSchemaOptions.disableUnique && field.unique) || false, + required: false, + index: field.index || field.unique || false, + }; + if (field.unique && field.localized) { + schema.sparse = true; + } + return schema; +}; const localizeSchema = (field: NonPresentationalField, schema, localization) => { if (field.localized && localization && Array.isArray(localization.locales)) { @@ -112,27 +117,39 @@ const fieldToSchemaMap: Record = { }); }, point: (field: PointField, schema: Schema, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions): void => { - const baseSchema = { + const baseSchema: SchemaTypeOptions = { type: { type: String, enum: ['Point'], }, coordinates: { type: [Number], - sparse: (buildSchemaOptions.disableUnique && field.unique) && field.localized, - unique: (buildSchemaOptions.disableUnique && field.unique) || false, required: false, default: field.defaultValue || undefined, }, }; + if (buildSchemaOptions.disableUnique && field.unique && field.localized) { + baseSchema.coordinates.sparse = true; + } schema.add({ [field.name]: localizeSchema(field, baseSchema, config.localization), }); - // if (field.index === true || field.index === undefined) { - // baseSchema.index = '2dsphere'; - // } + if (field.index === true || field.index === undefined) { + const indexOptions: IndexOptions = {}; + if (!buildSchemaOptions.disableUnique && field.unique) { + indexOptions.sparse = true; + indexOptions.unique = true; + } + if (field.localized && config.localization) { + config.localization.locales.forEach((locale) => { + schema.index({ [`${field.name}.${locale}`]: '2dsphere' }, indexOptions); + }); + } else { + schema.index({ [field.name]: '2dsphere' }, indexOptions); + } + } }, radio: (field: RadioField, schema: Schema, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions): void => { const baseSchema = { diff --git a/test/fields/collections/Point/index.ts b/test/fields/collections/Point/index.ts index 9032dc90aa..ef051e20ea 100644 --- a/test/fields/collections/Point/index.ts +++ b/test/fields/collections/Point/index.ts @@ -19,6 +19,7 @@ const PointFields: CollectionConfig = { name: 'localized', type: 'point', label: 'Localized Point', + unique: true, localized: true, }, { @@ -36,7 +37,7 @@ const PointFields: CollectionConfig = { export const pointDoc = { point: [7, -7], - localized: [5, -2], + localized: [15, -12], group: { point: [1, 9] }, }; diff --git a/test/fields/int.spec.ts b/test/fields/int.spec.ts index e99e111f8b..a36d8b8260 100644 --- a/test/fields/int.spec.ts +++ b/test/fields/int.spec.ts @@ -160,6 +160,9 @@ describe('Fields', () => { describe('point', () => { let doc; + const point = [7, -7]; + const localized = [5, -2]; + const group = { point: [1, 9] }; beforeAll(async () => { const findDoc = await payload.find({ @@ -183,9 +186,6 @@ describe('Fields', () => { }); it('should create', async () => { - const point = [7, -7]; - const localized = [5, -2]; - const group = { point: [1, 9] }; doc = await payload.create({ collection: 'point-fields', data: { @@ -199,6 +199,30 @@ describe('Fields', () => { expect(doc.localized).toEqual(localized); expect(doc.group).toMatchObject(group); }); + + it('should not create duplicate point when unique', async () => { + await expect(() => payload.create({ + collection: 'point-fields', + data: { + point, + localized, + group, + }, + })) + .rejects + .toThrow(Error); + + await expect(async () => payload.create({ + collection: 'number-fields', + data: { + min: 5, + }, + })).rejects.toThrow('The following field is invalid: min'); + + expect(doc.point).toEqual(point); + expect(doc.localized).toEqual(localized); + expect(doc.group).toMatchObject(group); + }); }); describe('array', () => { let doc;