diff --git a/spec/SchemaPerformance.spec.js b/spec/SchemaPerformance.spec.js index 21e97b0d43..72cd93938c 100644 --- a/spec/SchemaPerformance.spec.js +++ b/spec/SchemaPerformance.spec.js @@ -18,7 +18,7 @@ describe_only_db('mongo')('Schema Performance', function () { const object = new TestObject(); object.set('foo', 'bar'); await object.save(); - expect(getAllSpy.calls.count()).toBe(2); + expect(getAllSpy.calls.count()).toBe(0); }); it('test new object multiple fields', async () => { @@ -30,7 +30,7 @@ describe_only_db('mongo')('Schema Performance', function () { booleanField: true, }); await container.save(); - expect(getAllSpy.calls.count()).toBe(2); + expect(getAllSpy.calls.count()).toBe(0); }); it('test update existing fields', async () => { @@ -83,7 +83,7 @@ describe_only_db('mongo')('Schema Performance', function () { object.set('new', 'barz'); await object.save(); - expect(getAllSpy.calls.count()).toBe(1); + expect(getAllSpy.calls.count()).toBe(0); }); it('test add multiple fields to existing object', async () => { @@ -101,7 +101,7 @@ describe_only_db('mongo')('Schema Performance', function () { booleanField: true, }); await object.save(); - expect(getAllSpy.calls.count()).toBe(1); + expect(getAllSpy.calls.count()).toBe(0); }); it('test user', async () => { @@ -110,7 +110,7 @@ describe_only_db('mongo')('Schema Performance', function () { user.setPassword('testing'); await user.signUp(); - expect(getAllSpy.calls.count()).toBe(1); + expect(getAllSpy.calls.count()).toBe(0); }); it('test query include', async () => { diff --git a/src/Adapters/Cache/SchemaCache.js b/src/Adapters/Cache/SchemaCache.js index f55edf0635..43f1f2e397 100644 --- a/src/Adapters/Cache/SchemaCache.js +++ b/src/Adapters/Cache/SchemaCache.js @@ -9,6 +9,17 @@ export default { return this.all().find(cached => cached.className === className); }, + set(className, schema) { + const cache = this.all(); + const index = cache.findIndex(cached => cached.className === className); + if (index >= 0) { + cache[index] = schema; + } else { + cache.push(schema); + } + this.put(cache); + }, + put(allSchema) { SchemaCache.allClasses = allSchema; }, diff --git a/src/Adapters/Storage/StorageAdapter.js b/src/Adapters/Storage/StorageAdapter.js index d46265f64f..fc1444b967 100644 --- a/src/Adapters/Storage/StorageAdapter.js +++ b/src/Adapters/Storage/StorageAdapter.js @@ -34,7 +34,12 @@ export interface StorageAdapter { classExists(className: string): Promise; setClassLevelPermissions(className: string, clps: any): Promise; createClass(className: string, schema: SchemaType): Promise; - addFieldIfNotExists(className: string, fieldName: string, type: any): Promise; + addFieldIfNotExists( + className: string, + fieldName: string, + type: any, + transactionalSession: ?any + ): Promise; deleteClass(className: string): Promise; deleteAllClasses(fast: boolean): Promise; deleteFields(className: string, schema: SchemaType, fieldNames: Array): Promise; diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index 90f32b0b16..f2663f18cc 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -807,9 +807,8 @@ export default class SchemaController { className, }) ); - // TODO: Remove by updating schema cache directly - await this.reloadData({ clearCache: true }); const parseSchema = convertAdapterSchemaToParseSchema(adapterSchema); + SchemaCache.set(className, parseSchema); return parseSchema; } catch (error) { if (error && error.code === Parse.Error.DUPLICATE_VALUE) { @@ -875,12 +874,14 @@ export default class SchemaController { return ( deletePromise // Delete Everything .then(() => this.reloadData({ clearCache: true })) // Reload our Schema, so we have all the new values - .then(() => { - const promises = insertedFields.map(fieldName => { + .then(async () => { + const results = []; + for (let i = 0; i < insertedFields.length; i += 1) { + const fieldName = insertedFields[i]; const type = submittedFields[fieldName]; - return this.enforceFieldExists(className, fieldName, type); - }); - return Promise.all(promises); + results.push(await this.enforceFieldExists(className, fieldName, type)); + } + return results; }) .then(results => { enforceFields = results.filter(result => !!result); @@ -933,6 +934,7 @@ export default class SchemaController { return ( // The schema update succeeded. Reload the schema this.addClassIfNotExists(className) + .then(() => this.reloadData()) .catch(() => { // The schema update failed. This can be okay - it might // have failed because there's a race condition and a different @@ -1118,6 +1120,13 @@ export default class SchemaController { return Promise.resolve(); }) .then(() => { + const cached = SchemaCache.get(className); + if (cached) { + if (cached && !cached.fields[fieldName]) { + cached.fields[fieldName] = type; + SchemaCache.set(className, cached); + } + } return { className, fieldName, @@ -1210,7 +1219,7 @@ export default class SchemaController { async validateObject(className: string, object: any, query: any) { let geocount = 0; const schema = await this.enforceClassExists(className); - const promises = []; + const results = []; for (const fieldName in object) { if (object[fieldName] && getType(object[fieldName]) === 'GeoPoint') { @@ -1237,14 +1246,12 @@ export default class SchemaController { // Every object has ACL implicitly. continue; } - promises.push(schema.enforceFieldExists(className, fieldName, expected)); + results.push(await schema.enforceFieldExists(className, fieldName, expected)); } - const results = await Promise.all(promises); const enforceFields = results.filter(result => !!result); if (enforceFields.length !== 0) { - // TODO: Remove by updating schema cache directly - await this.reloadData({ clearCache: true }); + await this.reloadData(); } this.ensureFields(enforceFields);