Skip to content
This repository has been archived by the owner on Dec 1, 2017. It is now read-only.

Commit

Permalink
Delete child models when parent is removed. Add JSHint configuration …
Browse files Browse the repository at this point in the history
…files. Update tests.
  • Loading branch information
Karthik Viswanathan committed Jun 27, 2012
1 parent a5c40de commit febc74e
Show file tree
Hide file tree
Showing 11 changed files with 235 additions and 56 deletions.
1 change: 1 addition & 0 deletions .jshintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
6 changes: 6 additions & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"node": true,
"strict": false,
"es5": true,
"esnext": true
}
14 changes: 3 additions & 11 deletions lib/components.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
/*globals exports:true*/
const ALLOWED_FIELDS = {
layout: undefined,
action: undefined
};

var scaffold = require('./scaffold');

/* Get Components Key
* Requires: web request
* Returns: database key for components hash
*/
function getComponentsKey(req) {
return req.session.email + ':project:' + req.params.project_id + 'screen:' +
req.params.screen_id + ':components';
}

/* Get Default Component
* Requires: web request
* Returns: default component data
Expand All @@ -26,5 +18,5 @@ function getDefaultComponent(req) {
};
}

exports = module.exports = scaffold.generate(getComponentsKey,
getDefaultComponent, ALLOWED_FIELDS);
exports = module.exports = scaffold.generate(['projects', 'screens'],
['elements'], 'components', getDefaultComponent, ALLOWED_FIELDS);
4 changes: 2 additions & 2 deletions lib/crud.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ var utils = require('./utils');
* error - null if object list was retrieved or an error otherwise
* objectList - if error is null, the list of objects
*/
exports.list = function(key, allowedFields, db, callback) {
exports.list = function(key, db, callback) {
db.hvals(key, function(err, objectList) {
if (err) {
callback(err);
Expand Down Expand Up @@ -55,7 +55,7 @@ exports.add = function(req, key, defaultValues, db, callback) {
callback(err);
} else {
var object = defaultValues;
object.id = length + 1;
object.id = length + 1; // ids are 1-indexed

var value = JSON.stringify(object);
db.hset(key, String(object.id), value, function(err, status) {
Expand Down
14 changes: 3 additions & 11 deletions lib/elements.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*globals exports:true*/
const ALLOWED_FIELDS = {
title: undefined,
identifier: undefined,
Expand All @@ -8,15 +9,6 @@ const ALLOWED_FIELDS = {

var scaffold = require('./scaffold');

/* Get Elements Key
* Requires: web request
* Returns: database key for elements hash
*/
function getElementsKey(req) {
return req.session.email + ':project:' + req.params.project_id + ':screen:' +
req.params.screen_id + ':component:' + req.params.component_id + ':elements';
}

/* Get Default Element
* Requires: web request
* Returns: default element data
Expand All @@ -31,5 +23,5 @@ function getDefaultElement(req) {
};
}

exports = module.exports = scaffold.generate(getElementsKey,
getDefaultElement, ALLOWED_FIELDS);
exports = module.exports = scaffold.generate(['projects', 'screens',
'components'], [], 'elements', getDefaultElement, ALLOWED_FIELDS);
13 changes: 3 additions & 10 deletions lib/projects.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
/*globals exports:true*/
const ALLOWED_FIELDS = {
title: undefined,
author: undefined
};

var scaffold = require('./scaffold');

/* Get Projects Key
* Requires: web request
* Returns: database key for project hash
*/
function getProjectsKey(req) {
return req.session.email + ':projects';
}

/* Get Default Project
* Requires: web request
* Returns: default project data
Expand All @@ -34,5 +27,5 @@ function getDefaultProject(req) {
* can continue to use `exports.someProperty = someValue;` and have
* someProperty exported by node.
*/
exports = module.exports = scaffold.generate(getProjectsKey,
getDefaultProject, ALLOWED_FIELDS);
exports = module.exports = scaffold.generate([], ['screens'],
'projects', getDefaultProject, ALLOWED_FIELDS);
110 changes: 99 additions & 11 deletions lib/scaffold.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ var utils = require('./utils');
/* Generate a CRUD scaffold for an object
*
* Requires:
* getKey - function(req) which returns a key to the object's hash based on
* a request
* parents - the scaffolds that are parents of this scaffold
* i.e. ['projects', 'screens']
* children - the scaffolds that are direct children of this scaffold
* i.e. ['elements']
* name - the name of this scaffold
* i.e. 'components'
* getDefault - function(req) which returns a default object based on
* a request
* allowedFields - fields that are allowed to be modified in the form of
Expand All @@ -18,18 +22,37 @@ var utils = require('./utils');
* update(req, db, identifier, callback) - update an object
* remove(req, db, identifier, callback) - remove an object
*/
exports.generate = function(getKey, getDefault, allowedFields) {
exports.generate = function(parents, children, name, getDefault, allowedFields) {
var scaffold = {};

/* Get Hash Key
* Requires: web request
* Returns: database key for objects hash
*/
function getHashKey(req) {
var key = req.session.email + ':';

var parentKeys = parents.map(function(parentName) {
var singularName = parentName.substring(0, parentName.length - 1);
return singularName + ':' + req.params[singularName + '_id'];
});

if (parentKeys.length > 0) {
parentKeys[parentKeys.length - 1] += ':';
}

return key + parentKeys.join(':') + name;
}

/* Object List
* Requires: web request, db connection, callback
* Calls: callback(error, objectList):
* error - null if object list was retrieved or an error otherwise
* objectList - if error is null, the list of objects
*/
scaffold.list = function(req, db, callback) {
var key = getKey(req);
crud.list(key, allowedFields, db, function(err, objectList) {
var key = getHashKey(req);
crud.list(key, db, function(err, objectList) {
if (err) {
callback(err);
} else {
Expand All @@ -45,7 +68,7 @@ exports.generate = function(getKey, getDefault, allowedFields) {
* object - if error is null, the object
*/
scaffold.get = function(req, db, id, callback) {
var key = getKey(req);
var key = getHashKey(req);
crud.get(key, id, db, function(err, object) {
if (err) {
callback(err);
Expand All @@ -63,7 +86,7 @@ exports.generate = function(getKey, getDefault, allowedFields) {
*/
scaffold.add = function(req, db, callback) {
var defaultValues = getDefault(req);
var key = getKey(req);
var key = getHashKey(req);

callback = callback || utils.noop;
crud.add(req, key, defaultValues, db, function(err, object) {
Expand All @@ -82,7 +105,7 @@ exports.generate = function(getKey, getDefault, allowedFields) {
* object - if error is null, the object that was updated
*/
scaffold.update = function(req, db, id, callback) {
var key = getKey(req);
var key = getHashKey(req);
callback = callback || utils.noop;

crud.update(req, key, id, allowedFields, db,
Expand All @@ -101,11 +124,76 @@ exports.generate = function(getKey, getDefault, allowedFields) {
* error - null if the object was removed or an error otherwise
*/
scaffold.remove = function(req, db, id, callback) {
var key = getKey(req);
var key = getHashKey(req);
callback = callback || utils.noop;
id = String(id);

// set up the request to remove child scaffolds
var childReq = req;
var singularName = name.substring(0, name.length - 1);

if (!childReq.params) {
childReq.params = {};
}

// set up the id of the current object being removed for access by child
// scaffolds
childReq.params[singularName + '_id'] = id;

// statistics for determining when deletion is complete
var objectsRemoved = 0;
var numChildrenProcessed = 0;
var numObjects = 0;

// remove handler for deleting child scaffold objects
function removeHandler(err) {
if (err) {
callback(err);
} else {
objectsRemoved++;
if (numChildrenProcessed === children.length &&
objectsRemoved === numObjects) {
crud.remove(key, id, db, function(err, status) {
callback(err);
});
}
}
}

// if there is nothing to remove, immediately call the remove handler
if (children.length === 0) {
// set to one so that the handler thinks it has removed all objects
numObjects = 1;
removeHandler(null);
}

// remove objects in child scaffolds that correspond to this object
children.forEach(function(childName) {
var childScaffold = require('./' + childName);

// key is in the form project:screen:components; want to get it in
// the form project:screen:component:elements
var childKey = key.substr(0, key.length - 1);
childKey += ':' + id + ':' + childName;

db.hlen(childKey, function(err, length) {
numObjects += length;
numChildrenProcessed++;

crud.remove(key, id, db, function(err, status) {
callback(err);
// there are no children to remove
if (numChildrenProcessed === children.length && numObjects === 0) {
numObjects = 1;
removeHandler(null);
}

if (err) {
callback(err);
} else {
for (var i = 1; i <= length; i++) {
childScaffold.remove(childReq, db, i, removeHandler);
}
}
});
});
};

Expand Down
13 changes: 3 additions & 10 deletions lib/screens.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*globals exports:true*/
const ALLOWED_FIELDS = {
title: undefined,
is_start: undefined,
Expand All @@ -6,14 +7,6 @@ const ALLOWED_FIELDS = {

var scaffold = require('./scaffold');

/* Get Screens Key
* Requires: web request
* Returns: database key for screen hash
*/
function getScreensKey(req) {
return req.session.email + ':project:' + req.params.project_id + ':screens';
}

/* Get Default Screen
* Requires: web request
* Returns: default screen data
Expand All @@ -26,5 +19,5 @@ function getDefaultScreen(req) {
};
}

exports = module.exports = scaffold.generate(getScreensKey,
getDefaultScreen, ALLOWED_FIELDS);
exports = module.exports = scaffold.generate(['projects'], ['components'],
'screens', getDefaultScreen, ALLOWED_FIELDS);
41 changes: 41 additions & 0 deletions test/test.components.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var db = redis.redisConnect(settings);
var screens = require('../lib/screens');
var projects = require('../lib/projects');
var components = require('../lib/components');
var elements = require('../lib/elements');

var projectReq = {
session: {
Expand Down Expand Up @@ -53,6 +54,23 @@ var componentReq = {
}
};

var elementReq = {
session: {
email: 'test@test.org'
},
body: {
type: 'input_text',
layout: 'row1',
required: true,
src: ''
},
params: {
project_id: 1,
screen_id: 1,
component_id: 1
}
};

describe('component', function() {
before(function(done) {
var req = projectReq;
Expand Down Expand Up @@ -102,6 +120,9 @@ describe('component', function() {
componentList[0].type.should.equal(req.body.type);
componentList[0].layout.should.equal(req.body.layout);
componentList[0].action.should.equal(req.body.action);
componentList[1].type.should.equal(req.body.type);
componentList[1].layout.should.equal(req.body.layout);
componentList[1].action.should.equal(req.body.action);
done();
});
});
Expand Down Expand Up @@ -173,5 +194,25 @@ describe('component', function() {
});
}, 10);
});

it('deletes an element associated with a component', function(done) {
var req = componentReq;

components.add(req, db, function(err, component) {
req = elementReq;

elements.add(req, db, function(err, element) {
req = componentReq;

components.remove(req, db, 1, function(err) {
should.not.exist(err);
elements.list(req, db, function(err, elementList) {
elementList.should.eql([]);
done();
});
});
});
});
});
});
});
Loading

0 comments on commit febc74e

Please sign in to comment.