Fixes issue affecting deleting multiple fields of a Schema (#3735)

This commit is contained in:
Paulo Vítor S Reis
2017-04-23 18:22:55 -03:00
committed by Florent Vilmart
parent 2a5c20376a
commit 5e14147676
3 changed files with 85 additions and 24 deletions

View File

@@ -13,7 +13,6 @@
// DatabaseController. This will let us replace the schema logic for
// different databases.
// TODO: hide all schema logic inside the database adapter.
const Parse = require('parse/node').Parse;
const defaultColumns = Object.freeze({
@@ -465,18 +464,22 @@ export default class SchemaController {
// 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.
const deletePromises = [];
const deletedFields = [];
const insertedFields = [];
Object.keys(submittedFields).forEach(fieldName => {
if (submittedFields[fieldName].__op === 'Delete') {
const promise = this.deleteField(fieldName, className, database);
deletePromises.push(promise);
deletedFields.push(fieldName);
} else {
insertedFields.push(fieldName);
}
});
return Promise.all(deletePromises) // Delete Everything
let deletePromise = Promise.resolve();
if (deletedFields.length > 0) {
deletePromise = this.deleteFields(deletedFields, className, database);
}
return deletePromise // Delete Everything
.then(() => this.reloadData({ clearCache: true })) // Reload our Schema, so we have all the new values
.then(() => {
const promises = insertedFields.map(fieldName => {
@@ -647,24 +650,32 @@ export default class SchemaController {
});
}
// Delete a field, and remove that data from all objects. This is intended
// maintain compatibility
deleteField(fieldName, className, database) {
return this.deleteFields([fieldName], className, database);
}
// Delete fields, and remove that data from all objects. This is intended
// to remove unused fields, if other writers are writing objects that include
// this field, the field may reappear. Returns a Promise that resolves with
// no object on success, or rejects with { code, error } on failure.
// Passing the database and prefix is necessary in order to drop relation collections
// and remove fields from objects. Ideally the database would belong to
// a database adapter and this function would close over it or access it via member.
deleteField(fieldName, className, database) {
deleteFields(fieldNames, className, database) {
if (!classNameIsValid(className)) {
throw new Parse.Error(Parse.Error.INVALID_CLASS_NAME, invalidClassNameMessage(className));
}
if (!fieldNameIsValid(fieldName)) {
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `invalid field name: ${fieldName}`);
}
//Don't allow deleting the default fields.
if (!fieldNameIsValidForClass(fieldName, className)) {
throw new Parse.Error(136, `field ${fieldName} cannot be changed`);
}
fieldNames.forEach(fieldName => {
if (!fieldNameIsValid(fieldName)) {
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `invalid field name: ${fieldName}`);
}
//Don't allow deleting the default fields.
if (!fieldNameIsValidForClass(fieldName, className)) {
throw new Parse.Error(136, `field ${fieldName} cannot be changed`);
}
});
return this.getOneSchema(className, false, {clearCache: true})
.catch(error => {
@@ -675,15 +686,24 @@ export default class SchemaController {
}
})
.then(schema => {
if (!schema.fields[fieldName]) {
throw new Parse.Error(255, `Field ${fieldName} does not exist, cannot delete.`);
}
if (schema.fields[fieldName].type == 'Relation') {
//For relations, drop the _Join table
return database.adapter.deleteFields(className, schema, [fieldName])
.then(() => database.adapter.deleteClass(`_Join:${fieldName}:${className}`));
}
return database.adapter.deleteFields(className, schema, [fieldName]);
fieldNames.forEach(fieldName => {
if (!schema.fields[fieldName]) {
throw new Parse.Error(255, `Field ${fieldName} does not exist, cannot delete.`);
}
});
const schemaFields = { ...schema.fields };
return database.adapter.deleteFields(className, schema, fieldNames)
.then(() => {
return Promise.all(fieldNames.map(fieldName => {
const field = schemaFields[fieldName];
if (field && field.type === 'Relation') {
//For relations, drop the _Join table
return database.adapter.deleteClass(`_Join:${fieldName}:${className}`);
}
return Promise.resolve();
}));
});
}).then(() => {
this._cache.clear();
});