UNPKG

mohair

Version:

mohair is a simple and flexible sql builder with a fluent interface

631 lines (608 loc) 18.3 kB
// Generated by CoffeeScript 1.8.0 var Mohair, criterion, factories, implementsSqlFragmentInterface, prototypes, _, __slice = [].slice, __hasProp = {}.hasOwnProperty; _ = require('lodash'); criterion = require('criterion'); implementsSqlFragmentInterface = criterion.helper.implementsSqlFragmentInterface; prototypes = {}; factories = {}; prototypes.joinedItems = { sql: function(escape) { var parts; parts = []; this._items.forEach(function(item) { var itemSql; if (implementsSqlFragmentInterface(item)) { itemSql = item.sql(escape); if (!item.dontWrap) { itemSql = '(' + itemSql + ')'; } return parts.push(itemSql); } else { return parts.push(item); } }); return parts.join(this._join); }, params: function() { var params; params = []; this._items.forEach(function(item) { if (implementsSqlFragmentInterface(item)) { return params = params.concat(item.params()); } }); return params; }, dontWrap: true }; factories.joinedItems = function() { var items, join; join = arguments[0], items = 2 <= arguments.length ? __slice.call(arguments, 1) : []; return _.create(prototypes.joinedItems, { _join: join, _items: _.flatten(items) }); }; prototypes.aliases = { sql: function(escape) { var escapeStringValues, object, parts; object = this._object; escapeStringValues = this._escapeStringValues; parts = []; Object.keys(object).forEach(function(key) { var value, valueSql; value = object[key]; if (implementsSqlFragmentInterface(value)) { valueSql = value.sql(escape); if (!value.dontWrap) { valueSql = '(' + valueSql + ')'; } return parts.push(valueSql + ' AS ' + escape(key)); } else { return parts.push((escapeStringValues ? escape(value) : value) + ' AS ' + escape(key)); } }); return parts.join(', '); }, params: function() { var object, params; object = this._object; params = []; Object.keys(object).forEach(function(key) { var value; value = object[key]; if (implementsSqlFragmentInterface(value)) { return params = params.concat(value.params()); } }); return params; }, dontWrap: true }; factories.aliases = function(object, escapeStringValues) { if (escapeStringValues == null) { escapeStringValues = false; } if (Object.keys(object).length === 0) { throw new Error('alias object must have at least one property'); } return _.create(prototypes.aliases, { _object: object, _escapeStringValues: escapeStringValues }); }; factories.selectOutputs = function() { var outputs; outputs = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (outputs.length === 0) { return criterion('*'); } return factories.joinedItems(', ', _.flatten(outputs).map(function(output) { if (implementsSqlFragmentInterface(output)) { return output; } else if ('object' === typeof output) { return factories.aliases(output); } else { return criterion(output); } })); }; factories.fromItems = function() { var items; items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return factories.joinedItems(', ', _.flatten(items).map(function(item) { var escapeStringValues; if (implementsSqlFragmentInterface(item)) { return item; } else if ('object' === typeof item) { escapeStringValues = true; return factories.aliases(item, escapeStringValues); } else { return criterion.escape(item); } })); }; prototypes.select = { sql: function(mohair, escape) { var parts, sql; sql = ''; if (mohair._with != null) { sql += 'WITH '; parts = []; parts = Object.keys(mohair._with).map(function(key) { return escape(key) + ' AS (' + criterion(mohair._with[key]).sql(escape) + ')'; }); sql += parts.join(', '); sql += ' '; } sql += "SELECT"; if (mohair._distinct != null) { sql += " DISTINCT " + mohair._distinct; } sql += " "; sql += this._outputs.sql(escape); if (mohair._from != null) { sql += " FROM " + (mohair._from.sql(escape)); } else if (mohair._table != null) { sql += " FROM " + (escape(mohair._table)); } mohair._joins.forEach(function(join) { sql += " " + join.sql; if (join.criterion != null) { return sql += " AND (" + (join.criterion.sql(escape)) + ")"; } }); if (mohair._where != null) { sql += " WHERE " + (mohair._where.sql(escape)); } if (mohair._group != null) { sql += " GROUP BY " + (mohair._group.join(', ')); } if (mohair._having != null) { sql += " HAVING " + (mohair._having.sql(escape)); } if (mohair._window != null) { sql += " WINDOW " + mohair._window; } if (mohair._order != null) { sql += " ORDER BY " + (mohair._order.join(', ')); } if (mohair._limit != null) { sql += ' LIMIT '; if (implementsSqlFragmentInterface(mohair._limit)) { sql += mohair._limit.sql(escape); } else { sql += '?'; } } if (mohair._offset != null) { sql += ' OFFSET '; if (implementsSqlFragmentInterface(mohair._offset)) { sql += mohair._offset.sql(escape); } else { sql += '?'; } } if (mohair._for != null) { sql += " FOR " + mohair._for; } if (mohair._combinations != null) { mohair._combinations.forEach(function(combination) { return sql += " " + combination.operator + " " + (combination.query.sql(escape)); }); } return sql; }, params: function(mohair) { var params; params = []; if (mohair._with != null) { Object.keys(mohair._with).forEach(function(key) { return params = params.concat(criterion(mohair._with[key]).params()); }); } params = params.concat(this._outputs.params()); if (mohair._from != null) { params = params.concat(mohair._from.params()); } mohair._joins.forEach(function(join) { if (join.criterion != null) { return params = params.concat(join.criterion.params()); } }); if (mohair._where != null) { params = params.concat(mohair._where.params()); } if (mohair._having != null) { params = params.concat(mohair._having.params()); } if (mohair._limit != null) { if (implementsSqlFragmentInterface(mohair._limit)) { params = params.concat(mohair._limit.params()); } else { params.push(mohair._limit); } } if (mohair._offset != null) { if (implementsSqlFragmentInterface(mohair._offset)) { params = params.concat(mohair._offset.params()); } else { params.push(mohair._offset); } } if (mohair._combinations != null) { mohair._combinations.forEach(function(combination) { return params = params.concat(combination.query.params()); }); } return params; } }; factories.select = function() { var outputs; outputs = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return _.create(prototypes.select, { _outputs: factories.selectOutputs.apply(factories, outputs) }); }; prototypes.insert = { sql: function(mohair, escape) { var escapedKeys, keys, records, rows, sql, table; if (mohair._table == null) { throw new Error('.sql() of insert action requires call to .table() before it'); } if (mohair._from != null) { throw new Error('.sql() of insert action ignores and does not allow call to .from() before it'); } table = escape(mohair._table); records = this._records; keys = Object.keys(records[0]); escapedKeys = keys.map(escape); rows = records.map(function(record) { var row; row = keys.map(function(key) { if (implementsSqlFragmentInterface(record[key])) { return record[key].sql(escape); } else { return '?'; } }); return "(" + (row.join(', ')) + ")"; }); sql = "INSERT INTO " + table + "(" + (escapedKeys.join(', ')) + ") VALUES " + (rows.join(', ')); if (mohair._returning != null) { sql += " RETURNING " + (mohair._returning.sql(escape)); } return sql; }, params: function(mohair) { var keys, params, records; records = this._records; keys = Object.keys(records[0]); params = []; records.forEach(function(record) { return keys.forEach(function(key) { if (implementsSqlFragmentInterface(record[key])) { return params = params.concat(record[key].params()); } else { return params.push(record[key]); } }); }); if (mohair._returning != null) { params = params.concat(mohair._returning.params()); } return params; } }; factories.insert = function(recordOrRecords) { var keysOfFirstRecord, msg; if (Array.isArray(recordOrRecords)) { if (recordOrRecords.length === 0) { throw new Error('array argument is empty - no records to insert'); } msg = 'all records in the array argument must have the same keys.'; keysOfFirstRecord = Object.keys(recordOrRecords[0]); if (keysOfFirstRecord.length === 0) { throw new Error("can't insert empty object"); } recordOrRecords.forEach(function(record) { var keys; keys = Object.keys(record); if (keys.length !== keysOfFirstRecord.length) { throw new Error(msg); } return keysOfFirstRecord.forEach(function(key) { var value; value = record[key]; if ((value == null) && record[key] !== null) { throw new Error(msg); } }); }); return _.create(prototypes.insert, { _records: recordOrRecords }); } if ('object' === typeof recordOrRecords) { if (Object.keys(recordOrRecords).length === 0) { throw new Error("can't insert empty object"); } return _.create(prototypes.insert, { _records: [recordOrRecords] }); } throw new TypeError('argument must be an object or an array'); }; prototypes.update = { sql: function(mohair, escape) { var keys, sql, table, updates, updatesSql; updates = this._updates; if (mohair._table == null) { throw new Error('.sql() of update action requires call to .table() before it'); } table = escape(mohair._table); keys = Object.keys(updates); updatesSql = keys.map(function(key) { var escapedKey; escapedKey = escape(key); if (implementsSqlFragmentInterface(updates[key])) { return "" + escapedKey + " = " + (updates[key].sql(escape)); } else { return "" + escapedKey + " = ?"; } }); sql = "UPDATE " + table + " SET " + (updatesSql.join(', ')); if (mohair._from != null) { sql += " FROM " + (mohair._from.sql(escape)); } if (mohair._where != null) { sql += " WHERE " + (mohair._where.sql(escape)); } if (mohair._returning != null) { sql += " RETURNING " + (mohair._returning.sql(escape)); } return sql; }, params: function(mohair) { var params, updates; updates = this._updates; params = []; Object.keys(updates).forEach(function(key) { var value; value = updates[key]; if (implementsSqlFragmentInterface(value)) { return params = params.concat(value.params()); } else { return params.push(value); } }); if (mohair._from != null) { params = params.concat(mohair._from.params()); } if (mohair._where != null) { params = params.concat(mohair._where.params()); } if (mohair._returning != null) { params = params.concat(mohair._returning.params()); } return params; } }; factories.update = function(updates) { if (Object.keys(updates).length === 0) { throw new Error('nothing to update'); } return _.create(prototypes.update, { _updates: updates }); }; prototypes["delete"] = { sql: function(mohair, escape) { var sql, table; if (mohair._table == null) { throw new Error('.sql() of delete action requires call to .table() before it'); } table = escape(mohair._table); sql = "DELETE FROM " + table; if (mohair._from != null) { sql += " USING " + (mohair._from.sql(escape)); } if (mohair._where != null) { sql += " WHERE " + (mohair._where.sql(escape)); } if (mohair._returning != null) { sql += " RETURNING " + (mohair._returning.sql(escape)); } return sql; }, params: function(mohair) { var params; params = []; if (mohair._from != null) { params = params.concat(mohair._from.params()); } if (mohair._where != null) { params = params.concat(mohair._where.params()); } if (mohair._returning != null) { params = params.concat(mohair._returning.params()); } return params; } }; factories["delete"] = function() { return _.create(prototypes["delete"]); }; Mohair = function(source) { var k, v; if (source) { for (k in source) { if (!__hasProp.call(source, k)) continue; v = source[k]; this[k] = v; } } return this; }; Mohair.prototype = { fluent: function(key, value) { var next; next = new Mohair(this); next[key] = value; return next; }, _escape: _.identity, escape: function(arg) { return this.fluent('_escape', arg); }, _action: factories.select('*'), insert: function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return this.fluent('_action', factories.insert.apply(factories, args)); }, select: function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return this.fluent('_action', factories.select.apply(factories, args)); }, "delete": function() { return this.fluent('_action', factories["delete"]()); }, update: function(data) { return this.fluent('_action', factories.update(data)); }, "with": function(arg) { if (!(('object' === typeof arg) && Object.keys(arg).length !== 0)) { throw new Error('with must be called with an object that has at least one property'); } return this.fluent('_with', arg); }, distinct: function(arg) { if (arg == null) { arg = ''; } return this.fluent('_distinct', arg); }, group: function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return this.fluent('_group', args); }, window: function(arg) { return this.fluent('_window', arg); }, order: function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return this.fluent('_order', args); }, limit: function(arg) { return this.fluent('_limit', implementsSqlFragmentInterface(arg) ? arg : parseInt(arg, 10)); }, offset: function(arg) { return this.fluent('_offset', implementsSqlFragmentInterface(arg) ? arg : parseInt(arg, 10)); }, "for": function(arg) { return this.fluent('_for', arg); }, getTable: function() { return this._table; }, table: function(table) { if ('string' !== typeof table) { throw new Error('table must be a string. use .from() to call with multiple tables or subqueries.'); } return this.fluent('_table', table); }, from: function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return this.fluent('_from', factories.fromItems.apply(factories, args)); }, _joins: [], join: function() { var criterionArgs, join, next, sql; sql = arguments[0], criterionArgs = 2 <= arguments.length ? __slice.call(arguments, 1) : []; join = { sql: sql }; if (criterionArgs.length !== 0) { join.criterion = criterion.apply(null, criterionArgs); } next = new Mohair(this); next._joins = this._joins.slice(); next._joins.push(join); return next; }, where: function() { var args, where; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; where = criterion.apply(null, args); return this.fluent('_where', this._where != null ? this._where.and(where) : where); }, having: function() { var args, having; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; having = criterion.apply(null, args); return this.fluent('_having', this._having != null ? this._having.and(having) : having); }, returning: function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (args.length === 0) { return this.fluent('_returning', null); } else { return this.fluent('_returning', factories.selectOutputs.apply(factories, args)); } }, _combinations: [], combine: function(query, operator) { var combinations; combinations = this._combinations.slice(); combinations.push({ query: query, operator: operator }); return this.fluent('_combinations', combinations); }, union: function(query) { return this.combine(query, 'UNION'); }, unionAll: function(query) { return this.combine(query, 'UNION ALL'); }, intersect: function(query) { return this.combine(query, 'INTERSECT'); }, intersectAll: function(query) { return this.combine(query, 'INTERSECT ALL'); }, except: function(query) { return this.combine(query, 'EXCEPT'); }, exceptAll: function(query) { return this.combine(query, 'EXCEPT ALL'); }, call: function() { var args, fn; fn = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; return fn.apply(this, args); }, raw: function() { var params, sql; sql = arguments[0], params = 2 <= arguments.length ? __slice.call(arguments, 1) : []; return criterion.apply(null, [sql].concat(__slice.call(params))); }, sql: function(escape) { return this._action.sql(this, escape || this._escape); }, params: function() { return this._action.params(this); }, implementsSqlFragmentInterface: implementsSqlFragmentInterface }; module.exports = new Mohair;