mohair
Version:
mohair is a simple and flexible sql builder with a fluent interface
631 lines (608 loc) • 18.3 kB
JavaScript
// 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;