Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve koa example #19

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
215 changes: 86 additions & 129 deletions todo-angular-koa/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ var koa = require('koa');
// Middleware and helpers
var serve = require('koa-static');
var parse = require('co-body');
var router = require('koa-router');
var http = require('http');
var Router = require('koa-router');
var logger = require('koa-logger');
var co = require('co');

// Import rethinkdb
var r = require('rethinkdb');
Expand All @@ -14,147 +15,103 @@ var config = require(__dirname+"/config.js");

var app = koa();

//
// MIDDLEWARE
//

// Static content
app.use(serve(__dirname+'/public'));

// Create a RethinkDB connection
app.use(createConnection);

app.use(router(app));
app.get('/todo/get', get);
app.put('/todo/new', create);
app.post('/todo/update', update);
app.post('/todo/delete', del);

// Close the RethinkDB connection
app.use(closeConnection);

/*
* Create a RethinkDB connection, and save it in req._rdbConn
*/
function* createConnection(next) {
try{
var conn = yield r.connect(config.rethinkdb);
this._rdbConn = conn;
}
catch(err) {
this.status = 500;
this.body = err.message || http.STATUS_CODES[this.status];
// Log requests
app.use(logger());

// Parse application/json bodies into this.request.body
app.use(function* (next) {
this.request.body = yield parse.json(this);
yield next;
});

// Create a RethinkDB connection, save it in the koa context, and ensure it closes
app.use(function* wrapConnection(next) {
this.state.conn = yield r.connect(config.rethinkdb);
// No matter what happens downstream, always close the connection
try {
yield next;
} finally {
this.state.conn.close();
}
yield next;
}
});

//
// ROUTES
//

var router = Router();

// Retrieve all todos
function* get(next) {
try{
var cursor = yield r.table('todos').orderBy({index: "createdAt"}).run(this._rdbConn);
var result = yield cursor.toArray();
this.body = JSON.stringify(result);
}
catch(e) {
this.status = 500;
this.body = e.message || http.STATUS_CODES[this.status];
}
yield next;
}
router.get('/todo/get', function* get(next) {
var cursor = yield r.table('todos').orderBy({index: "createdAt"}).run(this.state.conn);
var result = yield cursor.toArray();
this.body = result;
})

// Create a new todo
function* create(next) {
try{
var todo = yield parse(this);
todo.createdAt = r.now(); // Set the field `createdAt` to the current time
var result = yield r.table('todos').insert(todo, {returnChanges: true}).run(this._rdbConn);

todo = result.changes[0].new_val; // todo now contains the previous todo + a field `id` and `createdAt`
this.body = JSON.stringify(todo);
}
catch(e) {
this.status = 500;
this.body = e.message || http.STATUS_CODES[this.status];
}
yield next;
}
router.put('/todo/new', function* create(next) {
var todo = this.request.body;
todo.createdAt = r.now(); // Set the field `createdAt` to the current time
var result = yield r.table('todos').insert(todo, {returnChanges: true}).run(this.state.conn);

todo = result.changes[0].new_val; // todo now contains the previous todo + a field `id` and `createdAt`
this.body = todo;
});

// Update a todo
function* update(next) {
try{
var todo = yield parse(this);
delete todo._saving;
if ((todo == null) || (todo.id == null)) {
throw new Error("The todo must have a field `id`.");
}

var result = yield r.table('todos').get(todo.id).update(todo, {returnChanges: true}).run(this._rdbConn);
this.body = JSON.stringify(result.changes[0].new_val);
}
catch(e) {
this.status = 500;
this.body = e.message || http.STATUS_CODES[this.status];
}
yield next;
}
router.post('/todo/update', function* update(next) {
var todo = this.request.body;
this.assert(todo && todo.id, 400, 'todo must have field `id`');
delete todo._saving;
var result = yield r.table('todos').get(todo.id).update(todo, {returnChanges: true}).run(this.state.conn);
this.body = result.changes[0].new_val;
});

// Delete a todo
function* del(next) {
try{
var todo = yield parse(this);
if ((todo == null) || (todo.id == null)) {
throw new Error("The todo must have a field `id`.");
}
var result = yield r.table('todos').get(todo.id).delete().run(this._rdbConn);
this.body = "";
}
catch(e) {
this.status = 500;
this.body = e.message || http.STATUS_CODES[this.status];
}
yield next;
}

/*
* Close the RethinkDB connection
*/
function* closeConnection(next) {
this._rdbConn.close();
}

r.connect(config.rethinkdb, function(err, conn) {
if (err) {
console.log("Could not open a connection to initialize the database");
console.log(err.message);
process.exit(1);
}
router.post('/todo/delete', function* del(next) {
var todo = this.request.body;
this.assert(todo && todo.id, 400, 'todo must have field `id`');
var result = yield r.table('todos').get(todo.id).delete().run(this.state.conn);
this.body = '';
});

r.table('todos').indexWait('createdAt').run(conn).then(function(err, result) {
// Mount our router
app.use(router.routes());

// Setup database and launch the koa server
var conn;
co(function* () {
try {
conn = yield r.connect(config.rethinkdb);
} catch(err) {
console.error("Could not open a connection to initialize the database");
throw err;
}
try {
yield r.table('todos').indexWait('createdAt').run(conn);
console.log("Table and index are available, starting koa...");
startKoa();
}).error(function(err) {
} catch(err) {
// The database/table/index was not available, create them
r.dbCreate(config.rethinkdb.db).run(conn).finally(function() {
return r.tableCreate('todos').run(conn)
}).finally(function() {
r.table('todos').indexCreate('createdAt').run(conn);
}).finally(function(result) {
r.table('todos').indexWait('createdAt').run(conn)
}).then(function(result) {
console.log("Table and index are available, starting koa...");
startKoa();
conn.close();
}).error(function(err) {
if (err) {
console.log("Could not wait for the completion of the index `todos`");
console.log(err);
process.exit(1);
}
console.log("Table and index are available, starting koa...");
startKoa();
conn.close();
});
yield r.dbCreate(config.rethinkdb.db).run(conn);
yield r.tableCreate('todos').run(conn);
yield r.table('todos').indexCreate('createdAt').run(conn);
yield r.table('todos').indexWait('createdAt').run(conn)
console.log("Table and index are available, starting koa...");
}
}).then(function () {
conn.close();
app.listen(config.koa.port, function() {
console.log('Listening on port', config.koa.port);
});
}).catch(function (err) {
conn.close();
console.error(err);
process.exit(1);
});


function startKoa() {
app.listen(config.koa.port);
console.log('Listening on port '+config.koa.port);
}
23 changes: 11 additions & 12 deletions todo-angular-koa/package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
{
"name": "todo"
, "version": "0.0.2"
, "private": true
, "dependencies": {
"koa": "0.6.0"
, "koa-static": "1.4.2"
, "koa-router": "3.1.4"
, "co-body": "0.0.1"
, "co": "3.0.2"
, "body-parser": "1.0.2"
, "rethinkdb": ">=2.1.1"
, "co-assert-timeout": "0.0.4"
"name": "todo",
"version": "0.0.2",
"private": true,
"dependencies": {
"co": "4.6.0",
"co-body": "4.2.0",
"koa": "1.2.0",
"koa-logger": "^1.3.0",
"koa-router": "5.3.0",
"koa-static": "1.4.2",
"rethinkdb": ">=2.1.1"
}
}
2 changes: 1 addition & 1 deletion todo-angular-koa/public/js/controllers/todoCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ todomvc.controller('TodoCtrl', function TodoCtrl($scope, $routeParams, todoStora
};

$scope.clearCompletedTodos = function () {
$scope.todos = todos.filter(function (val) {
$scope.todos = $scope.todos.filter(function (val) {
return !val.completed;
});
};
Expand Down