Finish implementation of PUT /schemas/:className
This commit is contained in:
@@ -162,6 +162,9 @@ describe('Schema', () => {
|
||||
foo: 'string',
|
||||
})
|
||||
done();
|
||||
})
|
||||
.catch(error => {
|
||||
fail('Error creating class: ' + JSON.stringify(error));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -339,7 +339,7 @@ describe('schemas', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects class name mis-matches', done => {
|
||||
it('rejects class name mis-matches in put', done => {
|
||||
request.put({
|
||||
url: 'http://localhost:8378/1/schemas/NewClass',
|
||||
headers: masterKeyHeaders,
|
||||
@@ -349,6 +349,7 @@ describe('schemas', () => {
|
||||
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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -370,12 +371,133 @@ describe('schemas', () => {
|
||||
});
|
||||
});
|
||||
|
||||
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'
|
||||
url: 'http://localhost:8378/1/schemas/HasAllPOD',
|
||||
headers: masterKeyHeaders,
|
||||
json: true,
|
||||
body: {},
|
||||
@@ -383,7 +505,7 @@ describe('schemas', () => {
|
||||
expect(body).toEqual(plainOldDataSchema);
|
||||
done();
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('lets you add fields', done => {
|
||||
@@ -403,16 +525,112 @@ describe('schemas', () => {
|
||||
}
|
||||
}
|
||||
}, (error, response, body) => {
|
||||
expect(body).toEqual('blah');
|
||||
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('blah');
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
169
src/Schema.js
169
src/Schema.js
@@ -116,7 +116,7 @@ function schemaAPITypeToMongoFieldType(type) {
|
||||
return invalidJsonError;
|
||||
} else if (!classNameIsValid(type.targetClass)) {
|
||||
return { error: invalidClassNameMessage(type.targetClass), code: Parse.Error.INVALID_CLASS_NAME };
|
||||
} else {
|
||||
} else {
|
||||
return { result: '*' + type.targetClass };
|
||||
}
|
||||
}
|
||||
@@ -200,6 +200,114 @@ Schema.prototype.reload = function() {
|
||||
return load(this.collection);
|
||||
};
|
||||
|
||||
// Returns { code, error } if invalid, or { result }, an object
|
||||
// suitable for inserting into _SCHEMA collection, otherwise
|
||||
function mongoSchemaFromFieldsAndClassName(fields, className) {
|
||||
if (!classNameIsValid(className)) {
|
||||
return {
|
||||
code: Parse.Error.INVALID_CLASS_NAME,
|
||||
error: invalidClassNameMessage(className),
|
||||
};
|
||||
}
|
||||
|
||||
for (var fieldName in fields) {
|
||||
if (!fieldNameIsValid(fieldName)) {
|
||||
return {
|
||||
code: Parse.Error.INVALID_KEY_NAME,
|
||||
error: 'invalid field name: ' + fieldName,
|
||||
};
|
||||
}
|
||||
if (!fieldNameIsValidForClass(fieldName, className)) {
|
||||
return {
|
||||
code: 136,
|
||||
error: 'field ' + fieldName + ' cannot be added',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var mongoObject = {
|
||||
_id: className,
|
||||
objectId: 'string',
|
||||
updatedAt: 'string',
|
||||
createdAt: 'string'
|
||||
};
|
||||
|
||||
for (var fieldName in defaultColumns[className]) {
|
||||
var validatedField = schemaAPITypeToMongoFieldType(defaultColumns[className][fieldName]);
|
||||
if (!validatedField.result) {
|
||||
return validatedField;
|
||||
}
|
||||
mongoObject[fieldName] = validatedField.result;
|
||||
}
|
||||
|
||||
for (var fieldName in fields) {
|
||||
var validatedField = schemaAPITypeToMongoFieldType(fields[fieldName]);
|
||||
if (!validatedField.result) {
|
||||
return validatedField;
|
||||
}
|
||||
mongoObject[fieldName] = validatedField.result;
|
||||
}
|
||||
|
||||
var geoPoints = Object.keys(mongoObject).filter(key => mongoObject[key] === 'geopoint');
|
||||
if (geoPoints.length > 1) {
|
||||
return {
|
||||
code: Parse.Error.INCORRECT_TYPE,
|
||||
error: 'currently, only one GeoPoint field may exist in an object. Adding ' + geoPoints[1] + ' when ' + geoPoints[0] + ' already exists.',
|
||||
};
|
||||
}
|
||||
|
||||
return { result: mongoObject };
|
||||
}
|
||||
|
||||
function mongoFieldTypeToSchemaAPIType(type) {
|
||||
if (type[0] === '*') {
|
||||
return {
|
||||
type: 'Pointer',
|
||||
targetClass: type.slice(1),
|
||||
};
|
||||
}
|
||||
if (type.startsWith('relation<')) {
|
||||
return {
|
||||
type: 'Relation',
|
||||
targetClass: type.slice('relation<'.length, type.length - 1),
|
||||
};
|
||||
}
|
||||
switch (type) {
|
||||
case 'number': return {type: 'Number'};
|
||||
case 'string': return {type: 'String'};
|
||||
case 'boolean': return {type: 'Boolean'};
|
||||
case 'date': return {type: 'Date'};
|
||||
case 'map':
|
||||
case 'object': return {type: 'Object'};
|
||||
case 'array': return {type: 'Array'};
|
||||
case 'geopoint': return {type: 'GeoPoint'};
|
||||
case 'file': return {type: 'File'};
|
||||
}
|
||||
}
|
||||
|
||||
// Builds a new schema (in schema API response format) out of an
|
||||
// existing mongo schema + a schemas API put request. This response
|
||||
// does not include the default fields, as it is intended to be passed
|
||||
// to mongoSchemaFromFieldsAndClassName. No validation is done here, it
|
||||
// is done in mongoSchemaFromFieldsAndClassName.
|
||||
function buildMergedSchemaObject(mongoObject, putRequest) {
|
||||
var newSchema = {};
|
||||
for (var oldField in mongoObject) {
|
||||
if (oldField !== '_id' && oldField !== 'ACL' && oldField !== 'updatedAt' && oldField !== 'createdAt' && oldField !== 'objectId') {
|
||||
var fieldIsDeleted = putRequest[oldField] && putRequest[oldField].__op === 'Delete'
|
||||
if (!fieldIsDeleted) {
|
||||
newSchema[oldField] = mongoFieldTypeToSchemaAPIType(mongoObject[oldField]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var newField in putRequest) {
|
||||
if (newField !== 'objectId' && putRequest[newField].__op !== 'Delete') {
|
||||
newSchema[newField] = putRequest[newField];
|
||||
}
|
||||
}
|
||||
return newSchema;
|
||||
}
|
||||
|
||||
// Create a new class that includes the three default fields.
|
||||
// ACL is an implicit column that does not get an entry in the
|
||||
// _SCHEMAS database. Returns a promise that resolves with the
|
||||
@@ -215,58 +323,13 @@ Schema.prototype.addClassIfNotExists = function(className, fields) {
|
||||
});
|
||||
}
|
||||
|
||||
if (!classNameIsValid(className)) {
|
||||
return Promise.reject({
|
||||
code: Parse.Error.INVALID_CLASS_NAME,
|
||||
error: invalidClassNameMessage(className),
|
||||
});
|
||||
}
|
||||
for (var fieldName in fields) {
|
||||
if (!fieldNameIsValid(fieldName)) {
|
||||
return Promise.reject({
|
||||
code: Parse.Error.INVALID_KEY_NAME,
|
||||
error: 'invalid field name: ' + fieldName,
|
||||
});
|
||||
}
|
||||
if (!fieldNameIsValidForClass(fieldName, className)) {
|
||||
return Promise.reject({
|
||||
code: 136,
|
||||
error: 'field ' + fieldName + ' cannot be added',
|
||||
});
|
||||
}
|
||||
var mongoObject = mongoSchemaFromFieldsAndClassName(fields, className);
|
||||
|
||||
if (!mongoObject.result) {
|
||||
return Promise.reject(mongoObject);
|
||||
}
|
||||
|
||||
var mongoObject = {
|
||||
_id: className,
|
||||
objectId: 'string',
|
||||
updatedAt: 'string',
|
||||
createdAt: 'string'
|
||||
};
|
||||
for (var fieldName in defaultColumns[className]) {
|
||||
var validatedField = schemaAPITypeToMongoFieldType(defaultColumns[className][fieldName]);
|
||||
if (validatedField.code) {
|
||||
return Promise.reject(validatedField);
|
||||
}
|
||||
mongoObject[fieldName] = validatedField.result;
|
||||
}
|
||||
|
||||
for (var fieldName in fields) {
|
||||
var validatedField = schemaAPITypeToMongoFieldType(fields[fieldName]);
|
||||
if (validatedField.code) {
|
||||
return Promise.reject(validatedField);
|
||||
}
|
||||
mongoObject[fieldName] = validatedField.result;
|
||||
}
|
||||
|
||||
var geoPoints = Object.keys(mongoObject).filter(key => mongoObject[key] === 'geopoint');
|
||||
if (geoPoints.length > 1) {
|
||||
return Promise.reject({
|
||||
code: Parse.Error.INCORRECT_TYPE,
|
||||
error: 'currently, only one GeoPoint field may exist in an object. Adding ' + geoPoints[1] + ' when ' + geoPoints[0] + ' already exists.',
|
||||
});
|
||||
}
|
||||
|
||||
return this.collection.insertOne(mongoObject)
|
||||
return this.collection.insertOne(mongoObject.result)
|
||||
.then(result => result.ops[0])
|
||||
.catch(error => {
|
||||
if (error.code === 11000) { //Mongo's duplicate key error
|
||||
@@ -651,4 +714,8 @@ function getObjectType(obj) {
|
||||
module.exports = {
|
||||
load: load,
|
||||
classNameIsValid: classNameIsValid,
|
||||
mongoSchemaFromFieldsAndClassName: mongoSchemaFromFieldsAndClassName,
|
||||
schemaAPITypeToMongoFieldType: schemaAPITypeToMongoFieldType,
|
||||
buildMergedSchemaObject: buildMergedSchemaObject,
|
||||
mongoFieldTypeToSchemaAPIType: mongoFieldTypeToSchemaAPIType,
|
||||
};
|
||||
|
||||
@@ -24,36 +24,10 @@ function classNameMismatchResponse(bodyClass, pathClass) {
|
||||
});
|
||||
}
|
||||
|
||||
function mongoFieldTypeToSchemaAPIType(type) {
|
||||
if (type[0] === '*') {
|
||||
return {
|
||||
type: 'Pointer',
|
||||
targetClass: type.slice(1),
|
||||
};
|
||||
}
|
||||
if (type.startsWith('relation<')) {
|
||||
return {
|
||||
type: 'Relation',
|
||||
targetClass: type.slice('relation<'.length, type.length - 1),
|
||||
};
|
||||
}
|
||||
switch (type) {
|
||||
case 'number': return {type: 'Number'};
|
||||
case 'string': return {type: 'String'};
|
||||
case 'boolean': return {type: 'Boolean'};
|
||||
case 'date': return {type: 'Date'};
|
||||
case 'map':
|
||||
case 'object': return {type: 'Object'};
|
||||
case 'array': return {type: 'Array'};
|
||||
case 'geopoint': return {type: 'GeoPoint'};
|
||||
case 'file': return {type: 'File'};
|
||||
}
|
||||
}
|
||||
|
||||
function mongoSchemaAPIResponseFields(schema) {
|
||||
var fieldNames = Object.keys(schema).filter(key => key !== '_id' && key !== '_metadata');
|
||||
var response = fieldNames.reduce((obj, fieldName) => {
|
||||
obj[fieldName] = mongoFieldTypeToSchemaAPIType(schema[fieldName])
|
||||
obj[fieldName] = Schema.mongoFieldTypeToSchemaAPIType(schema[fieldName])
|
||||
return obj;
|
||||
}, {});
|
||||
response.ACL = {type: 'ACL'};
|
||||
@@ -131,17 +105,15 @@ function modifySchema(req) {
|
||||
}
|
||||
|
||||
if (req.body.className && req.body.className != req.params.className) {
|
||||
return classNameMismatchResponse(req.body.className, req.path.className);
|
||||
return classNameMismatchResponse(req.body.className, req.params.className);
|
||||
}
|
||||
|
||||
if (!req.body.fields) {
|
||||
req.body.fields = {};
|
||||
}
|
||||
var submittedFields = req.body.fields || {};
|
||||
var className = req.params.className;
|
||||
|
||||
return req.config.database.loadSchema()
|
||||
.then(schema => schema.hasClass(req.params.className))
|
||||
.then(hasClass => {
|
||||
if (!hasClass) {
|
||||
.then(schema => {
|
||||
if (!schema.data[className]) {
|
||||
return Promise.resolve({
|
||||
status: 400,
|
||||
response: {
|
||||
@@ -150,6 +122,64 @@ function modifySchema(req) {
|
||||
}
|
||||
});
|
||||
}
|
||||
var existingFields = schema.data[className];
|
||||
|
||||
for (var submittedFieldName in submittedFields) {
|
||||
if (existingFields[submittedFieldName] && submittedFields[submittedFieldName].__op !== 'Delete') {
|
||||
return Promise.resolve({
|
||||
status: 400,
|
||||
response: {
|
||||
code: 255,
|
||||
error: 'field ' + submittedFieldName + ' exists, cannot update',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!existingFields[submittedFieldName] && submittedFields[submittedFieldName].__op === 'Delete') {
|
||||
return Promise.resolve({
|
||||
status: 400,
|
||||
response: {
|
||||
code: 255,
|
||||
error: 'field ' + submittedFieldName + ' does not exist, cannot delete',
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var newSchema = Schema.buildMergedSchemaObject(existingFields, submittedFields);
|
||||
var mongoObject = Schema.mongoSchemaFromFieldsAndClassName(newSchema, className);
|
||||
if (!mongoObject.result) {
|
||||
return Promise.resolve({
|
||||
status: 400,
|
||||
response: mongoObject,
|
||||
});
|
||||
}
|
||||
|
||||
// Finally we have checked to make sure the request is valid and we can start deleting fields.
|
||||
// Do all deletions first, then a single save to _SCHEMA collection to handle all additions.
|
||||
var deletionPromises = []
|
||||
Object.keys(submittedFields).forEach(submittedFieldName => {
|
||||
if (submittedFields[submittedFieldName].__op === 'Delete') {
|
||||
var promise = req.config.database.connect()
|
||||
.then(() => schema.deleteField(
|
||||
submittedFieldName,
|
||||
className,
|
||||
req.config.database.db,
|
||||
req.config.database.collectionPrefix
|
||||
));
|
||||
deletionPromises.push(promise);
|
||||
}
|
||||
});
|
||||
|
||||
return Promise.all(deletionPromises)
|
||||
.then(() => new Promise((resolve, reject) => {
|
||||
schema.collection.update({_id: className}, mongoObject.result, {w: 1}, (err, docs) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve({ response: mongoSchemaToSchemaAPIResponse(mongoObject.result)});
|
||||
})
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user