Skip to content
Browse files

Implement survey slugs

Make sure we index the slugs, since we'll use those for lookup purposes.
Also make sure every survey has a slug.
  • Loading branch information...
1 parent 47db8b4 commit 0bac316e6abec86862cadecbdc1a93cfa3073133 @prashtx prashtx committed Aug 18, 2012
Showing with 142 additions and 15 deletions.
  1. +1 −0 package.json
  2. +67 −10 surveys.js
  3. +74 −5 web.js
View
1 package.json
@@ -11,6 +11,7 @@
, "knox" : "https://github.com/slaskis/knox/tarball/master"
, "pg" : "0.6.x"
, "connect-s3" : "git://github.com/prashtx/connect-s3.git"
+ , "slug" : "0.2.x"
}
, "devDependencies": {
"mocha" : "https://github.com/visionmedia/mocha/tarball/master"
View
77 surveys.js
@@ -8,8 +8,29 @@
*/
var util = require('./util');
+var makeSlug = require('slug');
+function checkSlug(collection, name, index, done) {
+ var slug = makeSlug(name);
+ if (index > 0) {
+ slug = slug + '-' + index;
+ }
+
+ // See if we've already used this slug.
+ collection.find({ slug: slug }, function (err, cursor) {
+ if (err) { return done(err); }
+ cursor.count(function (err, count) {
+ if (err) { return done(err); }
+ if (count > 0) {
+ checkSlug(collection, name, index + 1, done);
+ } else {
+ done(null, slug);
+ }
+ });
+ });
+}
+
/*
* app: express server
* db: mongodb database
@@ -63,27 +84,62 @@ function setup(app, db, idgen, collectionName) {
});
});
+ // Get the survey ID associated with a slug
+ // GET http://localhost:3000/api/slugs/{SLUG}
+ app.get('/api/slugs/:slug', function (req, response) {
+ var handleError = util.makeErrorHandler(response);
+ getCollection(function (err, collection) {
+ if (handleError(err)) { return; }
+ collection.find({slug: req.params.slug}, function (err, cursor) {
+ if (handleError(err)) { return; }
+ cursor.toArray(function (err, items) {
+ if (handleError(err)) { return; }
+ if (items.length === 0) {
+ response.send(404);
+ return;
+ }
+
+ if (items.length > 1) {
+ console.log('!!! WARNING: There should only be one item with a given slug');
+ console.log('!!! Found ' + items.length);
+ console.log('!!! Items: ' + JSON.stringify(items));
+ }
+ response.send({
+ survey: items[0].id
+ });
+ });
+ });
+ });
+ });
+
// Add a survey
// POST http://localhost:3000/api/surveys
app.post('/api/surveys', function(req, response) {
var handleError = util.makeErrorHandler(response);
var surveys = req.body.surveys;
var total = surveys.length;
var count = 0;
+
getCollection(function(err, collection) {
+
// Iterate over each survey
surveys.forEach(function(survey) {
var id = idgen();
survey.id = id;
- // Add to database.
- collection.insert(survey, function(error) {
- if (handleError(error)) { return; }
-
- // Check if we've added all of them.
- count += 1;
- if (count === total) {
- response.send({surveys: surveys}, 201);
- }
+
+ checkSlug(collection, survey.name, 0, function (err, slug) {
+ if (handleError(err)) { return; }
+ survey.slug = slug;
+ // Add to database.
+ collection.insert(survey, function(error) {
+ if (handleError(error)) { return; }
+
+ // Check if we've added all of them.
+ count += 1;
+ if (count === total) {
+ response.send({surveys: surveys}, 201);
+ }
+ });
});
});
});
@@ -114,5 +170,6 @@ function setup(app, db, idgen, collectionName) {
}
module.exports = {
- setup: setup
+ setup: setup,
+ checkSlug: checkSlug
};
View
79 web.js
@@ -186,12 +186,81 @@ function setupRoutes(db, settings) {
// Ensure certain database structure.
function ensureStructure(db, callback) {
- db.collection(RESPONSES, function (error, collection) {
- if (error) { throw error; }
- collection.ensureIndex({'geo_info.centroid': '2d'}, function (error) {
- callback(error);
+ // Map f(callback) to f(error, callback)
+ function upgrade(g) {
+ return function (err, done) {
+ if (err) { callback(err); }
+ g(done);
+ };
+ }
+
+ // Chain async function calls
+ function chain (arr) {
+ return arr.reduce(function (memo, f, index) {
+ return function (err) {
+ upgrade(f)(err, memo);
+ };
+ }, function (e) { callback(e); });
+ }
+
+ function ensureResponses(done) {
+ db.collection(RESPONSES, function (error, collection) {
+ if (error) { throw error; }
+ // Ensure we have a geo index on the centroid field.
+ collection.ensureIndex({'geo_info.centroid': '2d'}, function (error) {
+ done(error);
+ });
});
- });
+ }
+
+ function ensureSurveys(done) {
+ db.collection(SURVEYS, function (error, collection) {
+ if (error) { throw error; }
+ // Index the slug field.
+ collection.ensureIndex('slug', function (error, index) {
+ if (error) { return done(error); }
+ // Index the survey ID.
+ collection.ensureIndex('id', function (error, index) {
+ done(error);
+ });
+ });
+ });
+ }
+
+ function ensureSlugs(done) {
+ db.collection(SURVEYS, function (error, collection) {
+ // Look for surveys with no slug
+ collection.find({}, function(err, cursor) {
+ cursor.toArray(function (err, arr) {
+ if (err) { return done(err); }
+ var count = 0;
+ arr.forEach(function (item) {
+ if (item.slug === undefined) {
+ // Add a slug
+ surveys.checkSlug(collection, item.name, 0, function (err, slug) {
+ if (err) { return done(err); }
+ // Update entry
+ collection.update({_id: item._id}, {'$set': {slug: slug}}, function (error) {
+ if (err) { return done(err); }
+ count += 1;
+ if (count === arr.length) {
+ done();
+ }
+ });
+ });
+ } else {
+ count += 1;
+ if (count === arr.length) {
+ done();
+ }
+ }
+ });
+ });
+ });
+ });
+ }
+
+ chain([ensureSlugs, ensureSurveys, ensureResponses])();
}
function startServer(port, cb) {

0 comments on commit 0bac316

Please sign in to comment.
Something went wrong with that request. Please try again.