Move HooksController to use MongoCollection instead of direct Mongo access.

This commit is contained in:
Nikita Lutsenko
2016-03-04 18:43:19 -08:00
parent c6ae64bdbe
commit 172da3aaa3
2 changed files with 86 additions and 99 deletions

View File

@@ -1,4 +1,3 @@
let mongodb = require('mongodb'); let mongodb = require('mongodb');
let Collection = mongodb.Collection; let Collection = mongodb.Collection;
@@ -18,8 +17,7 @@ export default class MongoCollection {
return this._rawFind(query, { skip, limit, sort }) return this._rawFind(query, { skip, limit, sort })
.catch(error => { .catch(error => {
// Check for "no geoindex" error // Check for "no geoindex" error
if (error.code != 17007 || if (error.code != 17007 || !error.message.match(/unable to find index for .geoNear/)) {
!error.message.match(/unable to find index for .geoNear/)) {
throw error; throw error;
} }
// Figure out what key needs an index // Figure out what key needs an index
@@ -59,6 +57,13 @@ export default class MongoCollection {
}) })
} }
// Atomically updates data in the database for a single (first) object that matched the query
// If there is nothing that matches the query - does insert
// Postgres Note: `INSERT ... ON CONFLICT UPDATE` that is available since 9.5.
upsertOne(query, update) {
return this._mongoCollection.update(query, update, { upsert: true });
}
// Atomically find and delete an object based on query. // Atomically find and delete an object based on query.
// The result is the promise with an object that was in the database before deleting. // 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. // Postgres Note: Translates directly to `DELETE * FROM ... RETURNING *`, which will return data after delete is done.
@@ -70,6 +75,10 @@ export default class MongoCollection {
}); });
} }
remove(query) {
return this._mongoCollection.remove(query);
}
drop() { drop() {
return this._mongoCollection.drop(); return this._mongoCollection.drop();
} }

View File

@@ -17,80 +17,67 @@ export class HooksController {
this._collectionPrefix = collectionPrefix; this._collectionPrefix = collectionPrefix;
} }
database() { load() {
return DatabaseAdapter.getDatabaseConnection(this._applicationId, this._collectionPrefix); return this._getHooks().then(hooks => {
hooks = hooks || [];
hooks.forEach((hook) => {
this.addHookToTriggers(hook);
});
});
} }
collection() { getCollection() {
if (this._collection) { if (this._collection) {
return Promise.resolve(this._collection) return Promise.resolve(this._collection)
} }
return this.database().rawCollection(DefaultHooksCollectionName).then((collection) => {
let database = DatabaseAdapter.getDatabaseConnection(this._applicationId, this._collectionPrefix);
return database.adaptiveCollection(DefaultHooksCollectionName).then(collection => {
this._collection = collection; this._collection = collection;
return collection; return collection;
}); });
} }
getFunction(functionName) { getFunction(functionName) {
return this.getOne({functionName: functionName}) return this._getHooks({ functionName: functionName }, 1).then(results => results[0]);
} }
getFunctions() { getFunctions() {
return this.get({functionName: { $exists: true }}) return this._getHooks({ functionName: { $exists: true } });
} }
getTrigger(className, triggerName) { getTrigger(className, triggerName) {
return this.getOne({className: className, triggerName: triggerName }) return this._getHooks({ className: className, triggerName: triggerName }, 1).then(results => results[0]);
} }
getTriggers() { getTriggers() {
return this.get({className: { $exists: true }, triggerName: { $exists: true }}) return this._getHooks({ className: { $exists: true }, triggerName: { $exists: true } });
} }
deleteFunction(functionName) { deleteFunction(functionName) {
triggers.removeFunction(functionName, this._applicationId); triggers.removeFunction(functionName, this._applicationId);
return this.delete({functionName: functionName}); return this._removeHooks({ functionName: functionName });
} }
deleteTrigger(className, triggerName) { deleteTrigger(className, triggerName) {
triggers.removeTrigger(triggerName, className, this._applicationId); triggers.removeTrigger(triggerName, className, this._applicationId);
return this.delete({className: className, triggerName: triggerName}); return this._removeHooks({ className: className, triggerName: triggerName });
} }
delete(query) { _getHooks(query, limit) {
return this.collection().then((collection) => { let options = limit ? { limit: limit } : undefined;
return collection.remove(query) return this.getCollection().then(collection => collection.find(query, options));
}).then( (res) => { }
_removeHooks(query) {
return this.getCollection().then(collection => {
return collection.remove(query);
}).then(() => {
return {}; return {};
}, 1);
}
getOne(query) {
return this.collection()
.then(coll => coll.findOne(query, {_id: 0}))
.then(hook => {
return hook;
}); });
} }
get(query) {
return this.collection()
.then(coll => coll.find(query, {_id: 0}).toArray())
.then(hooks => {
return hooks;
});
}
getHooks() {
return this.collection()
.then(coll => coll.find({}, {_id: 0}).toArray())
.then(hooks => {
return hooks;
}, () => ([]))
}
saveHook(hook) { saveHook(hook) {
var query; var query;
if (hook.functionName && hook.url) { if (hook.functionName && hook.url) {
query = { functionName: hook.functionName } query = { functionName: hook.functionName }
@@ -99,11 +86,11 @@ export class HooksController {
} else { } else {
throw new Parse.Error(143, "invalid hook declaration"); throw new Parse.Error(143, "invalid hook declaration");
} }
return this.collection().then((collection) => { return this.getCollection()
return collection.update(query, hook, {upsert: true}) .then(collection => collection.upsertOne(query, hook))
}).then(function(res){ .then(() => {
return hook; return hook;
}) });
} }
addHookToTriggers(hook) { addHookToTriggers(hook) {
@@ -179,21 +166,11 @@ export class HooksController {
} }
throw new Parse.Error(143, "invalid hook declaration"); throw new Parse.Error(143, "invalid hook declaration");
}; };
load() {
return this.getHooks().then((hooks) => {
hooks = hooks || [];
hooks.forEach((hook) => {
this.addHookToTriggers(hook);
});
});
}
} }
function wrapToHTTPRequest(hook) { function wrapToHTTPRequest(hook) {
return function(req, res) { return (req, res) => {
var jsonBody = {}; let jsonBody = {};
for (var i in req) { for (var i in req) {
jsonBody[i] = req[i]; jsonBody[i] = req[i];
} }
@@ -205,11 +182,12 @@ function wrapToHTTPRequest(hook) {
jsonBody.original = req.original.toJSON(); jsonBody.original = req.original.toJSON();
jsonBody.original.className = req.original.className; jsonBody.original.className = req.original.className;
} }
var jsonRequest = {}; let jsonRequest = {
jsonRequest.headers = { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} },
jsonRequest.body = JSON.stringify(jsonBody); body: JSON.stringify(jsonBody)
};
request.post(hook.url, jsonRequest, function (err, httpResponse, body) { request.post(hook.url, jsonRequest, function (err, httpResponse, body) {
var result; var result;