@@ -97,7 +97,7 @@ const requiredColumns = Object.freeze({
97
97
98
98
const systemClasses = Object . freeze ( [ '_User' , '_Installation' , '_Role' , '_Session' , '_Product' , '_PushStatus' ] ) ;
99
99
100
- const volatileClasses = Object . freeze ( [ '_PushStatus' ] ) ;
100
+ const volatileClasses = Object . freeze ( [ '_PushStatus' , '_Hooks' , '_GlobalConfig' ] ) ;
101
101
102
102
// 10 alpha numberic chars + uppercase
103
103
const userIdRegex = / ^ [ a - z A - Z 0 - 9 ] { 10 } $ / ;
@@ -244,6 +244,14 @@ const injectDefaultSchema = schema => ({
244
244
classLevelPermissions : schema . classLevelPermissions ,
245
245
} )
246
246
247
+ const dbTypeMatchesObjectType = ( dbType , objectType ) => {
248
+ if ( dbType . type !== objectType . type ) return false ;
249
+ if ( dbType . targetClass !== objectType . targetClass ) return false ;
250
+ if ( dbType === objectType . type ) return true ;
251
+ if ( dbType . type === objectType . type ) return true ;
252
+ return false ;
253
+ }
254
+
247
255
// Stores the entire schema of the app in a weird hybrid format somewhere between
248
256
// the mongo format and the Parse format. Soon, this will all be Parse format.
249
257
class SchemaController {
@@ -358,7 +366,7 @@ class SchemaController {
358
366
. then ( ( ) => {
359
367
let promises = insertedFields . map ( fieldName => {
360
368
const type = submittedFields [ fieldName ] ;
361
- return this . validateField ( className , fieldName , type ) ;
369
+ return this . enforceFieldExists ( className , fieldName , type ) ;
362
370
} ) ;
363
371
return Promise . all ( promises ) ;
364
372
} )
@@ -460,49 +468,36 @@ class SchemaController {
460
468
// object if the provided className-fieldName-type tuple is valid.
461
469
// The className must already be validated.
462
470
// If 'freeze' is true, refuse to update the schema for this field.
463
- validateField ( className , fieldName , type , freeze ) {
464
- return this . reloadData ( ) . then ( ( ) => {
465
- if ( fieldName . indexOf ( "." ) > 0 ) {
466
- // subdocument key (x.y) => ok if x is of type 'object'
467
- fieldName = fieldName . split ( "." ) [ 0 ] ;
468
- type = 'Object' ;
469
- }
471
+ enforceFieldExists ( className , fieldName , type , freeze ) {
472
+ if ( fieldName . indexOf ( "." ) > 0 ) {
473
+ // subdocument key (x.y) => ok if x is of type 'object'
474
+ fieldName = fieldName . split ( "." ) [ 0 ] ;
475
+ type = 'Object' ;
476
+ }
477
+ if ( ! fieldNameIsValid ( fieldName ) ) {
478
+ throw new Parse . Error ( Parse . Error . INVALID_KEY_NAME , `Invalid field name: ${ fieldName } .` ) ;
479
+ }
470
480
471
- if ( ! fieldNameIsValid ( fieldName ) ) {
472
- throw new Parse . Error ( Parse . Error . INVALID_KEY_NAME , `Invalid field name: ${ fieldName } .` ) ;
481
+ // If someone tries to create a new field with null/undefined as the value, return;
482
+ if ( ! type ) {
483
+ return Promise . resolve ( this ) ;
484
+ }
485
+
486
+ return this . reloadData ( ) . then ( ( ) => {
487
+ let expectedType = this . getExpectedType ( className , fieldName ) ;
488
+ if ( typeof type === 'string' ) {
489
+ type = { type } ;
473
490
}
474
491
475
- let expected = this . data [ className ] [ fieldName ] ;
476
- if ( expected ) {
477
- expected = ( expected === 'map' ? 'Object' : expected ) ;
478
- if ( expected . type && type . type
479
- && expected . type == type . type
480
- && expected . targetClass == type . targetClass ) {
481
- return Promise . resolve ( this ) ;
482
- } else if ( expected == type || expected . type == type ) {
483
- return Promise . resolve ( this ) ;
484
- } else {
492
+ if ( expectedType ) {
493
+ if ( ! dbTypeMatchesObjectType ( expectedType , type ) ) {
485
494
throw new Parse . Error (
486
495
Parse . Error . INCORRECT_TYPE ,
487
- `schema mismatch for ${ className } .${ fieldName } ; expected ${ expected . type || expected } but got ${ type } `
496
+ `schema mismatch for ${ className } .${ fieldName } ; expected ${ expectedType . type || expectedType } but got ${ type } `
488
497
) ;
489
498
}
490
499
}
491
500
492
- if ( freeze ) {
493
- throw new Parse . Error ( Parse . Error . INVALID_JSON , `schema is frozen, cannot add ${ fieldName } field` ) ;
494
- }
495
-
496
- // We don't have this field, but if the value is null or undefined,
497
- // we won't update the schema until we get a value with a type.
498
- if ( ! type ) {
499
- return Promise . resolve ( this ) ;
500
- }
501
-
502
- if ( typeof type === 'string' ) {
503
- type = { type } ;
504
- }
505
-
506
501
return this . _dbAdapter . addFieldIfNotExists ( className , fieldName , type ) . then ( ( ) => {
507
502
// The update succeeded. Reload the schema
508
503
return this . reloadData ( ) ;
@@ -513,11 +508,10 @@ class SchemaController {
513
508
return this . reloadData ( ) ;
514
509
} ) . then ( ( ) => {
515
510
// Ensure that the schema now validates
516
- return this . validateField ( className , fieldName , type , true ) ;
517
- } , ( error ) => {
518
- // The schema still doesn't validate. Give up
519
- throw new Parse . Error ( Parse . Error . INVALID_JSON ,
520
- 'schema key will not revalidate' ) ;
511
+ if ( ! dbTypeMatchesObjectType ( this . getExpectedType ( className , fieldName ) , type ) ) {
512
+ throw new Parse . Error ( Parse . Error . INVALID_JSON , `Could not add field ${ fieldName } ` ) ;
513
+ }
514
+ return this ;
521
515
} ) ;
522
516
} ) ;
523
517
}
@@ -674,9 +668,10 @@ class SchemaController {
674
668
675
669
// Returns the expected type for a className+key combination
676
670
// or undefined if the schema is not set
677
- getExpectedType ( className , key ) {
671
+ getExpectedType ( className , fieldName ) {
678
672
if ( this . data && this . data [ className ] ) {
679
- return this . data [ className ] [ key ] ;
673
+ const expectedType = this . data [ className ] [ fieldName ]
674
+ return expectedType === 'map' ? 'Object' : expectedType ;
680
675
}
681
676
return undefined ;
682
677
} ;
@@ -727,7 +722,7 @@ function buildMergedSchemaObject(existingFields, putRequest) {
727
722
// validates this field once the schema loads.
728
723
function thenValidateField ( schemaPromise , className , key , type ) {
729
724
return schemaPromise . then ( ( schema ) => {
730
- return schema . validateField ( className , key , type ) ;
725
+ return schema . enforceFieldExists ( className , key , type ) ;
731
726
} ) ;
732
727
}
733
728
0 commit comments