diff --git a/spec/schemas.spec.js b/spec/schemas.spec.js index 0ff8a22e66..b257c001bf 100644 --- a/spec/schemas.spec.js +++ b/spec/schemas.spec.js @@ -431,6 +431,7 @@ describe('schemas', () => { defaultValue: false, }, defaultZero: { type: 'Number', defaultValue: 0 }, + relation: { type: 'Relation', targetClass: 'SomeClass' } }, }, }).then(async response => { @@ -457,6 +458,7 @@ describe('schemas', () => { defaultValue: false, }, defaultZero: { type: 'Number', defaultValue: 0 }, + relation: { type: 'Relation', targetClass: 'SomeClass' } }, classLevelPermissions: defaultClassLevelPermissions, }); @@ -479,10 +481,108 @@ describe('schemas', () => { expect(obj.get('defaultFalse')).toEqual(false); expect(obj.get('defaultZero')).toEqual(0); expect(obj.get('ptr')).toBeUndefined(); + expect(obj.get('relation')).toBeUndefined(); done(); }); }); + it('try to set a relation field as a required field', async (done) => { + try { + await request({ + url: 'http://localhost:8378/1/schemas', + method: 'POST', + headers: masterKeyHeaders, + json: true, + body: { + className: 'NewClassWithRelationRequired', + fields: { + foo: { type: 'String' }, + relation: { type: 'Relation', targetClass: 'SomeClass', required: true } + }, + }, + }); + fail('should fail'); + } catch (e) { + expect(e.data.code).toEqual(111); + } + done(); + }); + + it('try to set a relation field with a default value', async (done) => { + try { + await request({ + url: 'http://localhost:8378/1/schemas', + method: 'POST', + headers: masterKeyHeaders, + json: true, + body: { + className: 'NewClassRelationWithOptions', + fields: { + foo: { type: 'String' }, + relation: { type: 'Relation', targetClass: 'SomeClass', defaultValue: { __type: 'Relation', className: '_User' } } + }, + }, + }); + fail('should fail'); + } catch (e) { + expect(e.data.code).toEqual(111); + } + done(); + }); + + it('try to update schemas with a relation field with options', async (done) => { + await request({ + url: 'http://localhost:8378/1/schemas', + method: 'POST', + headers: masterKeyHeaders, + json: true, + body: { + className: 'NewClassRelationWithOptions', + fields: { + foo: { type: 'String' } + }, + }, + }); + try { + await request({ + url: 'http://localhost:8378/1/schemas/NewClassRelationWithOptions', + method: 'POST', + headers: masterKeyHeaders, + json: true, + body: { + className: 'NewClassRelationWithOptions', + fields: { + relation: { type: 'Relation', targetClass: 'SomeClass', required: true } + }, + _method: "PUT" + } + }); + fail('should fail'); + } catch (e) { + expect(e.data.code).toEqual(111); + } + + try { + await request({ + url: 'http://localhost:8378/1/schemas/NewClassRelationWithOptions', + method: 'POST', + headers: masterKeyHeaders, + json: true, + body: { + className: 'NewClassRelationWithOptions', + fields: { + relation: { type: 'Relation', targetClass: 'SomeClass', defaultValue: { __type: 'Relation', className: '_User' } } + }, + _method: "PUT" + } + }); + fail('should fail'); + } catch (e) { + expect(e.data.code).toEqual(111); + } + done(); + }); + it('validated the data type of default values when creating a new class', async () => { try { await request({ diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index 23c4013ee5..da75c2f1f2 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -898,22 +898,34 @@ export default class SchemaController { error: 'field ' + fieldName + ' cannot be added', }; } - const type = fields[fieldName]; - const error = fieldTypeIsInvalid(type); + const fieldType = fields[fieldName]; + const error = fieldTypeIsInvalid(fieldType); if (error) return { code: error.code, error: error.message }; - if (type.defaultValue !== undefined) { - let defaultValueType = getType(type.defaultValue); + if (fieldType.defaultValue !== undefined) { + let defaultValueType = getType(fieldType.defaultValue); if (typeof defaultValueType === 'string') { defaultValueType = { type: defaultValueType }; + } else if (typeof defaultValueType === 'object' && fieldType.type === 'Relation') { + return { + code: Parse.Error.INCORRECT_TYPE, + error: `The 'default value' option is not applicable for ${typeToString(fieldType)}` + }; } - if (!dbTypeMatchesObjectType(type, defaultValueType)) { + if (!dbTypeMatchesObjectType(fieldType, defaultValueType)) { return { code: Parse.Error.INCORRECT_TYPE, error: `schema mismatch for ${className}.${fieldName} default value; expected ${typeToString( - type + fieldType )} but got ${typeToString(defaultValueType)}`, }; } + } else if (fieldType.required) { + if (typeof fieldType === 'object' && fieldType.type === 'Relation') { + return { + code: Parse.Error.INCORRECT_TYPE, + error: `The 'required' option is not applicable for ${typeToString(fieldType)}` + }; + } } } }