diff --git a/spec/schemas.spec.js b/spec/schemas.spec.js index 9557dd7924..a4d6d24346 100644 --- a/spec/schemas.spec.js +++ b/spec/schemas.spec.js @@ -3051,6 +3051,42 @@ describe('schemas', () => { }); }); + it('allows add unique index when you create a class', async () => { + await reconfigureServer({ silent: false }); + const response = await request({ + url: 'http://localhost:8378/1/schemas', + method: 'POST', + headers: masterKeyHeaders, + json: true, + body: { + className: 'NewClass', + fields: { + aString: { type: 'String' }, + }, + indexes: { + name1: { aString: 1, _options: { unique: true } }, + }, + }, + }); + expect(response.data).toEqual({ + className: 'NewClass', + fields: { + ACL: { type: 'ACL' }, + createdAt: { type: 'Date' }, + updatedAt: { type: 'Date' }, + objectId: { type: 'String' }, + aString: { type: 'String' }, + }, + classLevelPermissions: defaultClassLevelPermissions, + indexes: { + name1: { aString: 1, _options: { unique: true } }, + }, + }); + const indexes = await config.database.adapter.getIndexes('NewClass'); + expect(indexes.length).toBe(2); + expect(indexes.filter(row => row.unique).length).toEqual(1); + }); + it('empty index returns nothing', done => { request({ url: 'http://localhost:8378/1/schemas', @@ -3148,6 +3184,70 @@ describe('schemas', () => { }); }); + it('lets you add unique indexes', async () => { + await request({ + url: 'http://localhost:8378/1/schemas/NewClass', + method: 'POST', + headers: masterKeyHeaders, + json: true, + body: {}, + }); + let response = await request({ + url: 'http://localhost:8378/1/schemas/NewClass', + method: 'PUT', + headers: masterKeyHeaders, + json: true, + body: { + fields: { + aString: { type: 'String' }, + }, + indexes: { + name1: { aString: 1, _options: { unique: true } }, + }, + }, + }); + expect( + dd(response.data, { + className: 'NewClass', + fields: { + ACL: { type: 'ACL' }, + createdAt: { type: 'Date' }, + updatedAt: { type: 'Date' }, + objectId: { type: 'String' }, + aString: { type: 'String' }, + }, + classLevelPermissions: defaultClassLevelPermissions, + indexes: { + _id_: { _id: 1 }, + name1: { aString: 1, _options: { unique: true } }, + }, + }) + ).toEqual(undefined); + response = await request({ + url: 'http://localhost:8378/1/schemas/NewClass', + headers: masterKeyHeaders, + json: true, + }); + expect(response.data).toEqual({ + className: 'NewClass', + fields: { + ACL: { type: 'ACL' }, + createdAt: { type: 'Date' }, + updatedAt: { type: 'Date' }, + objectId: { type: 'String' }, + aString: { type: 'String' }, + }, + classLevelPermissions: defaultClassLevelPermissions, + indexes: { + _id_: { _id: 1 }, + name1: { aString: 1, _options: { unique: true } }, + }, + }); + const indexes = await config.database.adapter.getIndexes('NewClass'); + expect(indexes.length).toEqual(2); + expect(indexes.filter(row => row.unique).length).toEqual(1); + }); + it_only_db('mongo')('lets you add index with with pointer like structure', done => { request({ url: 'http://localhost:8378/1/schemas/NewClass', diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index 53d1bc4959..44a5eb54e1 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -2,6 +2,7 @@ import MongoCollection from './MongoCollection'; import MongoSchemaCollection from './MongoSchemaCollection'; import { StorageAdapter } from '../StorageAdapter'; +import deepcopy from 'deepcopy'; import type { SchemaType, QueryType, StorageClass, QueryOptions } from '../StorageAdapter'; import { parse as parseUrl, format as formatUrl } from '../../../vendor/mongodbUrl'; import { @@ -274,7 +275,12 @@ export class MongoStorageAdapter implements StorageAdapter { const deletePromises = []; const insertedIndexes = []; Object.keys(submittedIndexes).forEach(name => { - const field = submittedIndexes[name]; + const field = deepcopy(submittedIndexes[name]); + let indexOptions = {}; + if (field._options) { + indexOptions = field._options; + delete field._options; + } if (existingIndexes[name] && field.__op !== 'Delete') { throw new Parse.Error(Parse.Error.INVALID_QUERY, `Index ${name} exists, cannot update.`); } @@ -302,11 +308,16 @@ export class MongoStorageAdapter implements StorageAdapter { ); } }); - existingIndexes[name] = field; insertedIndexes.push({ key: field, name, + ...indexOptions, }); + const fieldCopy = deepcopy(field); + if (Object.keys(indexOptions).length) { + fieldCopy._options = indexOptions; + } + existingIndexes[name] = fieldCopy; } }); let insertPromise = Promise.resolve();