Skip to content

Commit 234d009

Browse files
drew-grossflovilmart
authored andcommitted
Cleanup delete schema (#1604)
* Some cleanup for deleting one schema * tidyness * Remove _allCollections as Parse Server doesn't need it.
1 parent d14d451 commit 234d009

File tree

4 files changed

+52
-51
lines changed

4 files changed

+52
-51
lines changed

src/Adapters/Storage/Mongo/MongoStorageAdapter.js

+23-13
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,21 @@ let MongoClient = mongodb.MongoClient;
1010
const MongoSchemaCollectionName = '_SCHEMA';
1111
const DefaultMongoURI = 'mongodb://localhost:27017/parse';
1212

13+
const storageAdapterAllCollections = mongoAdapter => {
14+
return mongoAdapter.connect()
15+
.then(() => mongoAdapter.database.collections())
16+
.then(collections => {
17+
return collections.filter(collection => {
18+
if (collection.namespace.match(/\.system\./)) {
19+
return false;
20+
}
21+
// TODO: If you have one app with a collection prefix that happens to be a prefix of another
22+
// apps prefix, this will go very very badly. We should fix that somehow.
23+
return (collection.collectionName.indexOf(mongoAdapter._collectionPrefix) == 0);
24+
});
25+
});
26+
}
27+
1328
export class MongoStorageAdapter {
1429
// Private
1530
_uri: string;
@@ -70,7 +85,10 @@ export class MongoStorageAdapter {
7085
});
7186
}
7287

73-
dropCollection(className: string) {
88+
// Deletes a schema. Resolve if successful. If the schema doesn't
89+
// exist, resolve with undefined. If schema exists, but can't be deleted for some other reason,
90+
// reject with INTERNAL_SERVER_ERROR.
91+
deleteOneSchema(className: string) {
7492
return this.collection(this._collectionPrefix + className).then(collection => collection.drop())
7593
.catch(error => {
7694
// 'ns not found' means collection was already gone. Ignore deletion attempt.
@@ -81,18 +99,10 @@ export class MongoStorageAdapter {
8199
});
82100
}
83101

84-
// Used for testing only right now.
85-
allCollections() {
86-
return this.connect().then(() => {
87-
return this.database.collections();
88-
}).then(collections => {
89-
return collections.filter(collection => {
90-
if (collection.namespace.match(/\.system\./)) {
91-
return false;
92-
}
93-
return (collection.collectionName.indexOf(this._collectionPrefix) == 0);
94-
});
95-
});
102+
// Delete all data known to this adatper. Used for testing.
103+
deleteAllSchemas() {
104+
return storageAdapterAllCollections(this)
105+
.then(collections => Promise.all(collections.map(collection => collection.drop())));
96106
}
97107

98108
// Remove the column and all the data. For Relations, the _Join collection is handled

src/Controllers/DatabaseController.js

+12-18
Original file line numberDiff line numberDiff line change
@@ -381,11 +381,7 @@ DatabaseController.prototype.mongoFind = function(className, query, options = {}
381381
// Returns a promise.
382382
DatabaseController.prototype.deleteEverything = function() {
383383
this.schemaPromise = null;
384-
385-
return this.adapter.allCollections().then(collections => {
386-
let promises = collections.map(collection => collection.drop());
387-
return Promise.all(promises);
388-
});
384+
return this.adapter.deleteAllSchemas();
389385
};
390386

391387
// Finds the keys in a query. Returns a Set. REST format only
@@ -652,21 +648,19 @@ DatabaseController.prototype.find = function(className, query, {
652648

653649
DatabaseController.prototype.deleteSchema = function(className) {
654650
return this.collectionExists(className)
655-
.then(exist => {
656-
if (!exist) {
657-
return Promise.resolve();
651+
.then(exist => {
652+
if (!exist) {
653+
return Promise.resolve();
654+
}
655+
return this.adapter.adaptiveCollection(className)
656+
.then(collection => collection.count())
657+
.then(count => {
658+
if (count > 0) {
659+
throw new Parse.Error(255, `Class ${className} is not empty, contains ${count} objects, cannot drop schema.`);
658660
}
659-
return this.adapter.adaptiveCollection(className)
660-
.then(collection => {
661-
return collection.count()
662-
.then(count => {
663-
if (count > 0) {
664-
throw new Parse.Error(255, `Class ${className} is not empty, contains ${count} objects, cannot drop schema.`);
665-
}
666-
return collection.drop();
667-
})
668-
})
661+
return this.adapter.deleteOneSchema(className);
669662
})
663+
});
670664
}
671665

672666
DatabaseController.prototype.addPointerPermissions = function(schema, className, operation, query, aclGroup = []) {

src/Controllers/SchemaController.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ function validateCLP(perms, fields) {
134134
}
135135
return;
136136
}
137-
137+
138138
Object.keys(perms[operation]).forEach((key) => {
139139
verifyPermissionKey(key);
140140
let perm = perms[operation][key];
@@ -543,7 +543,7 @@ class SchemaController {
543543
if (this.data[className][fieldName].type == 'Relation') {
544544
//For relations, drop the _Join table
545545
return database.adapter.deleteFields(className, [fieldName], [])
546-
.then(() => database.adapter.dropCollection(`_Join:${fieldName}:${className}`));
546+
.then(() => database.adapter.deleteOneSchema(`_Join:${fieldName}:${className}`));
547547
}
548548

549549
const fieldNames = [fieldName];
@@ -632,15 +632,15 @@ class SchemaController {
632632
found = true;
633633
}
634634
}
635-
635+
636636
if (found) {
637637
return Promise.resolve();
638638
}
639639

640640
// No matching CLP, let's check the Pointer permissions
641641
// And handle those later
642642
let permissionField = ['get', 'find'].indexOf(operation) > -1 ? 'readUserFields' : 'writeUserFields';
643-
643+
644644
// Reject create when write lockdown
645645
if (permissionField == 'writeUserFields' && operation == 'create') {
646646
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN,

src/Routers/SchemasRouter.js

+13-16
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ var removeJoinTables = (database, mongoSchema) => {
7070
.filter(field => mongoSchema[field].startsWith('relation<'))
7171
.map(field => {
7272
let collectionName = `_Join:${field}:${mongoSchema._id}`;
73-
return database.adapter.dropCollection(collectionName);
73+
return database.adapter.deleteOneSchema(collectionName);
7474
})
7575
);
7676
};
@@ -79,22 +79,19 @@ function deleteSchema(req) {
7979
if (!SchemaController.classNameIsValid(req.params.className)) {
8080
throw new Parse.Error(Parse.Error.INVALID_CLASS_NAME, SchemaController.invalidClassNameMessage(req.params.className));
8181
}
82-
8382
return req.config.database.deleteSchema(req.params.className)
84-
.then(() => {
85-
// We've dropped the collection now, so delete the item from _SCHEMA
86-
// and clear the _Join collections
87-
return req.config.database.schemaCollection()
88-
.then(coll => coll.findAndDeleteSchema(req.params.className))
89-
.then(document => {
90-
if (document === null) {
91-
//tried to delete non-existent class
92-
return Promise.resolve();
93-
}
94-
return removeJoinTables(req.config.database, document);
95-
});
96-
})
97-
.then(() => ({ response: {} }));
83+
.then(() => req.config.database.schemaCollection())
84+
// We've dropped the collection now, so delete the item from _SCHEMA
85+
// and clear the _Join collections
86+
.then(coll => coll.findAndDeleteSchema(req.params.className))
87+
.then(document => {
88+
if (document === null) {
89+
//tried to delete non-existent class
90+
return Promise.resolve();
91+
}
92+
return removeJoinTables(req.config.database, document);
93+
})
94+
.then(() => ({ response: {} }));
9895
}
9996

10097
export class SchemasRouter extends PromiseRouter {

0 commit comments

Comments
 (0)