Browse files

initial checkin

  • Loading branch information...
0 parents commit 3740032787fc3e651e53b27b5b971e96ca17bfad @malkomalko malkomalko committed Mar 4, 2011
0 README
No changes.
1 index.js
@@ -0,0 +1 @@
+module.exports = require('./lib/fast_legs');
153 lib/fast_legs/base.js
@@ -0,0 +1,153 @@
+var Statements = require("./statements")
+ , async = require("../../support/async");
+
+function Base(client) {
+ this.client = client;
+};
+
+Base.prototype.extend = function(obj) {
+ return _.extend(obj, FastLegS.Base);
+};
+
+Base.prototype.truncate = function(opts, callback) {
+ if (typeof opts === 'function') {
+ callback = opts;
+ opts = {};
+ }
+
+ var truncateStatement = Statements.truncate(this, opts);
+ this.client.emit('query', truncateStatement, function(err, result) {
+ callback(err, !result.rowCount);
+ });
+};
+
+Base.prototype.create = function(obj, callback) {
+ var self = this;
+
+ var createQuery = function() {
+ var insertStatement = Statements.insert(self, obj);
+ self.client.emit('query', insertStatement, function(err, result) {
+ callback(err, result.rowCount);
+ });
+ };
+
+ loadSchema(self, createQuery);
+};
+
+Base.prototype.find = function(selector, opts, callback) {
+ var self = this;
+
+ var findQuery = function() {
+ if (_.isFunction(opts)) {
+ callback = opts;
+ opts = {};
+ }
+
+ var selectStatement = Statements.select(self, selector, opts);
+ self.client.emit('query', selectStatement, function(err, result) {
+ var results = null;
+
+ if (_(opts.include).isUndefined()) {
+ if (_(selector).isArray())
+ results = _.isUndefined(result) ? [] : result.rows;
+ else if (_(selector).isNumber() || _(selector).isString())
+ results = _.isUndefined(result.rows[0]) ? null : result.rows[0];
+ else
+ results = _.isUndefined(result) ? [] : result.rows;
+
+ callback(err, results);
+ } else {
+ results = _.isUndefined(result) ? [] : result.rows;
+ handleIncludes(self, results, selector, opts.include, callback);
+ }
+ });
+ };
+
+ loadSchema(self, findQuery);
+};
+
+Base.prototype.destroy = function(selector, callback) {
+ var self = this;
+
+ var destroyQuery = function() {
+ if (_.isFunction(selector)) {
+ callback = selector;
+ selector = {};
+ }
+
+ var destroyStatement = Statements.destroy(self, selector);
+ self.client.emit('query', destroyStatement, function(err, results) {
+ var deletedRows = _(results).isUndefined() ? 0 : results.rowCount;
+ callback(err, deletedRows);
+ });
+ }
+
+ loadSchema(self, destroyQuery);
+};
+
+var handleIncludes = function(self, models, selector, includes, callback) {
+ var includedModels = _(includes).keys();
+
+ var findIncludes = function(model, callback) {
+ var finders = {};
+ _(includedModels).each(function(includeFinder) {
+ finders[includeFinder] = function(cb) {
+ var includedModel = _(self.many).select(function(m) {
+ return _(_(m).keys()).include(includeFinder);
+ })[0];
+
+ var where = _(includes[includeFinder].where).isUndefined() ?
+ {} : includes[includeFinder].where;
+
+ if (!_(includedModel).isUndefined()) {
+ var primaryKeySelector = {};
+ primaryKeySelector[includedModel.joinOn] = model[self.primaryKey];
+ var selector = _.extend(primaryKeySelector, where);
+
+ delete includes[includeFinder].where;
+
+ includedModel[includeFinder].find(selector,
+ includes[includeFinder],
+ function(err, results) {
+ cb(err, results);
+ });
+ } else {
+ cb(null, []);
+ }
+ }
+ });
+
+ async.parallel(finders, function(err, results) {
+ var models = _.extend(model, results);
+ callback(err, models);
+ });
+ };
+
+ async.map(models, findIncludes, function(err, results) {
+ var formattedResults = null;
+
+ if (_(selector).isArray())
+ formattedResults = _.isUndefined(results) ? [] : results;
+ else if (_(selector).isNumber() || _(selector).isString())
+ formattedResults = _.isUndefined(results) ? null : results[0];
+ else
+ formattedResults = _.isUndefined(results) ? [] : results;
+
+ callback(err, formattedResults);
+ });
+};
+
+var loadSchema = function(model, query) {
+ var statement = Statements.information(model);
+
+ if (_(model._fields).isUndefined()) {
+ model.client.emit('query', statement, function(err, result) {
+ model._fields = result.rows;
+ query();
+ });
+ } else {
+ query();
+ }
+};
+
+module.exports = Base;
34 lib/fast_legs/client.js
@@ -0,0 +1,34 @@
+var pg = require(__dirname + "/../../support/node-postgres/lib")
+ , EventEmitter = require('events').EventEmitter;
+
+function Client(connParams) {
+ this.connParams = connParams;
+ this.connected = false;
+};
+
+Client.prototype.__proto__ = EventEmitter.prototype;
+
+Client.prototype.connect = function() {
+ this.client = new pg.Client(this.connParams);
+ this.on('query', function(query, callback) {
+ this.connected || this.doConnect();
+ this.client.query(query, function(err, result) {
+ callback(err, result);
+ });
+ });
+}
+
+Client.prototype.disconnect = function() {
+ if (this.client.queryQueue.length === 0) {
+ this.client.end();
+ } else {
+ this.client.on('drain', this.client.end.bind(this.client));
+ }
+}
+
+Client.prototype.doConnect = function() {
+ this.client.connect();
+ return this.connected = true;
+}
+
+module.exports = Client;
18 lib/fast_legs/index.js
@@ -0,0 +1,18 @@
+exports.version = '0.0.1';
+
+var Base = require('./base')
+ , Client = require('./client');
+
+var FastLegS = function() {
+
+};
+
+FastLegS.prototype.connect = function(connParams) {
+ var client = new Client(connParams);
+ client.connect();
+ this.Base = new Base(client);
+ this.client = client;
+ return this;
+};
+
+module.exports = exports = new FastLegS();
261 lib/fast_legs/statements.js
@@ -0,0 +1,261 @@
+exports.select = function(model, selector, opts) {
+ var fields = buildSelectFields(model, opts)
+ , stmt = "SELECT " + fields + " FROM " + model.tableName
+ , where = buildWhereClause(model, selector)
+ , limit = buildLimitClause(opts)
+ , order = buildOrderClause(opts);
+
+ return stmt + where + limit + order + ';';
+};
+
+exports.insert = function(model, obj) {
+ var stmt = "INSERT INTO " + model.tableName
+ , fields = buildInsertFields(model, obj);
+
+ return stmt + fields + ';';
+};
+
+exports.update = function(model, selector, obj) {
+ var stmt = "UPDATE " + model.tableName
+ , set = buildUpdateFields(model, obj)
+ , where = buildWhereClause(model, selector);
+
+ return stmt + set + where + ';';
+};
+
+exports.destroy = function(model, selector) {
+ var stmt = "DELETE FROM " + model.tableName
+ , where = buildWhereClause(model, selector);
+
+ return stmt + where + ";"
+};
+
+exports.truncate = function(model, opts) {
+ var opts = opts === undefined ? {} : opts
+ , stmt = "TRUNCATE " + model.tableName;
+
+ if (opts.cascade) {
+ stmt += " CASCADE";
+ }
+
+ return stmt + ";"
+};
+
+exports.information = function(model) {
+ var stmt = "SELECT column_name, is_nullable, data_type, " +
+ "character_maximum_length, column_default " +
+ "FROM information_schema.columns " +
+ "WHERE table_name = '" + model.tableName + "';";
+
+ return stmt;
+};
+
+var buildInsertFields = function(model, fields) {
+ if (_(fields).isArray()) {
+ var keys = _(fields).chain()
+ .map(function(field) {
+ return _(field).keys();
+ })
+ .flatten()
+ .uniq()
+ .value();
+
+ var vals = _(fields).chain()
+ .map(function(field) {
+ var vals = _(keys).map(function(key) {
+ return quote(field[key]);
+ });
+ return "(" + vals + ")";
+ })
+ .join(', ')
+ .value();
+
+ return "(" + keys + ") VALUES " + vals;
+ } else {
+ var fields = validFields(model, fields)
+ , keys = _(fields).keys().join(',')
+ , vals = toCsv(fields);
+
+ return "(" + keys + ") VALUES(" + vals + ") RETURNING *";
+ }
+};
+
+var buildLimitClause = function(opts) {
+ if (_(opts.limit).isUndefined()) {
+ return "";
+ } else {
+ return " LIMIT " + opts.limit;
+ }
+};
+
+var buildOperator = function(key, value) {
+ var field = key.split('.')[0];
+
+ switch(key.split('.')[1]) {
+ case 'ne': case 'not':
+ var operator = "<>";
+ break;
+ case 'gt':
+ var operator = ">";
+ break;
+ case 'lt':
+ var operator = "<";
+ break;
+ case 'gte':
+ var operator = ">=";
+ break;
+ case 'lte':
+ var operator = "<=";
+ break;
+ case 'like':
+ var operator = "LIKE";
+ break;
+ case 'nlike': case 'not_like':
+ var operator = "NOT LIKE";
+ break;
+ case 'ilike':
+ var operator = "ILIKE";
+ break;
+ case 'nilike': case 'not_ilike':
+ var operator = "NOT ILIKE";
+ break;
+ case 'in':
+ var operator = "IN";
+ break;
+ case 'nin': case 'not_in':
+ var operator = "NOT IN";
+ break;
+ default:
+ var operator = "=";
+ }
+
+ return field + ' ' + operator + ' ' + quote(value);
+};
+
+var buildOrderClause = function(opts) {
+ if (_(opts.order).isUndefined()) {
+ return "";
+ } else {
+ var orderFields = _(opts.order).chain()
+ .map(function(orderField) {
+ var direction = orderField[0] === '-' ? "DESC" : "ASC";
+ var orderField = orderField[0] === '-' ?
+ orderField.substring(1, orderField.length): orderField;
+ return orderField + " " + direction;
+ })
+ .join(', ')
+ .value();
+
+ return " ORDER BY " + orderFields;
+ }
+};
+
+var buildSelectFields = function(model, opts) {
+ if (_(opts.only).isUndefined()) {
+ return "*";
+ } else {
+ var columns = _(model._fields).pluck('column_name');
+ var valid_fields = _.select(opts.only, function(valid_field) {
+ return _.include(columns, valid_field);
+ });
+ return _(valid_fields).isEmpty() ? "*" : valid_fields.join(',');
+ }
+};
+
+var buildUpdateFields = function(model, fields) {
+ var fields = validFields(model, fields)
+ , pred = _(fields).chain()
+ .map(function(value, key) {
+ return key + '=' + quote(value);
+ })
+ .join(', ')
+ .value();
+
+ return nil(pred) ? '' : " SET " + pred;
+};
+
+var buildWhereClause = function(model, selector) {
+ if (_(selector).isArray()) {
+ var ids = toCsv(selector);
+ var pred = model.primaryKey + " IN (" + ids + ")";
+ } else if (_(selector).isNumber() || _(selector).isString()) {
+ var id = selector;
+ var pred = model.primaryKey + " = '" + id + "'";
+ } else if (nil(selector)){
+ var pred = '';
+ } else {
+ var pred = _(selector).chain()
+ .map(function(value, key) {
+ if (fieldIsValid(model, key))
+ return buildOperator(key, value);
+ })
+ .compact()
+ .join(' AND ')
+ .value();
+ pred += nil(pred) ? 'INVALID' : '';
+ }
+
+ return nil(pred) ? '' : " WHERE " + pred;
+};
+
+var fieldIsValid = function(model, field) {
+ var columns = _(model._fields).pluck('column_name');
+ return _.include(columns, field.split('.')[0]);
+};
+
+var nil = function(value) {
+ if (_(value).isUndefined() || _(value).isNull() || _(value).isNaN()) {
+ return true;
+ } else if (_(value).isArray() && _(value).isEmpty()) {
+ return true;
+ } else if (value.toString() === '[object Object]' && _(value).isEmpty()) {
+ return true;
+ } else if (_(value).isString() && _(value).isEmpty()) {
+ return true;
+ } else {
+ return false;
+ }
+};
+
+var quote = function(value) {
+ if (nil(value)) {
+ return "NULL";
+ } else if (_(value).isNumber()) {
+ return value;
+ } else if (_(value).isArray()) {
+ return "(" + toCsv(value) + ")";
+ } else if (_(value).isDate()) {
+ return "'" + toDateTime(value) + "'";
+ } else {
+ return "'" + value + "'";
+ }
+};
+
+var toCsv = function(list, keys) {
+ return _(list).chain()
+ .values()
+ .map(function(o) { return quote(o) })
+ .join(',')
+ .value();
+};
+
+var toDateTime = function(value) {
+ if (_(value).isDate()) {
+ return value.getFullYear()
+ + '/' + (value.getMonth()+1)
+ + '/' + (value.getDate())
+ + ' ' + (value.getHours())
+ + ':' + (value.getMinutes())
+ + ':' + (value.getSeconds());
+ }
+};
+
+var validFields = function(model, fields) {
+ var returnFields = {};
+ _(fields).each(function(value, key) {
+ if (fieldIsValid(model, key)) {
+ returnFields[key] = value;
+ }
+ });
+ return returnFields;
+};
232 test/integration/integration_test.js
@@ -0,0 +1,232 @@
+var helper = require('../test_helper.js');
+
+module.exports = {
+ 'integrates': function() {
+ var logging = false;
+
+ var connParams = {
+ user: 'basic_user'
+ , password: ''
+ , database: 'Fast_LegS'
+ , host: 'localhost'
+ , port: 5432
+ };
+
+ FastLegS.connect(connParams);
+
+ var posts = [
+ { id: 1, title: 'Some Title 1', blurb: 'Some blurb 1',
+ body: 'Some body 1', published: false },
+ { id: 2, title: 'Some Title 2',
+ body: 'Some body 2', published: true },
+ { id: 3, title: 'Some Title 3', blurb: 'Some blurb 3',
+ body: 'Some body 3', published: true },
+ { id: 4, title: 'Some Title 4', blurb: 'Some blurb 4',
+ body: 'Some body 4', published: true }
+ ]
+
+ var comments = [
+ { id: 1, post_id: 1, comment: 'Comment 1', created_at: new Date() },
+ { id: 2, post_id: 1, comment: 'Comment 2', created_at: new Date() },
+ { id: 3, post_id: 2, comment: 'Comment 3', created_at: new Date() },
+ { id: 4, post_id: 2, comment: 'Comment 4', created_at: new Date() },
+ { id: 5, post_id: 3, comment: 'Comment 5', created_at: new Date() },
+ { id: 6, post_id: 3, comment: 'Comment 6', created_at: new Date() },
+ { id: 7, post_id: 4, comment: 'Comment 7', created_at: new Date() },
+ { id: 8, post_id: 4, comment: 'Comment 8', created_at: new Date() }
+ ]
+
+ var Comment = FastLegS.Base.extend({
+ tableName: 'comments',
+ primaryKey: 'id'
+ });
+
+ var Post = FastLegS.Base.extend({
+ tableName: 'posts',
+ primaryKey: 'id',
+ many: [
+ { 'comments': Comment, joinOn: 'post_id' }
+ ]
+ });
+
+ async.series({
+ 'setup: truncates database': function(callback) {
+ Comment.truncate(function(err, result) {
+ Post.truncate({ cascade: true }, function(err, result) {
+ assert.eql(true, result);
+ callback(err, result);
+ });
+ });
+ },
+ 'create: create multiple posts': function(callback) {
+ Post.create(posts, function(err, result) {
+ assert.eql(posts.rowCount, result.rowCount);
+ callback(err, result);
+ });
+ },
+ 'create: create multiple comments': function(callback) {
+ Comment.create(comments, function(err, result) {
+ assert.eql(comments.rowCount, result.rowCount);
+ callback(err, result);
+ })
+ },
+ 'find: find a post by primary key': function(callback) {
+ Post.find(posts[0].id, function(err, results) {
+ assert.eql(posts[0].title, results.title);
+ callback(err, results);
+ });
+ },
+ 'find: find a post and only return certain fields': function(callback) {
+ Post.find(posts[1].id, { only: ['id'] }, function(err, results) {
+ assert.isUndefined(results.title);
+ callback(err, results);
+ });
+ },
+ 'find: find a comment by primary key': function(callback) {
+ Comment.find(comments[0].id, function(err, results) {
+ assert.eql(comments[0].comment, results.comment);
+ callback(err, results);
+ });
+ },
+ 'find: find a comment and only return certain fields': function(callback) {
+ Comment.find(comments[1].id, { only: ['id'] }, function(err, results) {
+ assert.isUndefined(results.comment);
+ callback(err, results);
+ });
+ },
+ 'find: find a post with a basic include(join)': function(callback) {
+ Post.find(posts[0].id, {
+ include: {
+ 'comments': { }
+ }
+ }, function(err, results) {
+ assert.eql(2, results.comments.length);
+ callback(err, results);
+ })
+ },
+ 'find: find a post with advanced include(join) opts': function(callback) {
+ Post.find({ 'blurb.ilike': '%Some blurb%' }, {
+ only: ['id', 'blurb'],
+ include: {
+ 'comments': {
+ where: {'published': true },
+ only: ['id', 'post_id', 'published'],
+ order: ['id']
+ }
+ }
+ }, function(err, results) {
+ assert.eql(2, results[0].comments.length);
+ callback(err, results);
+ });
+ },
+ 'find: multiple records': function(callback) {
+ var ids = _.pluck(comments, 'id');
+ Comment.find(ids, function(err, results) {
+ assert.eql(ids.length, results.length);
+ callback(err, results)
+ })
+ },
+ 'find: ignores unknown columns': function(callback) {
+ Post.find({ 'body': 'Some body 2' }, {
+ only: ['id', 'bad_field']
+ }, function(err, results) {
+ assert.eql(1, results.length);
+ callback(err, results);
+ })
+ },
+ 'find: ignores all unknown columns returning everything': function(callback) {
+ Post.find({ 'id': 1 }, {
+ only: ['bad_field']
+ }, function(err, results) {
+ assert.eql(1, results.length);
+ callback(err, results);
+ });
+ },
+ 'find: ignores empty only clause returning everything': function(callback) {
+ Post.find({ 'id': 2 }, {
+ only: []
+ }, function(err, results) {
+ assert.eql(1, results.length);
+ callback(err, results);
+ });
+ },
+ 'destroy: model by primary key': function(callback) {
+ Comment.destroy(8, function(err, results) {
+ assert.eql(1, results);
+ callback(err, results);
+ });
+ },
+ 'destroy: multiple records by primary key': function(callback) {
+ Comment.destroy([7, 6], function(err, results) {
+ assert.eql(2, results);
+ callback(err, results);
+ });
+ },
+ 'destroy: by a basic selector': function(callback) {
+ Comment.destroy({ 'comment':'Comment 5' }, function(err, results) {
+ assert.eql(1, results);
+ callback(err, results);
+ });
+ },
+ 'destroy: all records for model': function(callback) {
+ Comment.destroy(function(err, results) {
+ assert.eql(4, results);
+ callback(err, results);
+ });
+ },
+ 'destroy: nothing via empty selector': function(callback) {
+ Comment.destroy(function(err, results) {
+ assert.eql(0, results);
+ callback(err, results);
+ });
+ },
+ 'destroy: nothing via empty array': function(callback) {
+ Comment.destroy([], function(err, results) {
+ assert.eql(0, results);
+ callback(err, results);
+ });
+ },
+ 'destroy: nothing via bad selector': function(callback) {
+ Comment.destroy({ 'bad_field': 3 }, function(err, results) {
+ assert.eql(0, results);
+ callback(err, results);
+ });
+ },
+ 'truncate': function(callback) {
+ Post.truncate({ cascade: true }, function(err, results) {
+ assert.eql(true, results);
+ callback(err, results);
+ });
+ },
+ 'find: nothing': function(callback) {
+ var ids = _.pluck(posts, 'id');
+ Post.find(ids, function(err, results) {
+ assert.eql([], results);
+ callback(err, results);
+ });
+ },
+ 'find: nothing': function(callback) {
+ Post.find(posts.id, function(err, result) {
+ assert.isNull(result);
+ callback(err, result);
+ });
+ },
+ 'find: no clients with bad selector': function(callback) {
+ Post.find({ 'bad_field': 12 }, function(err, result) {
+ assert.eql([], result);
+ callback(err, result);
+ });
+ }
+ },
+ function(err, result) {
+ if (logging) {
+ if (err) {
+ console.log(err);
+ } else {
+ console.log(result);
+ }
+ }
+ FastLegS.client.disconnect();
+ });
+ }
+};
6 test/test_helper.js
@@ -0,0 +1,6 @@
+require.paths.unshift(__dirname + '/../..', __dirname + '/../support');
+
+var assert = global.assert = require('assert')
+ , FastLegS = global.FastLegS = require('FastLegS')
+ , _ = global._ = require('underscore')
+ , async = global.async = require('async');
418 test/unit/statements_test.js
@@ -0,0 +1,418 @@
+var helper = require('../test_helper.js')
+ , Statements = require('../../lib/fast_legs/statements');
+
+var model = {
+ tableName: 'model_name',
+ primaryKey: 'index',
+ _fields: [
+ { 'column_name': 'index' },
+ { 'column_name': 'name' },
+ { 'column_name': 'email' },
+ { 'column_name': 'age' },
+ { 'column_name': 'field' }
+ ]
+};
+
+module.exports = {
+
+ // SELECT
+
+ 'select statement: single primary key': function() {
+ assert.eql(
+ Statements.select(model, '2345', {}),
+ "SELECT * FROM model_name WHERE index = '2345';"
+ );
+ },
+ 'select statement: multiple primary keys': function() {
+ assert.eql(
+ Statements.select(model, ['1234', '5678'], {}),
+ "SELECT * FROM model_name WHERE index IN ('1234','5678');"
+ );
+ },
+ 'select statement: single field': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'name': 'awesome sauce'
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE name = 'awesome sauce';"
+ );
+ },
+ 'select statement: multiple fields': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'name': 'awesome sauce',
+ 'email': 'joepancakes@email.com'
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE name = 'awesome sauce' " +
+ "AND email = 'joepancakes@email.com';"
+ );
+ },
+ 'select statement: only option': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'name': 'awesome sauce',
+ 'email': 'joepancakes@email.com'
+ }, {
+ only: ['index', 'email']
+ }),
+
+ "SELECT index,email FROM model_name " +
+ "WHERE name = 'awesome sauce' " +
+ "AND email = 'joepancakes@email.com';"
+ );
+ },
+ 'select statement: limit': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'name': 'awesome sauce',
+ 'email': 'joepancakes@email.com'
+ }, {
+ only: ['index', 'email'],
+ limit: 25
+ }),
+
+ "SELECT index,email FROM model_name " +
+ "WHERE name = 'awesome sauce' " +
+ "AND email = 'joepancakes@email.com' " +
+ "LIMIT 25;"
+ );
+ },
+ 'select statement: order asc': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'name': 'awesome sauce',
+ 'email': 'joepancakes@email.com'
+ }, {
+ only: ['index', 'email'],
+ limit: 50,
+ order: ['field']
+ }),
+
+ "SELECT index,email FROM model_name " +
+ "WHERE name = 'awesome sauce' " +
+ "AND email = 'joepancakes@email.com' " +
+ "LIMIT 50 " +
+ "ORDER BY field ASC;"
+ );
+ },
+ 'select statement: order desc': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'name': 'awesome sauce',
+ 'email': 'joepancakes@email.com'
+ }, {
+ only: ['index', 'email'],
+ limit: 50,
+ order: ['-field']
+ }),
+
+ "SELECT index,email FROM model_name " +
+ "WHERE name = 'awesome sauce' " +
+ "AND email = 'joepancakes@email.com' " +
+ "LIMIT 50 " +
+ "ORDER BY field DESC;"
+ );
+ },
+ 'select statement: multiple order fields': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'name': 'awesome sauce',
+ 'email': 'joepancakes@email.com'
+ }, {
+ only: ['index', 'email'],
+ limit: 50,
+ order: ['-field', 'another_field']
+ }),
+
+ "SELECT index,email FROM model_name " +
+ "WHERE name = 'awesome sauce' " +
+ "AND email = 'joepancakes@email.com' " +
+ "LIMIT 50 " +
+ "ORDER BY field DESC, another_field ASC;"
+ );
+ },
+ 'select statement: not equals (ne, not)': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'name.ne': 'awesome sauce'
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE name <> 'awesome sauce';"
+ );
+ assert.eql(
+ Statements.select(model, {
+ 'name.not': 'awesome sauce'
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE name <> 'awesome sauce';"
+ );
+ },
+ 'select statement: greater than (gt)': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'age.gt': 21
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE age > 21;"
+ );
+ },
+ 'select statement: less than (lt)': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'age.lt': 21
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE age < 21;"
+ );
+ },
+ 'select statement: greater than or equal (gte)': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'age.gte': 21
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE age >= 21;"
+ );
+ },
+ 'select statement: less than or equal (lte)': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'age.lte': 21
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE age <= 21;"
+ );
+ },
+ 'select statement: like (like)': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'name.like': '%John%'
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE name LIKE '%John%';"
+ );
+ },
+ 'select statement: not like (nlike, not_like)': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'name.nlike': '%John%'
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE name NOT LIKE '%John%';"
+ );
+ assert.eql(
+ Statements.select(model, {
+ 'name.not_like': '%John%'
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE name NOT LIKE '%John%';"
+ );
+ },
+ 'select statement: case insensitive like (ilike)': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'name.ilike': '%john%'
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE name ILIKE '%john%';"
+ );
+ },
+ 'select statement: not case insensitive like (nilike, not_ilike)': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'name.nilike': '%john%'
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE name NOT ILIKE '%john%';"
+ );
+ assert.eql(
+ Statements.select(model, {
+ 'name.not_ilike': '%john%'
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE name NOT ILIKE '%john%';"
+ );
+ },
+ 'select statement: in a list of values (in)': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'field.in': ['some name', 34]
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE field IN ('some name',34);"
+ );
+ },
+ 'select statement: not in a list of values (nin, not_in)': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'field.nin': ['some name', 34]
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE field NOT IN ('some name',34);"
+ );
+ assert.eql(
+ Statements.select(model, {
+ 'field.not_in': ['some name', 34]
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE field NOT IN ('some name',34);"
+ );
+ },
+ 'select statement: ignores invalid fields': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'field.in': ['some name', 34],
+ 'bad_field': 1234
+ }, {}),
+
+ "SELECT * FROM model_name " +
+ "WHERE field IN ('some name',34);"
+ );
+ },
+ 'select statement: returns empty with all invalid fields': function() {
+ assert.eql(
+ Statements.select(model, {
+ 'bad_field': 1234
+ }, {}),
+
+ "SELECT * FROM model_name WHERE INVALID;"
+ );
+ },
+
+ // INSERT
+
+ 'insert statement: basic with all valid fields': function() {
+ var obj = { index: '1234', name: 'Joseph' };
+
+ assert.eql(
+ Statements.insert(model, obj),
+ "INSERT INTO model_name(index,name) " +
+ "VALUES('1234','Joseph') RETURNING *;"
+ );
+ },
+ 'insert statement: ignore invalid fields': function() {
+ var obj = {
+ bad_field: 'abcdef',
+ email: 'bob@email.com',
+ name: 'Bob',
+ age: 8
+ };
+
+ assert.eql(
+ Statements.insert(model, obj),
+ "INSERT INTO model_name(email,name,age) " +
+ "VALUES('bob@email.com','Bob',8) RETURNING *;"
+ );
+ },
+
+ // UPDATE
+
+ 'update statement: basic with all valid fields': function() {
+ var obj = { index: '1234', name: 'Joseph' };
+
+ assert.eql(
+ Statements.update(model, {
+ 'age.gt': 15
+ }, obj),
+ "UPDATE model_name " +
+ "SET index='1234', name='Joseph' " +
+ "WHERE age > 15;"
+ );
+ },
+ 'update statement: ignore invalid fields': function() {
+ var obj = {
+ age: 8,
+ bad_field: 'abcdef',
+ name: 'Bob',
+ email: 'bob@email.com'
+ };
+
+ assert.eql(
+ Statements.update(model, {
+ 'name': 'Joe'
+ }, obj),
+ "UPDATE model_name " +
+ "SET age=8, name='Bob', email='bob@email.com' " +
+ "WHERE name = 'Joe';"
+ );
+ },
+
+ // DELETE
+
+ 'delete statement: delete all rows': function() {
+ assert.eql(
+ Statements.destroy(model),
+
+ "DELETE FROM model_name;"
+ );
+ },
+ 'delete statement: one field for selector': function() {
+ assert.eql(
+ Statements.destroy(model, {
+ 'name': 'awesome sauce'
+ }),
+
+ "DELETE FROM model_name " +
+ "WHERE name = 'awesome sauce';"
+ );
+ },
+ 'delete statement: multiple fields for selector': function() {
+ assert.eql(
+ Statements.destroy(model, {
+ 'name': 'awesome sauce',
+ 'email': 'happyman@bluesky.com'
+ }),
+
+ "DELETE FROM model_name " +
+ "WHERE name = 'awesome sauce' " +
+ "AND email = 'happyman@bluesky.com';"
+ );
+ },
+ 'delete statement: ignores invalid fields': function() {
+ assert.eql(
+ Statements.destroy(model, {
+ 'name': 'awesome sauce',
+ 'email': 'happyman@bluesky.com',
+ 'bad_field': 1000
+ }),
+
+ "DELETE FROM model_name " +
+ "WHERE name = 'awesome sauce' " +
+ "AND email = 'happyman@bluesky.com';"
+ );
+ },
+
+ // TRUNCATE
+
+ 'truncate statement: truncates all records': function() {
+ assert.eql(
+ Statements.truncate(model),
+ "TRUNCATE model_name;"
+ );
+ },
+ 'truncate statement: passing cascading option': function() {
+ assert.eql(
+ Statements.truncate(model, { cascade: true }),
+ "TRUNCATE model_name CASCADE;"
+ );
+ },
+}

0 comments on commit 3740032

Please sign in to comment.