Merge pull request #759 from ParsePlatform/nlutsenko.storage.findAndDoMagic
Add findOneAndDelete, findOneAndModify to MongoCollection, move most of usages to it.
This commit is contained in:
@@ -47,6 +47,29 @@ export default class MongoCollection {
|
|||||||
return this._mongoCollection.count(query, { skip, limit, sort });
|
return this._mongoCollection.count(query, { skip, limit, sort });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Atomically finds and updates an object based on query.
|
||||||
|
// The result is the promise with an object that was in the database !AFTER! changes.
|
||||||
|
// Postgres Note: Translates directly to `UPDATE * SET * ... RETURNING *`, which will return data after the change is done.
|
||||||
|
findOneAndUpdate(query, update) {
|
||||||
|
// arguments: query, sort, update, options(optional)
|
||||||
|
// Setting `new` option to true makes it return the after document, not the before one.
|
||||||
|
return this._mongoCollection.findAndModify(query, [], update, { new: true }).then(document => {
|
||||||
|
// Value is the object where mongo returns multiple fields.
|
||||||
|
return document.value;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Atomically find and delete an object based on query.
|
||||||
|
// The result is the promise with an object that was in the database before deleting.
|
||||||
|
// Postgres Note: Translates directly to `DELETE * FROM ... RETURNING *`, which will return data after delete is done.
|
||||||
|
findOneAndDelete(query) {
|
||||||
|
// arguments: query, sort
|
||||||
|
return this._mongoCollection.findAndRemove(query, []).then(document => {
|
||||||
|
// Value is the object where mongo returns multiple fields.
|
||||||
|
return document.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
drop() {
|
drop() {
|
||||||
return this._mongoCollection.drop();
|
return this._mongoCollection.drop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,51 +142,45 @@ DatabaseController.prototype.update = function(className, query, update, options
|
|||||||
var isMaster = !('acl' in options);
|
var isMaster = !('acl' in options);
|
||||||
var aclGroup = options.acl || [];
|
var aclGroup = options.acl || [];
|
||||||
var mongoUpdate, schema;
|
var mongoUpdate, schema;
|
||||||
return this.loadSchema(acceptor).then((s) => {
|
return this.loadSchema(acceptor)
|
||||||
schema = s;
|
.then(s => {
|
||||||
if (!isMaster) {
|
schema = s;
|
||||||
return schema.validatePermission(className, aclGroup, 'update');
|
if (!isMaster) {
|
||||||
}
|
return schema.validatePermission(className, aclGroup, 'update');
|
||||||
return Promise.resolve();
|
|
||||||
}).then(() => {
|
|
||||||
|
|
||||||
return this.handleRelationUpdates(className, query.objectId, update);
|
|
||||||
}).then(() => {
|
|
||||||
return this.collection(className);
|
|
||||||
}).then((coll) => {
|
|
||||||
var mongoWhere = transform.transformWhere(schema, className, query);
|
|
||||||
if (options.acl) {
|
|
||||||
var writePerms = [
|
|
||||||
{_wperm: {'$exists': false}}
|
|
||||||
];
|
|
||||||
for (var entry of options.acl) {
|
|
||||||
writePerms.push({_wperm: {'$in': [entry]}});
|
|
||||||
}
|
}
|
||||||
mongoWhere = {'$and': [mongoWhere, {'$or': writePerms}]};
|
return Promise.resolve();
|
||||||
}
|
})
|
||||||
|
.then(() => this.handleRelationUpdates(className, query.objectId, update))
|
||||||
mongoUpdate = transform.transformUpdate(schema, className, update);
|
.then(() => this.adaptiveCollection(className))
|
||||||
|
.then(collection => {
|
||||||
return coll.findAndModify(mongoWhere, {}, mongoUpdate, {});
|
var mongoWhere = transform.transformWhere(schema, className, query);
|
||||||
}).then((result) => {
|
if (options.acl) {
|
||||||
if (!result.value) {
|
var writePerms = [
|
||||||
return Promise.reject(new Parse.Error(Parse.Error.OBJECT_NOT_FOUND,
|
{_wperm: {'$exists': false}}
|
||||||
'Object not found.'));
|
];
|
||||||
}
|
for (var entry of options.acl) {
|
||||||
if (result.lastErrorObject.n != 1) {
|
writePerms.push({_wperm: {'$in': [entry]}});
|
||||||
return Promise.reject(new Parse.Error(Parse.Error.OBJECT_NOT_FOUND,
|
}
|
||||||
'Object not found.'));
|
mongoWhere = {'$and': [mongoWhere, {'$or': writePerms}]};
|
||||||
}
|
|
||||||
|
|
||||||
var response = {};
|
|
||||||
var inc = mongoUpdate['$inc'];
|
|
||||||
if (inc) {
|
|
||||||
for (var key in inc) {
|
|
||||||
response[key] = (result.value[key] || 0) + inc[key];
|
|
||||||
}
|
}
|
||||||
}
|
mongoUpdate = transform.transformUpdate(schema, className, update);
|
||||||
return response;
|
return collection.findOneAndUpdate(mongoWhere, mongoUpdate);
|
||||||
});
|
})
|
||||||
|
.then(result => {
|
||||||
|
if (!result) {
|
||||||
|
return Promise.reject(new Parse.Error(Parse.Error.OBJECT_NOT_FOUND,
|
||||||
|
'Object not found.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = {};
|
||||||
|
let inc = mongoUpdate['$inc'];
|
||||||
|
if (inc) {
|
||||||
|
Object.keys(inc).forEach(key => {
|
||||||
|
response[key] = result[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Processes relation-updating operations from a REST-format update.
|
// Processes relation-updating operations from a REST-format update.
|
||||||
|
|||||||
@@ -40,49 +40,43 @@ export class UserController extends AdaptableController {
|
|||||||
|
|
||||||
|
|
||||||
verifyEmail(username, token) {
|
verifyEmail(username, token) {
|
||||||
|
if (!this.shouldVerifyEmails) {
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
|
|
||||||
// Trying to verify email when not enabled
|
// Trying to verify email when not enabled
|
||||||
if (!this.shouldVerifyEmails) {
|
// TODO: Better error here.
|
||||||
reject();
|
return Promise.reject();
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
return this.config.database
|
||||||
var database = this.config.database;
|
.adaptiveCollection('_User')
|
||||||
|
.then(collection => {
|
||||||
database.collection('_User').then(coll => {
|
|
||||||
// Need direct database access because verification token is not a parse field
|
// Need direct database access because verification token is not a parse field
|
||||||
return coll.findAndModify({
|
return collection.findOneAndUpdate({
|
||||||
username: username,
|
username: username,
|
||||||
_email_verify_token: token,
|
_email_verify_token: token
|
||||||
}, null, {$set: {emailVerified: true}}, (err, doc) => {
|
}, {$set: {emailVerified: true}});
|
||||||
if (err || !doc.value) {
|
})
|
||||||
reject(err);
|
.then(document => {
|
||||||
} else {
|
if (!document) {
|
||||||
resolve(doc.value);
|
return Promise.reject();
|
||||||
}
|
}
|
||||||
});
|
return document;
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checkResetTokenValidity(username, token) {
|
checkResetTokenValidity(username, token) {
|
||||||
return new Promise((resolve, reject) => {
|
return this.config.database.adaptiveCollection('_User')
|
||||||
return this.config.database.collection('_User').then(coll => {
|
.then(collection => {
|
||||||
return coll.findOne({
|
return collection.find({
|
||||||
username: username,
|
username: username,
|
||||||
_perishable_token: token,
|
_perishable_token: token
|
||||||
}, (err, doc) => {
|
}, { limit: 1 });
|
||||||
if (err || !doc) {
|
})
|
||||||
reject(err);
|
.then(results => {
|
||||||
} else {
|
if (results.length != 1) {
|
||||||
resolve(doc);
|
return Promise.reject();
|
||||||
}
|
}
|
||||||
});
|
return results[0];
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getUserIfNeeded(user) {
|
getUserIfNeeded(user) {
|
||||||
@@ -130,24 +124,16 @@ export class UserController extends AdaptableController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setPasswordResetToken(email) {
|
setPasswordResetToken(email) {
|
||||||
var database = this.config.database;
|
let token = randomString(25);
|
||||||
var token = randomString(25);
|
return this.config.database
|
||||||
return new Promise((resolve, reject) => {
|
.adaptiveCollection('_User')
|
||||||
return database.collection('_User').then(coll => {
|
.then(collection => {
|
||||||
// Need direct database access because verification token is not a parse field
|
// Need direct database access because verification token is not a parse field
|
||||||
return coll.findAndModify({
|
return collection.findOneAndUpdate(
|
||||||
email: email,
|
{ email: email}, // query
|
||||||
}, null, {$set: {_perishable_token: token}}, (err, doc) => {
|
{ $set: { _perishable_token: token } } // update
|
||||||
if (err || !doc.value) {
|
);
|
||||||
console.error(err);
|
|
||||||
reject(err);
|
|
||||||
} else {
|
|
||||||
doc.value._perishable_token = token;
|
|
||||||
resolve(doc.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPasswordResetEmail(email) {
|
sendPasswordResetEmail(email) {
|
||||||
|
|||||||
@@ -164,14 +164,14 @@ function deleteSchema(req) {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
// We've dropped the collection now, so delete the item from _SCHEMA
|
// We've dropped the collection now, so delete the item from _SCHEMA
|
||||||
// and clear the _Join collections
|
// and clear the _Join collections
|
||||||
return req.config.database.collection('_SCHEMA')
|
return req.config.database.adaptiveCollection('_SCHEMA')
|
||||||
.then(coll => coll.findAndRemove({_id: req.params.className}, []))
|
.then(coll => coll.findOneAndDelete({_id: req.params.className}))
|
||||||
.then(doc => {
|
.then(document => {
|
||||||
if (doc.value === null) {
|
if (document === null) {
|
||||||
//tried to delete non-existent class
|
//tried to delete non-existent class
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
return removeJoinTables(req.config.database, doc.value);
|
return removeJoinTables(req.config.database, document);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user