downstairs
Advanced tools
Comparing version 0.2.8 to 0.2.9
var Downstairs = {}; | ||
var Table = require('./table'); | ||
var Collection = require('./collection') | ||
var pg = require('pg') | ||
@@ -9,3 +9,3 @@ , async = require('async') | ||
Downstairs.connections = {}; | ||
Table.use(Downstairs); | ||
Collection.use(Downstairs); | ||
@@ -35,4 +35,5 @@ Downstairs.add = function(connection, name){ | ||
Downstairs.Table = Table; | ||
Downstairs.Collection = Collection; | ||
Downstairs.Table = Collection; | ||
Downstairs.Connection = Connection; | ||
module.exports = Downstairs; |
var async = require('async') | ||
, _ = require('underscore'); | ||
var fieldsFinder = function(keys, record){ | ||
var data = {}; | ||
_.each(keys, function(key){ | ||
if (key !== 'id'){ | ||
data[key] = record[key]; | ||
} | ||
}) | ||
return data; | ||
} | ||
var Record = function(properties){ | ||
@@ -11,6 +23,22 @@ this._isNew = true; | ||
// this.destroy = function(cb) {} | ||
this.destroy = function(cb) { | ||
var data = fieldsFinder(_.keys(this.properties), this); | ||
this._model.delete({id: this.id}, cb); | ||
} | ||
// this.save = function(cb) {} | ||
this.save = function(cb){ | ||
var data = fieldsFinder(_.keys(this.properties), this); | ||
var _model = this._model; | ||
this.isValid(function(err, result){ | ||
if (result){ | ||
return _model.update(data, {id: this.id}, cb); | ||
} | ||
else { | ||
return cb(err, null); | ||
} | ||
}); | ||
} | ||
//an interim step for reaching a JSON representation of the model | ||
@@ -21,5 +49,4 @@ this.toJson = function(options) { | ||
} | ||
}; | ||
module.exports = Record; |
358
lib/table.js
@@ -1,355 +0,3 @@ | ||
var Table = {} | ||
, async = require('async') | ||
, _ = require('underscore') | ||
, Record = require('./record'); | ||
Table.Downstairs; | ||
Table.use = function(Downstairs){ | ||
Table.Downstairs = Downstairs; | ||
} | ||
var jsonConditionsToSQL = function(Model, conditions){ | ||
var clauses = []; | ||
for (var key in conditions){ | ||
if (Model.sql[key]) { | ||
if (typeof conditions[key] === 'null') { | ||
var clause = Model.sql[key].isNull(); | ||
clauses.push(clause); | ||
} | ||
else if (conditions[key] || conditions[key] === '' || conditions[key] === 0) { | ||
var clause = Model.sql[key].equals(conditions[key]); | ||
clauses.push(clause); | ||
} | ||
} | ||
} | ||
var anded = ander(clauses); | ||
return anded; | ||
} | ||
var ander = function(clauses){ | ||
var base = clauses.shift(); | ||
var chainer = function(clause){ | ||
base = base.and(clause); | ||
}; | ||
clauses.forEach(chainer, base); | ||
return base; | ||
} | ||
var parseConditions = function (conditions, _self, sqlBaseQuery) { | ||
if (conditions){ | ||
var sqlConditions = jsonConditionsToSQL(_self, conditions); | ||
if (sqlConditions) { | ||
return sqlBaseQuery.where(sqlConditions); | ||
} | ||
} | ||
return sqlBaseQuery; | ||
} | ||
var cleanData = function(sql, data){ | ||
var objectKeys = _.keys(data); | ||
var differences = _.difference(objectKeys, sql._initialConfig.columns); | ||
differences.forEach(function(diff){ | ||
delete data[diff]; | ||
}) | ||
return data; | ||
} | ||
/* | ||
* Mixin behaviours for all models go here | ||
*/ | ||
Table.findAll = function(conditions, cb){ | ||
var results = []; | ||
if (typeof conditions === 'function') { | ||
cb = conditions; | ||
conditions = null; | ||
} | ||
var sqlStr; | ||
var sqlBaseQuery = this.sql.select(this.sql.star()).from(this.sql); | ||
sqlBaseQuery = parseConditions(conditions, this, sqlBaseQuery); | ||
sqlStr = sqlBaseQuery.toQuery(); | ||
if (conditions && conditions.queryParameters){ | ||
if (conditions.queryParameters.orderBy){ | ||
sqlStr.text = sqlStr.text + " ORDER BY " + conditions.queryParameters['orderBy']; | ||
} | ||
if (conditions.queryParameters.limit){ | ||
sqlStr.text = sqlStr.text + " LIMIT " + conditions.queryParameters['limit']; | ||
} | ||
// if (conditions.queryParameters.offset){ | ||
// sqlStr.text = sqlStr.text + " OFFSET " + conditions.queryParameters['offset']; | ||
// } | ||
} | ||
var _self = this; | ||
var _cb = cb; | ||
var finderAllCb = function(err, results){ | ||
var models = []; | ||
if (results){ | ||
for (var i in results.rows){ | ||
var model = new _self(results.rows[i]); | ||
models.push(model); | ||
} | ||
} | ||
_cb(err, models); | ||
} | ||
if (!this.connection.connectionString) { | ||
this.connection.connectionString = this.Downstairs.connectionString; | ||
} | ||
this.connection.query(sqlStr, finderAllCb); | ||
}; | ||
Table.find = function(conditions, cb){ | ||
if (typeof conditions === 'function') { | ||
cb = conditions; | ||
conditions = null; | ||
} | ||
var findCb = function(err, models){ | ||
if (models && models[0]) { | ||
cb(err, models[0]); | ||
} | ||
else { | ||
cb(err, null); | ||
} | ||
} | ||
this.findAll(conditions, findCb); | ||
}; | ||
Table.count = function(conditions, cb){ | ||
var results = []; | ||
if (typeof conditions === 'function') { | ||
cb = conditions; | ||
conditions = null; | ||
} | ||
var sqlStr; | ||
var sqlBaseQuery = this.sql.select('COUNT(*)').from(this.sql); | ||
sqlBaseQuery = parseConditions(conditions, this, sqlBaseQuery); | ||
sqlStr = sqlBaseQuery.toQuery(); | ||
var _self = this; | ||
var _cb = cb; | ||
var countCb = function(err, results){ | ||
if (results && results.rows && results.rows[0] && results.rows[0].count) { | ||
_cb(err, results.rows[0].count); | ||
} | ||
else { | ||
_cb(err, 0); | ||
} | ||
} | ||
if (!this.connection.connectionString) { | ||
this.connection.connectionString = this.Downstairs.connectionString; | ||
} | ||
this.connection.query(sqlStr, countCb); | ||
}; | ||
Table.update = function(data, conditions, cb){ | ||
if (typeof data === 'function'){ | ||
cb = data; | ||
data = null; | ||
conditions = null; | ||
} | ||
if (typeof conditions === 'function') { | ||
cb = conditions; | ||
conditions = null; | ||
} | ||
if (!conditions && data) { | ||
if (data.nodes && data.left && data.right) { | ||
// Sniff for a where clause condition object | ||
conditions = data; | ||
data = null; | ||
} | ||
} | ||
var _cb = cb; | ||
if (!data || typeof data === 'function') { | ||
return _cb({message: 'No data was provided'}, false); | ||
} | ||
data = cleanData(this.sql, data); | ||
var sqlStr; | ||
var sqlBaseQuery = this.sql.update(data); | ||
sqlBaseQuery = parseConditions(conditions, this, sqlBaseQuery); | ||
sqlStr = sqlBaseQuery.toQuery(); | ||
var updateCb = function(err, results){ | ||
var result = false; | ||
if (results && results.rowCount > 0 && results.command === 'UPDATE') { | ||
result = true; | ||
} | ||
_cb(err, result); | ||
} | ||
this.connection.query(sqlStr, updateCb); | ||
} | ||
Table.create = function(data, cb){ | ||
if (typeof data === 'function') { | ||
cb = data; | ||
data = null; | ||
} | ||
var _cb = cb; | ||
if (!data || typeof data === 'function') { | ||
return _cb({message: 'No data was provided'}, false); | ||
} | ||
data = cleanData(this.sql, data); | ||
var sqlStr; | ||
var sqlBaseQuery = this.sql.insert(data); | ||
sqlStr = sqlBaseQuery.toQuery(); | ||
var _self = this; | ||
var queries = {}; | ||
queries.creator = function(insertCb) { | ||
_self.connection.query(sqlStr, insertCb); | ||
} | ||
queries.findCreated = function(insertCb) { | ||
_self.find(data, insertCb); | ||
} | ||
async.series(queries, function(err, queryResults) { | ||
return _cb(err, queryResults.findCreated); | ||
}); | ||
} | ||
Table.delete = function(data, cb) { | ||
if (typeof data === 'function') { | ||
cb = data; | ||
data = null; | ||
} | ||
var _cb = cb; | ||
var sqlStr; | ||
var sqlBaseQuery = this.sql.delete(data); | ||
sqlStr = sqlBaseQuery.toQuery(); | ||
var deleteCb = function(err, results) { | ||
var result = false; | ||
if (!err) { | ||
result = true; | ||
} | ||
_cb(err, result); | ||
} | ||
this.connection.query(sqlStr, deleteCb); | ||
} | ||
var mixinTableFunctions = function(obj){ | ||
for (var property in Table){ | ||
if (property === "model"){ continue } | ||
if (typeof Table[property] === 'function'){ | ||
obj[property] = Table[property]; | ||
} | ||
} | ||
} | ||
var createValidator = function(model, validationName){ | ||
return function(cb){ | ||
model[validationName](cb); | ||
} | ||
}; | ||
/* | ||
* The model function creates a Model constructor function | ||
* & copies all Table level behaviours onto the Model | ||
* & copies the node-sql object onto the Model. | ||
*/ | ||
Table.model = function(name, sql, validations, connectionName){ | ||
var dbConnection; | ||
if (connectionName){ | ||
dbConnection = Table.Downstairs.get(connectionName); | ||
} else { | ||
dbConnection = Table.Downstairs.get('default'); | ||
} | ||
var Model = function(properties){ | ||
this.properties = properties; | ||
var validationCycle = []; | ||
var _modelImplInstance = this; | ||
for (var prop in properties){ | ||
this[prop] = this.properties[prop]; | ||
} | ||
for (var validation in this.validations){ | ||
this[validation] = this.validations[validation]; | ||
var _self = this; | ||
validationCycle.push(createValidator(_modelImplInstance, validation)); | ||
} | ||
this.isValid = function(cb){ | ||
if (typeof this.validations === 'undefined'){ | ||
cb("Define validations on the model first.", null); | ||
} | ||
async.parallel(validationCycle, function(err, results){ | ||
var validationErrors = _.filter(results, function(result){ return result != null}); | ||
if (validationErrors.length == 0){ | ||
validationErrors = null | ||
} | ||
cb(validationErrors, validationErrors == null); | ||
}); | ||
} | ||
}; | ||
Model.prototype = new Record(); | ||
Model.prototype.constructor = Record; | ||
Model.connection = dbConnection; | ||
Model.sql = sql; | ||
Model.prototype.sql = sql; | ||
Model.Downstairs = Table.Downstairs; | ||
Model.name = name; | ||
Model.prototype.validations = validations; | ||
mixinTableFunctions(Model); | ||
if (!dbConnection){ | ||
throw new Error('There is no connection defined. Make sure you have called Downstairs.add(connection)'); | ||
} | ||
else { | ||
dbConnection.register(name, Model); | ||
} | ||
return Model; | ||
} | ||
module.exports = Table; | ||
//for backwards compatability | ||
Collection = require('./collection'); | ||
module.exports = Collection; |
{ | ||
"name": "downstairs", | ||
"description": "A light ORM wrapped about brianc's node-sql and node-pg", | ||
"version": "0.2.8", | ||
"version": "0.2.9", | ||
"homepage": "https://github.com/moneytribeaustralia/downstairs.js", | ||
@@ -6,0 +6,0 @@ "author": { |
@@ -23,3 +23,17 @@ var pg = require('pg') | ||
var accountBlueprint = { | ||
Account: { | ||
name: function(){ return faker2.Lorem.words(1).join(''); } | ||
} | ||
} | ||
var roleBlueprint = { | ||
Role: { | ||
name: function(){ return faker2.Lorem.words(1).join(''); } | ||
} | ||
} | ||
ctx.add(userBlueprint); | ||
ctx.add(accountBlueprint); | ||
ctx.add(roleBlueprint); | ||
@@ -37,17 +51,42 @@ exports.ectypes = ctx; | ||
exports.userSQL = sql.Table.define({ | ||
name: 'users' | ||
, quote: true | ||
, schema: 'public' | ||
, columns: ['id' | ||
, 'username' | ||
, 'created_at' | ||
, 'updated_at' | ||
, 'email' | ||
, 'null_field' | ||
, 'password' | ||
] | ||
}); | ||
//common sql configurations used across tests | ||
exports.userConfig = sql.Table.define({ | ||
name: 'users' | ||
, quote: true | ||
, schema: 'public' | ||
, columns: ['id' | ||
, 'username' | ||
, 'created_at' | ||
, 'updated_at' | ||
, 'email' | ||
, 'password' | ||
, 'role_id' | ||
] | ||
}); | ||
exports.userTableSQL = "CREATE TABLE users\ | ||
exports.accountConfig = sql.Table.define({ | ||
name: 'accounts' | ||
, quote: true | ||
, columns: ['id' | ||
, 'user_id' | ||
] | ||
}); | ||
exports.roleConfig = sql.Table.define({ | ||
name: 'roles' | ||
, quote: true | ||
, columns: ['id' | ||
, 'name' | ||
] | ||
}); | ||
exports.repeatableConfig = sql.Table.define({ | ||
name: 'repeatables' | ||
, quote: true | ||
, schema: 'public' | ||
, columns: ['id' | ||
, 'name'] | ||
}); | ||
exports.userSQL = "CREATE TABLE users\ | ||
(\ | ||
@@ -59,13 +98,26 @@ id serial NOT NULL,\ | ||
email character varying(512) unique,\ | ||
null_field character varying(50),\ | ||
password character varying(512), \ | ||
role_id integer, \ | ||
CONSTRAINT pk_users PRIMARY KEY (id)\ | ||
);" | ||
exports.repeatableTableSQL = "CREATE TABLE repeatables\ | ||
exports.accountSQL = "CREATE TABLE accounts\ | ||
(\ | ||
id serial NOT NULL,\ | ||
user_id integer, \ | ||
name character varying(100)\ | ||
);" | ||
exports.roleSQL = "CREATE TABLE roles\ | ||
(\ | ||
id serial NOT NULL,\ | ||
name character varying(100)\ | ||
);" | ||
exports.repeatableSQL = "CREATE TABLE repeatables\ | ||
(\ | ||
id serial NOT NULL,\ | ||
name character varying(100)\ | ||
);" | ||
var defaultConnection = new Connection.PostgreSQL(env.connectionString); | ||
@@ -72,0 +124,0 @@ exports.defaultConnection = defaultConnection; |
@@ -7,8 +7,5 @@ var Downstairs = require('../lib/downstairs.js') | ||
, ectypes = helper.ectypes | ||
, Table = require('../lib/downstairs.js').Table | ||
, Collection = require('../lib/downstairs.js').Collection | ||
, Validator = require('validator').Validator; | ||
var userSQL = helper.userSQL; | ||
var userTableSQL = helper.userTableSQL; | ||
var userValidations = { | ||
@@ -38,3 +35,3 @@ usernamePresent: function(cb){ | ||
Downstairs.add(helper.defaultConnection); | ||
var User = Table.model('User', userSQL, userValidations); | ||
var User = Collection.model('User', helper.userConfig, userValidations); | ||
@@ -44,3 +41,3 @@ describe('validations', function(done){ | ||
beforeEach(function(done){ | ||
helper.resetDb(userTableSQL, done); | ||
helper.resetDb(helper.userSQL, done); | ||
}) | ||
@@ -76,3 +73,3 @@ | ||
var User = Table.model('User', userSQL, userValidation); | ||
var User = Collection.model('User', helper.userConfig, userValidation); | ||
var user = new User({username: 'fred'}); | ||
@@ -79,0 +76,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Non-existent author
Supply chain riskThe package was published by an npm account that no longer exists.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
62685
32
1463
1