sql-bricks
Advanced tools
Comparing version
{ | ||
"name": "sql-bricks", | ||
"version": "2.0.3", | ||
"version": "3.0.0-beta.1", | ||
"author": "Peter Rust <peter@cornerstonenw.com>", | ||
@@ -5,0 +5,0 @@ "description": "Transparent, Schemaless SQL Generation", |
@@ -1,2 +0,2 @@ | ||
# SQL Bricks.js | ||
# SQL Bricks.js | ||
@@ -3,0 +3,0 @@ [](https://travis-ci.org/CSNW/sql-bricks) |
@@ -103,14 +103,12 @@ (function() { | ||
[Select, Insert, Update, Delete].forEach(function(stmt) { | ||
stmt.defineClause = function(clause_id, template, opts) { | ||
stmt.defineClause = function(clause_id, render_fn, opts) { | ||
opts = opts || {}; | ||
var clauses = this.prototype.clauses = this.prototype.clauses || []; | ||
var templ_fn = template; | ||
if (typeof templ_fn != 'function') | ||
templ_fn = function(opts) { return templ(template, this, opts); }; | ||
this.prototype[clause_id + 'ToString'] = templ_fn; | ||
render_fn.clause_id = clause_id; | ||
this.prototype.clauses = this.prototype.clauses || []; | ||
var index; | ||
if (opts.after || opts.before) { | ||
index = clauses.indexOf(opts.after || opts.before); | ||
index = _.findIndex(this.prototype.clauses, function(render_fn) { | ||
return render_fn.clause_id == (opts.after || opts.before); | ||
}); | ||
if (index == -1) | ||
@@ -123,5 +121,5 @@ throw new Error('Error adding clause ' + clause_id + ': dependent clause "' + opts.after + '" not found'); | ||
else { | ||
index = clauses.length; | ||
index = this.prototype.clauses.length; | ||
} | ||
clauses.splice(index, 0, clause_id); | ||
this.prototype.clauses.splice(index, 0, render_fn); | ||
}; | ||
@@ -273,15 +271,30 @@ }); | ||
Select.defineClause('select', 'SELECT {{#if _distinct}}DISTINCT {{/if}}{{#if _columns}}{{columns _columns}}{{/if}}'); | ||
Select.defineClause('into', '{{#if _into}}INTO {{#if _temp}}TEMP {{/if}}{{table _into}}{{/if}}'); | ||
Select.defineClause('select', function(opts) { | ||
return `SELECT ${this._distinct ? 'DISTINCT ' : ''}` + | ||
(this._columns ? handleColumns(this._columns, opts) : ''); | ||
}); | ||
Select.defineClause('into', function(opts) { | ||
if (this._into) | ||
return `INTO ${this._temp ? 'TEMP ' : ''}${handleTable(this._into, opts)}`; | ||
}); | ||
Select.defineClause('from', function(opts) { | ||
if (!this._from) | ||
return; | ||
var result = 'FROM ' + handleTables(this._from, opts); | ||
var result = `FROM ${handleTables(this._from, opts)}`; | ||
if (this.joins) | ||
result += ' ' + _.invoke(this.joins, 'toString', opts).join(' '); | ||
result += ` ${_.invoke(this.joins, 'toString', opts).join(' ')}`; | ||
return result; | ||
}); | ||
Select.defineClause('where', '{{#if _where}}WHERE {{expression _where}}{{/if}}'); | ||
Select.defineClause('groupBy', '{{#if _groupBy}}GROUP BY {{columns _groupBy}}{{/if}}'); | ||
Select.defineClause('having', '{{#if _having}}HAVING {{expression _having}}{{/if}}'); | ||
Select.defineClause('where', function(opts) { | ||
if (this._where) | ||
return `WHERE ${handleExpression(this._where, opts)}`; | ||
}); | ||
Select.defineClause('groupBy', function(opts) { | ||
if (this._groupBy) | ||
return `GROUP BY ${handleColumns(this._groupBy, opts)}`; | ||
}); | ||
Select.defineClause('having', function(opts) { | ||
if (this._having) | ||
return `HAVING ${handleExpression(this._having, opts)}`; | ||
}); | ||
@@ -299,4 +312,11 @@ _.forEach(compounds, function(sql_keyword, clause_id) { | ||
Select.defineClause('orderBy', '{{#if _orderBy}}ORDER BY {{columns _orderBy}}{{/if}}'); | ||
Select.defineClause('forUpdate', '{{#if _forUpdate}}FOR UPDATE{{#if _of}} OF {{columns _of}}{{/if}}{{#if _noWait}} NO WAIT{{/if}}{{/if}}'); | ||
Select.defineClause('orderBy', function(opts) { | ||
if (this._orderBy) | ||
return `ORDER BY ${handleColumns(this._orderBy, opts)}`; | ||
}); | ||
Select.defineClause('forUpdate', function(opts) { | ||
if (this._forUpdate) | ||
return `FOR UPDATE${this._of ? ` OF ${handleColumns(this._of, opts)}` : ''}` + | ||
(this._noWait ? ' NO WAIT' : ''); | ||
}); | ||
@@ -375,7 +395,9 @@ | ||
Insert.defineClause('insert', 'INSERT'); | ||
Insert.defineClause('into', '{{#if _table}}INTO {{table _table}}{{/if}}'); | ||
Insert.defineClause('insert', function() { return 'INSERT'; }); | ||
Insert.defineClause('into', function(opts) { | ||
if (this._table) return `INTO ${handleTable(this._table, opts)}`; | ||
}); | ||
Insert.defineClause('columns', function(opts) { | ||
if (!this._values) return ''; | ||
return '(' + handleColumns(_.keys(this._values[0]), opts) + ')'; | ||
if (this._values) | ||
return '(' + handleColumns(_.keys(this._values[0]), opts) + ')'; | ||
}); | ||
@@ -414,4 +436,8 @@ Insert.defineClause('values', function(opts) { | ||
Update.defineClause('update', 'UPDATE'); | ||
Update.defineClause('table', '{{table _table}}'); | ||
Update.defineClause('update', function() { | ||
return 'UPDATE'; | ||
}); | ||
Update.defineClause('table', function(opts) { | ||
return handleTable(this._table, opts); | ||
}); | ||
Update.defineClause('set', function(opts) { | ||
@@ -422,3 +448,6 @@ return 'SET ' + _.map(this._values, function(value, key) { | ||
}); | ||
Update.defineClause('where', '{{#if _where}}WHERE {{expression _where}}{{/if}}'); | ||
Update.defineClause('where', function(opts) { | ||
if (this._where) | ||
return `WHERE ${handleExpression(this._where, opts)}`; | ||
}); | ||
@@ -443,4 +472,9 @@ | ||
Delete.defineClause('delete', 'DELETE FROM {{table _from}}'); | ||
Delete.defineClause('where', '{{#if _where}}WHERE {{expression _where}}{{/if}}'); | ||
Delete.defineClause('delete', function(opts) { | ||
return `DELETE FROM ${handleTable(this._from, opts)}`; | ||
}); | ||
Delete.defineClause('where', function(opts) { | ||
if (this._where) | ||
return `WHERE ${handleExpression(this._where, opts)}`; | ||
}); | ||
@@ -503,9 +537,5 @@ | ||
Statement.prototype._toString = function(opts) { | ||
var result = ''; | ||
this.clauses.forEach(function(clause) { | ||
var rlt = this[clause + 'ToString'](opts); | ||
if (rlt) | ||
result += rlt + ' '; | ||
}.bind(this)); | ||
return result.trim(); | ||
return _.compact(this.clauses.map(function(clause) { | ||
return clause.call(this, opts) | ||
}.bind(this))).join(' '); | ||
}; | ||
@@ -1004,66 +1034,2 @@ | ||
// uber-simple mini-templating language to make it easy to define clauses | ||
// handlebars-like syntax, supports helpers and nested blocks | ||
// does not support context changes, the dot operator on properties or HTML escaping | ||
function templ(str, ctx, opts) { | ||
var result = ''; | ||
var lastIndex = 0; | ||
var tmpl_re = /\{\{([#\/])?(\w+) ?(\w+)?\}\}/g; | ||
var m; | ||
while (m = tmpl_re.exec(str)) { | ||
var is_block = m[1]; | ||
var is_start = m[1] == '#'; | ||
if (m[3]) { | ||
var fn_name = m[2], attr = m[3]; | ||
var helper = templ.helpers[fn_name]; | ||
} | ||
else { | ||
var attr = m[2]; | ||
} | ||
var val = ctx[attr]; | ||
result += str.slice(lastIndex, m.index); | ||
if (is_block) { | ||
if (is_start) { | ||
var end_re = new RegExp("\\{\\{([#/])" + fn_name + ' ?(\\w+)?\\}\\}', 'g'); | ||
end_re.lastIndex = tmpl_re.lastIndex; | ||
// incr & decr level 'til we find the end block that matches this start block | ||
var level = 1; | ||
while (level) { | ||
var end_m = end_re.exec(str); | ||
if (!end_m) | ||
throw new Error('End not found for block ' + fn_name); | ||
if (end_m[1] == '#') | ||
level++; | ||
else | ||
level--; | ||
} | ||
var contents = str.slice(tmpl_re.lastIndex, end_m.index); | ||
result += helper.call(ctx, val, opts, contents, ctx); | ||
lastIndex = tmpl_re.lastIndex = end_re.lastIndex; | ||
} | ||
} | ||
else { | ||
if (fn_name) | ||
result += helper.call(ctx, val, opts); | ||
else | ||
result += val; | ||
lastIndex = tmpl_re.lastIndex; | ||
} | ||
} | ||
result += str.slice(lastIndex); | ||
return result; | ||
} | ||
sql.templ = templ; | ||
templ.helpers = { | ||
'if': function(val, opts, contents, ctx) { return val ? templ(contents, ctx, opts) : ''; }, | ||
'ifNotNull': function(val, opts, contents, ctx) { return val != null ? templ(contents, ctx, opts) : ''; }, | ||
'columns': handleColumns, | ||
'table': handleTable, | ||
'tables': handleTables, | ||
'expression': handleExpression | ||
}; | ||
// provided for browser support, based on https://gist.github.com/prust/5936064 | ||
@@ -1070,0 +1036,0 @@ function inherits(ctor, superCtor) { |
@@ -153,2 +153,7 @@ (function() { | ||
it("select('*').from('person').where(sql('LTRIM(last_name) = $', last_name));", function() { | ||
var last_name = 'Flintstone'; | ||
check(select('*').from('person').where(sql('LTRIM(last_name) = $', last_name)), "SELECT * FROM person WHERE LTRIM(last_name) = 'Flintstone'"); | ||
}); | ||
it(".groupBy('city').having(lt('max(temp_lo)', 40))", function() { | ||
@@ -155,0 +160,0 @@ |
@@ -61,30 +61,2 @@ (function() { | ||
describe('SQL Bricks', function() { | ||
describe('mini-templating lang', function() { | ||
it('should find content of if', function() { | ||
var result = sql.templ('{{#if test}}Hi there!{{/if}}', {'test': true}); | ||
assert.equal(result, 'Hi there!'); | ||
}); | ||
it('should display content on both sides of it', function() { | ||
var result = sql.templ('before{{#if test}}inside{{/if}}after', {'test': false}); | ||
assert.equal(result, 'beforeafter'); | ||
}); | ||
it('should handle multiple values', function() { | ||
var result = sql.templ('before{{val}}between{{val2}}after', {'val': 'value 1', 'val2': 'value 2'}); | ||
assert.equal(result, 'beforevalue 1betweenvalue 2after'); | ||
}); | ||
it('should handle multiple if chunks', function() { | ||
var result = sql.templ('before{{#if test}}first{{/if}}between{{#if test}}second{{/if}}after', {'test': true}); | ||
assert.equal(result, 'beforefirstbetweensecondafter'); | ||
}); | ||
it('should throw on mismatched if', function() { | ||
assert.throws(function() { | ||
sql.templ('{{#if test}}Hi there!', {'test': true}); | ||
}); | ||
}); | ||
it('should handle nested if', function() { | ||
var result = sql.templ('{{#if oneThing}} and {{#if anotherThing}}Test{{/if}}{{/if}}', {'oneThing': true, 'anotherThing': true}); | ||
assert.equal(result, ' and Test'); | ||
}); | ||
}); | ||
describe('parameterized sql', function() { | ||
@@ -91,0 +63,0 @@ it('should generate for insert statements', function() { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
318298
-0.71%14
-6.67%8026
-0.64%2
100%