diff --git a/spec/DefinedSchemas.spec.js b/spec/DefinedSchemas.spec.js index e3d6fd51fe..b2cae864c1 100644 --- a/spec/DefinedSchemas.spec.js +++ b/spec/DefinedSchemas.spec.js @@ -371,7 +371,7 @@ describe('DefinedSchemas', () => { expect(schema.indexes).toEqual(indexes); }); - it('should delete removed indexes', async () => { + it('should delete unknown indexes when keepUnknownIndexes is not set', async () => { const server = await reconfigureServer(); let indexes = { complex: { createdAt: 1, updatedAt: 1 } }; @@ -393,6 +393,53 @@ describe('DefinedSchemas', () => { cleanUpIndexes(schema); expect(schema.indexes).toBeUndefined(); }); + + it('should delete unknown indexes when keepUnknownIndexes is set to false', async () => { + const server = await reconfigureServer(); + + let indexes = { complex: { createdAt: 1, updatedAt: 1 } }; + + let schemas = { definitions: [{ className: 'Test', indexes }], keepUnknownIndexes: false }; + await new DefinedSchemas(schemas, server.config).execute(); + + indexes = {}; + schemas = { definitions: [{ className: 'Test', indexes }], keepUnknownIndexes: false }; + // Change indexes + await new DefinedSchemas(schemas, server.config).execute(); + let schema = await new Parse.Schema('Test').get(); + cleanUpIndexes(schema); + expect(schema.indexes).toBeUndefined(); + + // Update + await new DefinedSchemas(schemas, server.config).execute(); + schema = await new Parse.Schema('Test').get(); + cleanUpIndexes(schema); + expect(schema.indexes).toBeUndefined(); + }); + + it('should not delete unknown indexes when keepUnknownIndexes is set to true', async () => { + const server = await reconfigureServer(); + + const indexes = { complex: { createdAt: 1, updatedAt: 1 } }; + + let schemas = { definitions: [{ className: 'Test', indexes }], keepUnknownIndexes: true }; + await new DefinedSchemas(schemas, server.config).execute(); + + schemas = { definitions: [{ className: 'Test', indexes: {} }], keepUnknownIndexes: true }; + + // Change indexes + await new DefinedSchemas(schemas, server.config).execute(); + let schema = await new Parse.Schema('Test').get(); + cleanUpIndexes(schema); + expect(schema.indexes).toEqual({ complex: { createdAt: 1, updatedAt: 1 } }); + + // Update + await new DefinedSchemas(schemas, server.config).execute(); + schema = await new Parse.Schema('Test').get(); + cleanUpIndexes(schema); + expect(schema.indexes).toEqual(indexes); + }); + xit('should keep protected indexes', async () => { const server = await reconfigureServer(); diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 27f55865d0..cf8072dc91 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -28,6 +28,13 @@ module.exports.SchemaOptions = { action: parsers.booleanParser, default: false, }, + keepUnknownIndexes: { + env: 'PARSE_SERVER_SCHEMA_KEEP_UNKNOWN_INDEXES', + help: + 'Keep indexes that are not defined in the schema and are present in the database. Set this to true if you are adding indexes manually so that it wont be dropped when you run schema migration', + action: parsers.booleanParser, + default: false, + }, lockSchemas: { env: 'PARSE_SERVER_SCHEMA_LOCK_SCHEMAS', help: diff --git a/src/Options/docs.js b/src/Options/docs.js index 31c4f4ea07..a25cda57d2 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -4,6 +4,7 @@ * @property {Function} beforeMigration Execute a callback before running schema migrations. * @property {Any} definitions Rest representation on Parse.Schema https://docs.parseplatform.org/rest/guide/#adding-a-schema * @property {Boolean} deleteExtraFields Is true if Parse Server should delete any fields not defined in a schema definition. This should only be used during development. + * @property {Boolean} keepUnknownIndexes Keep indexes that are not defined in the schema and are present in the database. Set this to true if you are adding indexes manually so that it wont be dropped when you run schema migration * @property {Boolean} lockSchemas Is true if Parse Server will reject any attempts to modify the schema while the server is running. * @property {Boolean} recreateModifiedFields Is true if Parse Server should recreate any fields that are different between the current database schema and theschema definition. This should only be used during development. * @property {Boolean} strict Is true if Parse Server should exit if schema update fail. diff --git a/src/Options/index.js b/src/Options/index.js index 75c1945108..6522ede054 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -25,6 +25,9 @@ export interface SchemaOptions { /* Is true if Parse Server will reject any attempts to modify the schema while the server is running. :DEFAULT: false */ lockSchemas: ?boolean; + /* Keep indexes that are not defined in the schema and are present in the database. Set this to true if you are adding indexes manually so that it wont be dropped when you run schema migration + :DEFAULT: false */ + keepUnknownIndexes: ?boolean; /* Execute a callback before running schema migrations. */ beforeMigration: ?() => void | Promise; /* Execute a callback after running schema migrations. */ diff --git a/src/SchemaMigrations/DefinedSchemas.js b/src/SchemaMigrations/DefinedSchemas.js index e9c685797c..c927041c44 100644 --- a/src/SchemaMigrations/DefinedSchemas.js +++ b/src/SchemaMigrations/DefinedSchemas.js @@ -349,7 +349,10 @@ export class DefinedSchemas { Object.keys(cloudSchema.indexes).forEach(indexName => { if (!this.isProtectedIndex(localSchema.className, indexName)) { if (!localSchema.indexes || !localSchema.indexes[indexName]) { - newLocalSchema.deleteIndex(indexName); + // If keepUnknownIndex is falsy, then delete all unknown indexes from the db. + if(!this.schemaOptions.keepUnknownIndexes){ + newLocalSchema.deleteIndex(indexName); + } } else if ( !this.paramsAreEquals(localSchema.indexes[indexName], cloudSchema.indexes[indexName]) ) { diff --git a/src/SchemaMigrations/Migrations.js b/src/SchemaMigrations/Migrations.js index 8768911189..23499bdba7 100644 --- a/src/SchemaMigrations/Migrations.js +++ b/src/SchemaMigrations/Migrations.js @@ -6,6 +6,7 @@ export interface SchemaOptions { deleteExtraFields: ?boolean; recreateModifiedFields: ?boolean; lockSchemas: ?boolean; + keepUnknownIndexes: ?boolean; beforeMigration: ?() => void | Promise; afterMigration: ?() => void | Promise; }