Skip to content

Implement Schemas PUT #452

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 17, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions spec/Schema.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ describe('Schema', () => {
foo: 'string',
})
done();
})
.catch(error => {
fail('Error creating class: ' + JSON.stringify(error));
});
});

Expand Down Expand Up @@ -570,4 +573,32 @@ describe('Schema', () => {
Parse.Object.enableSingleInstance();
});
});

it('can merge schemas', done => {
expect(Schema.buildMergedSchemaObject({
_id: 'SomeClass',
someType: 'number'
}, {
newType: {type: 'Number'}
})).toEqual({
someType: {type: 'Number'},
newType: {type: 'Number'},
});
done();
});

it('can merge deletions', done => {
expect(Schema.buildMergedSchemaObject({
_id: 'SomeClass',
someType: 'number',
outDatedType: 'string',
},{
newType: {type: 'GeoPoint'},
outDatedType: {__op: 'Delete'},
})).toEqual({
someType: {type: 'Number'},
newType: {type: 'GeoPoint'},
});
done();
});
});
317 changes: 316 additions & 1 deletion spec/schemas.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ describe('schemas', () => {
headers: restKeyHeaders,
}, (error, response, body) => {
expect(response.statusCode).toEqual(401);
expect(body.error).toEqual('unauthorized');
expect(body.error).toEqual('master key not specified');
done();
});
});
Expand Down Expand Up @@ -318,4 +318,319 @@ describe('schemas', () => {
done();
});
});

it('requires the master key to modify schemas', done => {
request.post({
url: 'http://localhost:8378/1/schemas/NewClass',
headers: masterKeyHeaders,
json: true,
body: {},
}, (error, response, body) => {
request.put({
url: 'http://localhost:8378/1/schemas/NewClass',
headers: noAuthHeaders,
json: true,
body: {},
}, (error, response, body) => {
expect(response.statusCode).toEqual(403);
expect(body.error).toEqual('unauthorized');
done();
});
});
});

it('rejects class name mis-matches in put', done => {
request.put({
url: 'http://localhost:8378/1/schemas/NewClass',
headers: masterKeyHeaders,
json: true,
body: {className: 'WrongClassName'}
}, (error, response, body) => {
expect(response.statusCode).toEqual(400);
expect(body.code).toEqual(Parse.Error.INVALID_CLASS_NAME);
expect(body.error).toEqual('class name mismatch between WrongClassName and NewClass');
done();
});
});

it('refuses to add fields to non-existent classes', done => {
request.put({
url: 'http://localhost:8378/1/schemas/NoClass',
headers: masterKeyHeaders,
json: true,
body: {
fields: {
newField: {type: 'String'}
}
}
}, (error, response, body) => {
expect(response.statusCode).toEqual(400);
expect(body.code).toEqual(Parse.Error.INVALID_CLASS_NAME);
expect(body.error).toEqual('class NoClass does not exist');
done();
});
});

it('refuses to put to existing fields, even if it would not be a change', done => {
var obj = hasAllPODobject();
obj.save()
.then(() => {
request.put({
url: 'http://localhost:8378/1/schemas/HasAllPOD',
headers: masterKeyHeaders,
json: true,
body: {
fields: {
aString: {type: 'String'}
}
}
}, (error, response, body) => {
expect(response.statusCode).toEqual(400);
expect(body.code).toEqual(255);
expect(body.error).toEqual('field aString exists, cannot update');
done();
});
})
});

it('refuses to delete non-existant fields', done => {
var obj = hasAllPODobject();
obj.save()
.then(() => {
request.put({
url: 'http://localhost:8378/1/schemas/HasAllPOD',
headers: masterKeyHeaders,
json: true,
body: {
fields: {
nonExistantKey: {__op: "Delete"},
}
}
}, (error, response, body) => {
expect(response.statusCode).toEqual(400);
expect(body.code).toEqual(255);
expect(body.error).toEqual('field nonExistantKey does not exist, cannot delete');
done();
});
});
});

it('refuses to add a geopoint to a class that already has one', done => {
var obj = hasAllPODobject();
obj.save()
.then(() => {
request.put({
url: 'http://localhost:8378/1/schemas/HasAllPOD',
headers: masterKeyHeaders,
json: true,
body: {
fields: {
newGeo: {type: 'GeoPoint'}
}
}
}, (error, response, body) => {
expect(response.statusCode).toEqual(400);
expect(body.code).toEqual(Parse.Error.INCORRECT_TYPE);
expect(body.error).toEqual('currently, only one GeoPoint field may exist in an object. Adding newGeo when aGeoPoint already exists.');
done();
});
});
});

it('refuses to add two geopoints', done => {
var obj = new Parse.Object('NewClass');
obj.set('aString', 'aString');
obj.save()
.then(() => {
request.put({
url: 'http://localhost:8378/1/schemas/NewClass',
headers: masterKeyHeaders,
json: true,
body: {
fields: {
newGeo1: {type: 'GeoPoint'},
newGeo2: {type: 'GeoPoint'},
}
}
}, (error, response, body) => {
expect(response.statusCode).toEqual(400);
expect(body.code).toEqual(Parse.Error.INCORRECT_TYPE);
expect(body.error).toEqual('currently, only one GeoPoint field may exist in an object. Adding newGeo2 when newGeo1 already exists.');
done();
});
});
});

it('allows you to delete and add a geopoint in the same request', done => {
var obj = new Parse.Object('NewClass');
obj.set('geo1', new Parse.GeoPoint({latitude: 0, longitude: 0}));
obj.save()
.then(() => {
request.put({
url: 'http://localhost:8378/1/schemas/NewClass',
headers: masterKeyHeaders,
json: true,
body: {
fields: {
geo2: {type: 'GeoPoint'},
geo1: {__op: 'Delete'}
}
}
}, (error, response, body) => {
expect(dd(body, {
"className": "NewClass",
"fields": {
"ACL": {"type": "ACL"},
"createdAt": {"type": "Date"},
"objectId": {"type": "String"},
"updatedAt": {"type": "Date"},
"geo2": {"type": "GeoPoint"},
}
})).toEqual(undefined);
done();
});
})
});

it('put with no modifications returns all fields', done => {
var obj = hasAllPODobject();
obj.save()
.then(() => {
request.put({
url: 'http://localhost:8378/1/schemas/HasAllPOD',
headers: masterKeyHeaders,
json: true,
body: {},
}, (error, response, body) => {
expect(body).toEqual(plainOldDataSchema);
done();
});
})
});

it('lets you add fields', done => {
request.post({
url: 'http://localhost:8378/1/schemas/NewClass',
headers: masterKeyHeaders,
json: true,
body: {},
}, (error, response, body) => {
request.put({
url: 'http://localhost:8378/1/schemas/NewClass',
headers: masterKeyHeaders,
json: true,
body: {
fields: {
newField: {type: 'String'}
}
}
}, (error, response, body) => {
expect(dd(body, {
className: 'NewClass',
fields: {
"ACL": {"type": "ACL"},
"createdAt": {"type": "Date"},
"objectId": {"type": "String"},
"updatedAt": {"type": "Date"},
"newField": {"type": "String"},
},
})).toEqual(undefined);
request.get({
url: 'http://localhost:8378/1/schemas/NewClass',
headers: masterKeyHeaders,
json: true,
}, (error, response, body) => {
expect(body).toEqual({
className: 'NewClass',
fields: {
ACL: {type: 'ACL'},
createdAt: {type: 'Date'},
updatedAt: {type: 'Date'},
objectId: {type: 'String'},
newField: {type: 'String'},
}
});
done();
});
});
})
});

it('lets you delete multiple fields and add fields', done => {
var obj1 = hasAllPODobject();
obj1.save()
.then(() => {
request.put({
url: 'http://localhost:8378/1/schemas/HasAllPOD',
headers: masterKeyHeaders,
json: true,
body: {
fields: {
aString: {__op: 'Delete'},
aNumber: {__op: 'Delete'},
aNewString: {type: 'String'},
aNewNumber: {type: 'Number'},
aNewRelation: {type: 'Relation', targetClass: 'HasAllPOD'},
aNewPointer: {type: 'Pointer', targetClass: 'HasAllPOD'},
}
}
}, (error, response, body) => {
expect(body).toEqual({
className: 'HasAllPOD',
fields: {
//Default fields
ACL: {type: 'ACL'},
createdAt: {type: 'Date'},
updatedAt: {type: 'Date'},
objectId: {type: 'String'},
//Custom fields
aBool: {type: 'Boolean'},
aDate: {type: 'Date'},
aObject: {type: 'Object'},
aArray: {type: 'Array'},
aGeoPoint: {type: 'GeoPoint'},
aFile: {type: 'File'},
aNewNumber: {type: 'Number'},
aNewString: {type: 'String'},
aNewPointer: {type: 'Pointer', targetClass: 'HasAllPOD'},
aNewRelation: {type: 'Relation', targetClass: 'HasAllPOD'},
}
});
var obj2 = new Parse.Object('HasAllPOD');
obj2.set('aNewPointer', obj1);
var relation = obj2.relation('aNewRelation');
relation.add(obj1);
obj2.save().then(done); //Just need to make sure saving works on the new object.
});
});
});

it('will not delete any fields if the additions are invalid', done => {
var obj = hasAllPODobject();
obj.save()
.then(() => {
request.put({
url: 'http://localhost:8378/1/schemas/HasAllPOD',
headers: masterKeyHeaders,
json: true,
body: {
fields: {
fakeNewField: {type: 'fake type'},
aString: {__op: 'Delete'}
}
}
}, (error, response, body) => {
expect(body.code).toEqual(Parse.Error.INCORRECT_TYPE);
expect(body.error).toEqual('invalid field type: fake type');
request.get({
url: 'http://localhost:8378/1/schemas/HasAllPOD',
headers: masterKeyHeaders,
json: true,
}, (error, response, body) => {
expect(response.body).toEqual(plainOldDataSchema);
done();
});
});
});
});
});
Loading