@@ -273,19 +273,22 @@ class SchemaController {
273273 data ;
274274 perms ;
275275
276- constructor ( databaseAdapter ) {
276+ constructor ( databaseAdapter , schemaCache ) {
277277 this . _dbAdapter = databaseAdapter ;
278-
278+ this . _cache = schemaCache ;
279279 // this.data[className][fieldName] tells you the type of that field, in mongo format
280280 this . data = { } ;
281281 // this.perms[className][operation] tells you the acl-style permissions
282282 this . perms = { } ;
283283 }
284284
285- reloadData ( ) {
285+ reloadData ( clearCache = false ) {
286286 this . data = { } ;
287287 this . perms = { } ;
288- return this . getAllClasses ( )
288+ if ( clearCache ) {
289+ this . _cache . reset ( ) ;
290+ }
291+ return this . getAllClasses ( clearCache )
289292 . then ( allSchemas => {
290293 allSchemas . forEach ( schema => {
291294 this . data [ schema . className ] = injectDefaultSchema ( schema ) . fields ;
@@ -303,17 +306,39 @@ class SchemaController {
303306 } ) ;
304307 }
305308
306- getAllClasses ( ) {
309+ getAllClasses ( clearCache = false ) {
310+ if ( clearCache ) {
311+ this . _cache . reset ( ) ;
312+ }
313+ let allClasses = this . _cache . get ( ) ;
314+ if ( allClasses && allClasses . length && ! clearCache ) {
315+ return Promise . resolve ( allClasses ) ;
316+ }
307317 return this . _dbAdapter . getAllClasses ( )
308- . then ( allSchemas => allSchemas . map ( injectDefaultSchema ) ) ;
318+ . then ( allSchemas => allSchemas . map ( injectDefaultSchema ) )
319+ . then ( allSchemas => {
320+ this . _cache . set ( allSchemas ) ;
321+ return allSchemas ;
322+ } )
309323 }
310324
311- getOneSchema ( className , allowVolatileClasses = false ) {
325+ getOneSchema ( className , allowVolatileClasses = false , clearCache ) {
326+ if ( clearCache ) {
327+ this . _cache . reset ( ) ;
328+ }
329+ let cached = this . _cache . getOneSchema ( className ) ;
330+ if ( cached && ! clearCache ) {
331+ return Promise . resolve ( cached ) ;
332+ }
312333 if ( allowVolatileClasses && volatileClasses . indexOf ( className ) > - 1 ) {
313334 return Promise . resolve ( this . data [ className ] ) ;
314335 }
315336 return this . _dbAdapter . getClass ( className )
316337 . then ( injectDefaultSchema )
338+ . then ( ( result ) => {
339+ this . _cache . setOneSchema ( className , result ) ;
340+ return result ;
341+ } )
317342 }
318343
319344 // Create a new class that includes the three default fields.
@@ -331,6 +356,10 @@ class SchemaController {
331356
332357 return this . _dbAdapter . createClass ( className , convertSchemaToAdapterSchema ( { fields, classLevelPermissions, className } ) )
333358 . then ( convertAdapterSchemaToParseSchema )
359+ . then ( ( res ) => {
360+ this . _cache . reset ( ) ;
361+ return res ;
362+ } )
334363 . catch ( error => {
335364 if ( error && error . code === Parse . Error . DUPLICATE_VALUE ) {
336365 throw new Parse . Error ( Parse . Error . INVALID_CLASS_NAME , `Class ${ className } already exists.` ) ;
@@ -376,7 +405,7 @@ class SchemaController {
376405 } ) ;
377406
378407 return Promise . all ( deletePromises ) // Delete Everything
379- . then ( ( ) => this . reloadData ( ) ) // Reload our Schema, so we have all the new values
408+ . then ( ( ) => this . reloadData ( true ) ) // Reload our Schema, so we have all the new values
380409 . then ( ( ) => {
381410 let promises = insertedFields . map ( fieldName => {
382411 const type = submittedFields [ fieldName ] ;
@@ -410,13 +439,13 @@ class SchemaController {
410439 // We don't have this class. Update the schema
411440 return this . addClassIfNotExists ( className )
412441 // The schema update succeeded. Reload the schema
413- . then ( ( ) => this . reloadData ( ) )
442+ . then ( ( ) => this . reloadData ( true ) )
414443 . catch ( error => {
415444 // The schema update failed. This can be okay - it might
416445 // have failed because there's a race condition and a different
417446 // client is making the exact same schema update that we want.
418447 // So just reload the schema.
419- return this . reloadData ( ) ;
448+ return this . reloadData ( true ) ;
420449 } )
421450 . then ( ( ) => {
422451 // Ensure that the schema now validates
@@ -486,7 +515,7 @@ class SchemaController {
486515 }
487516 validateCLP ( perms , newSchema ) ;
488517 return this . _dbAdapter . setClassLevelPermissions ( className , perms )
489- . then ( ( ) => this . reloadData ( ) ) ;
518+ . then ( ( ) => this . reloadData ( true ) ) ;
490519 }
491520
492521 // Returns a promise that resolves successfully to the new schema
@@ -521,23 +550,26 @@ class SchemaController {
521550 `schema mismatch for ${ className } .${ fieldName } ; expected ${ expectedType . type || expectedType } but got ${ type . type } `
522551 ) ;
523552 }
553+ return this ;
524554 }
525555
526556 return this . _dbAdapter . addFieldIfNotExists ( className , fieldName , type ) . then ( ( ) => {
527557 // The update succeeded. Reload the schema
528- return this . reloadData ( ) ;
558+ return this . reloadData ( true ) ;
529559 } , error => {
530560 //TODO: introspect the error and only reload if the error is one for which is makes sense to reload
531561
532562 // The update failed. This can be okay - it might have been a race
533563 // condition where another client updated the schema in the same
534564 // way that we wanted to. So, just reload the schema
535- return this . reloadData ( ) ;
565+ return this . reloadData ( true ) ;
536566 } ) . then ( error => {
537567 // Ensure that the schema now validates
538568 if ( ! dbTypeMatchesObjectType ( this . getExpectedType ( className , fieldName ) , type ) ) {
539569 throw new Parse . Error ( Parse . Error . INVALID_JSON , `Could not add field ${ fieldName } ` ) ;
540570 }
571+ // Remove the cached schema
572+ this . _cache . reset ( ) ;
541573 return this ;
542574 } ) ;
543575 } ) ;
@@ -562,7 +594,7 @@ class SchemaController {
562594 throw new Parse . Error ( 136 , `field ${ fieldName } cannot be changed` ) ;
563595 }
564596
565- return this . getOneSchema ( className )
597+ return this . getOneSchema ( className , false , true )
566598 . catch ( error => {
567599 if ( error === undefined ) {
568600 throw new Parse . Error ( Parse . Error . INVALID_CLASS_NAME , `Class ${ className } does not exist.` ) ;
@@ -579,8 +611,9 @@ class SchemaController {
579611 return database . adapter . deleteFields ( className , schema , [ fieldName ] )
580612 . then ( ( ) => database . adapter . deleteClass ( `_Join:${ fieldName } :${ className } ` ) ) ;
581613 }
582-
583614 return database . adapter . deleteFields ( className , schema , [ fieldName ] ) ;
615+ } ) . then ( ( ) => {
616+ this . _cache . reset ( ) ;
584617 } ) ;
585618 }
586619
@@ -711,9 +744,9 @@ class SchemaController {
711744}
712745
713746// Returns a promise for a new Schema.
714- const load = dbAdapter => {
715- let schema = new SchemaController ( dbAdapter ) ;
716- return schema . reloadData ( ) . then ( ( ) => schema ) ;
747+ const load = ( dbAdapter , schemaCache , clearCache ) => {
748+ let schema = new SchemaController ( dbAdapter , schemaCache ) ;
749+ return schema . reloadData ( clearCache ) . then ( ( ) => schema ) ;
717750}
718751
719752// Builds a new schema (in schema API response format) out of an
0 commit comments