diff --git a/lib/db/adapters/mysql.js b/lib/db/adapters/mysql.js index 440d0f3..a7b57d9 100644 --- a/lib/db/adapters/mysql.js +++ b/lib/db/adapters/mysql.js @@ -84,28 +84,36 @@ MySQLAdapter.reopenClass(/** @lends MySQLAdapter */ { }, { __name__: 'MySQLGrammar' }), Translator: Adapter.Translator.extend({ - predicates: function(p) { - this._super.apply(this, arguments); - this._predicatesForMySQLStrings(p); - this._predicatesForMySQLDates(p); + iexactRule: function(r) { + r.using('%s LIKE %s'); }, - - _predicatesForMySQLStrings: function(p) { - p('iexact').using('%s LIKE %s'); - p('contains').using('%s LIKE BINARY %s').value('like', 'contains'); - p('icontains').using('%s LIKE %s').value('like', 'contains'); - p('startsWith').using('%s LIKE BINARY %s').value('like', 'startsWith'); - p('istartsWith').using('%s LIKE %s').value('like', 'startsWith'); - p('endsWith').using('%s LIKE BINARY %s').value('like', 'endsWith'); - p('iendsWith').using('%s LIKE %s').value('like', 'endsWith'); - p('regex').using('%s REGEXP BINARY %s').value('regex'); - p('iregex').using('%s REGEXP %s').value('regex'); + containsRule: function(r) { + r.using('%s LIKE BINARY %s').value('like', 'contains'); }, - - _predicatesForMySQLDates: function(p) { - var parseWeekday = date.parseWeekdayToInt; + icontainsRule: function(r) { + r.using('%s LIKE %s').value('like', 'contains'); + }, + startsWithRule: function(r) { + r.using('%s LIKE BINARY %s').value('like', 'startsWith'); + }, + istartsWithRule: function(r) { + r.using('%s LIKE %s').value('like', 'startsWith'); + }, + endsWithRule: function(r) { + r.using('%s LIKE BINARY %s').value('like', 'endsWith'); + }, + iendsWithRule: function(r) { + r.using('%s LIKE %s').value('like', 'endsWith'); + }, + regexRule: function(r) { + r.using('%s REGEXP BINARY %s').value('regex'); + }, + iregexRule: function(r) { + r.using('%s REGEXP %s').value('regex'); + }, + weekdayRule: function(r) { var shift = function(n) { return (n + 6) % 7; }; - p('weekday').using('WEEKDAY(%s) = %s').value(parseWeekday, shift); + r.using('WEEKDAY(%s) = %s').value(date.parseWeekdayToInt, shift); }, typeForSerial: function() { return 'integer primary key auto_increment'; }, diff --git a/lib/db/adapters/pg.js b/lib/db/adapters/pg.js index ec3036d..ecf219c 100644 --- a/lib/db/adapters/pg.js +++ b/lib/db/adapters/pg.js @@ -87,37 +87,47 @@ PGAdapter.reopenClass(/** @lends PGAdapter */{ }, { __name__: 'PGGrammar' }), Translator: Adapter.Translator.extend({ - predicates: function(p) { - this._super.apply(this, arguments); - this._predicatesForPGStrings(p); - this._predicaetesForPGDates(p); - }, - - _predicatesForPGStrings: function(p) { - p('iexact').using('UPPER(%s::text) = UPPER(%s)'); - p('contains').using('%s::text LIKE %s') - .value('like', 'contains'); - p('icontains').using('UPPER(%s::text) LIKE UPPER(%s)') - .value('like', 'contains'); - p('startsWith').using('%s::text LIKE %s') - .value('like', 'startsWith'); - p('istartsWith').using('UPPER(%s::text) LIKE UPPER(%s)') - .value('like', 'startsWith'); - p('endsWith').using('%s::text LIKE %s') - .value('like', 'endsWith'); - p('iendsWith').using('UPPER(%s::text) LIKE UPPER(%s)') - .value('like', 'endsWith'); - }, - - _predicaetesForPGDates: function(p) { - var parseWeekday = date.parseWeekdayToInt; - p('year').using('EXTRACT(\'year\' FROM %s) = %s'); - p('month').using('EXTRACT(\'month\' FROM %s) = %s'); - p('day').using('EXTRACT(\'day\' FROM %s) = %s'); - p('weekday').using('EXTRACT(\'dow\' FROM %s) = %s').value(parseWeekday); - p('hour').using('EXTRACT(\'hour\' FROM %s) = %s'); - p('minute').using('EXTRACT(\'minute\' FROM %s) = %s'); - p('second').using('EXTRACT(\'second\' FROM %s) = %s'); + iexactRule: function(r) { + r.using('UPPER(%s::text) = UPPER(%s)'); + }, + containsRule: function(r) { + r.using('%s::text LIKE %s').value('like', 'contains'); + }, + icontainsRule: function(r) { + r.using('UPPER(%s::text) LIKE UPPER(%s)').value('like', 'contains'); + }, + startsWithRule: function(r) { + r.using('%s::text LIKE %s').value('like', 'startsWith'); + }, + istartsWithRule: function(r) { + r.using('UPPER(%s::text) LIKE UPPER(%s)').value('like', 'startsWith'); + }, + endsWithRule: function(r) { + r.using('%s::text LIKE %s').value('like', 'endsWith'); + }, + iendsWithRule: function(r) { + r.using('UPPER(%s::text) LIKE UPPER(%s)').value('like', 'endsWith'); + }, + yearRule: function(r) { + r.using('EXTRACT(\'year\' FROM %s) = %s'); + }, + monthRule: function(r) { + r.using('EXTRACT(\'month\' FROM %s) = %s'); + }, + dayRule: function(r) { + r.using('EXTRACT(\'day\' FROM %s) = %s'); + }, + weekdayRule: function(r) { + r.using('EXTRACT(\'dow\' FROM %s) = %s').value(date.parseWeekdayToInt); + }, + hourRule: function(r) { + r.using('EXTRACT(\'hour\' FROM %s) = %s'); + }, + minuteRule: function(r) { + r.using('EXTRACT(\'minute\' FROM %s) = %s'); + }, + secondRule: function(r) { + r.using('EXTRACT(\'second\' FROM %s) = %s'); }, typeForBinary: function() { return 'bytea'; }, diff --git a/lib/db/adapters/sqlite3.js b/lib/db/adapters/sqlite3.js index a099769..952848f 100644 --- a/lib/db/adapters/sqlite3.js +++ b/lib/db/adapters/sqlite3.js @@ -125,23 +125,38 @@ var SQLite3Adapter = Adapter.extend(/** @lends SQLite3Adapter# */ { }); +var LIKE_FORMAT = '%s LIKE %s ESCAPE \'\\\''; + SQLite3Adapter.reopenClass(/** @lends SQLite3Adapter */ { Phrasing: Adapter.Phrasing.extend(), Translator: Adapter.Translator.extend({ - predicates: function(p) { - this._super.apply(this, arguments); - - var likeFormat = '%s LIKE %s ESCAPE \'\\\''; - p('iexact').using(likeFormat); - p('contains').using(likeFormat).value('like', 'contains'); - p('icontains').using(likeFormat).value('like', 'contains'); - p('startsWith').using(likeFormat).value('like', 'startsWith'); - p('istartsWith').using(likeFormat).value('like', 'startsWith'); - p('endsWith').using(likeFormat).value('like', 'endsWith'); - p('iendsWith').using(likeFormat).value('like', 'endsWith'); - p('regex').using('%s REGEXP %s').value('regex'); - p('iregex').using('%s REGEXP \'(?i)\' || %s').value('regex'); + iexactRule: function(r) { + r.using(LIKE_FORMAT); + }, + containsRule: function(r) { + r.using(LIKE_FORMAT).value('like', 'contains'); + }, + icontainsRule: function(r) { + r.using(LIKE_FORMAT).value('like', 'contains'); + }, + startsWithRule: function(r) { + r.using(LIKE_FORMAT).value('like', 'startsWith'); + }, + istartsWithRule: function(r) { + r.using(LIKE_FORMAT).value('like', 'startsWith'); + }, + endsWithRule: function(r) { + r.using(LIKE_FORMAT).value('like', 'endsWith'); + }, + iendsWithRule: function(r) { + r.using(LIKE_FORMAT).value('like', 'endsWith'); + }, + regexRule: function(r) { + r.using('%s REGEXP %s').value('regex'); + }, + iregexRule: function(r) { + r.using('%s REGEXP \'(?i)\' || %s').value('regex'); }, typeForSerial: function() { return 'integer primary key autoincrement'; }, diff --git a/lib/db/grammar/translator.js b/lib/db/grammar/translator.js index 32284fd..dc59336 100644 --- a/lib/db/grammar/translator.js +++ b/lib/db/grammar/translator.js @@ -87,78 +87,72 @@ Translator.reopen(/** @lends Translator# */{ */ predicates: function(p) { this._super.apply(this, arguments); - this._predicatesGeneric(p); - this._predicatesForStrings(p); - this._predicaetesForDates(p); + + _(Translator.__class__.prototype).map(function(fn, name) { + var match = name.match(/_(\w+)Rule/i); + return match && match[1]; + }) + .filter() + .forEach(function(name) { + var method = this['_' + name + 'Rule']; + var override = this[name + 'Rule'] || function() {}; + var rule = p(name).match(new RegExp('^' + name + '$', 'i')); + method.call(this, rule); + override.call(this, rule); + }, this); }, - /** - * Define generic predicates. - * - * @since 1.0 - * @private - * @method - * @param {Translator~PredicateCreator} p The predicate creator. - */ - _predicatesGeneric: function(p) { - p('exact').match(/^(?:exact|eql)$/i).using('%s = %s'); - p('iexact').match(/^i(?:exact|eql)$/i).using('UPPER(%s) = UPPER(%s)'); - p('in').match(/^in$/i).using('%s IN (%@)').expands(); - p('gt').match(/^gt$/i).using('%s > %s'); - p('gte').match(/^gte$/i).using('%s >= %s'); - p('lt').match(/^lt$/i).using('%s < %s'); - p('lte').match(/^lte$/i).using('%s <= %s'); - p('between').match(/^between$/i) - .using('%s BETWEEN %s AND %s').expandsValue(); - p('isnull').match(/^(?:is)null$/i) - .using('%s IS %s').value('isNull', 'literal'); + _exactRule: function(r) { + r.match(/^(?:exact|eql)$/i).using('%s = %s'); + }, + _iexactRule: function(r) { + r.match(/^i(?:exact|eql)$/i).using('UPPER(%s) = UPPER(%s)'); + }, + _inRule: function(r) { r.using('%s IN (%@)').expands(); }, + _gtRule: function(r) { r.using('%s > %s'); }, + _gteRule: function(r) { r.using('%s >= %s'); }, + _ltRule: function(r) { r.using('%s < %s'); }, + _lteRule: function(r) { r.using('%s <= %s'); }, + _betweenRule: function(r) { + r.using('%s BETWEEN %s AND %s').expandsValue(); + }, + _isnullRule: function(r) { + r.match(/^(?:is)null$/i).using('%s IS %s').value('isNull', 'literal'); }, - /** - * Define string based predicates. - * - * @since 1.0 - * @private - * @method - * @param {Translator~PredicateCreator} p The predicate creator. - */ - _predicatesForStrings: function(p) { - p('contains').match(/^contains$/i).using('%s LIKE %s') - .value('like', 'contains'); - p('icontains').match(/^icontains$/i).using('UPPER(%s) LIKE UPPER(%s)') - .value('like', 'contains'); - p('startsWith').match(/^startsWith$/i).using('%s LIKE %s') - .value('like', 'startsWith'); - p('istartsWith').match(/^istartsWith$/i).using('UPPER(%s) LIKE UPPER(%s)') - .value('like', 'startsWith'); - p('endsWith').match(/^endsWith$/i).using('%s LIKE %s') - .value('like', 'endsWith'); - p('iendsWith').match(/^iendsWith$/i).using( 'UPPER(%s) LIKE UPPER(%s)') - .value('like', 'endsWith'); - p('regex').match(/^regex$/i).using('%s ~ %s') - .value('regex'); - p('iregex').match(/^iregex$/i).using('%s ~* %s') - .value('regex'); + _containsRule: function(r) { + r.using('%s LIKE %s').value('like', 'contains'); + }, + _icontainsRule: function(r) { + r.using('UPPER(%s) LIKE UPPER(%s)').value('like', 'contains'); + }, + _startsWithRule: function(r) { + r.using('%s LIKE %s').value('like', 'startsWith'); + }, + _istartsWithRule: function(r) { + r.using('UPPER(%s) LIKE UPPER(%s)').value('like', 'startsWith'); + }, + _endsWithRule: function(r) { + r.using('%s LIKE %s').value('like', 'endsWith'); + }, + _iendsWithRule: function(r) { + r.using( 'UPPER(%s) LIKE UPPER(%s)').value('like', 'endsWith'); + }, + _regexRule: function(r) { + r.using('%s ~ %s').value('regex'); + }, + _iregexRule: function(r) { + r.using('%s ~* %s').value('regex'); }, - /** - * Define date based predicates. - * - * @since 1.0 - * @private - * @method - * @param {Translator~PredicateCreator} p The predicate creator. - */ - _predicaetesForDates: function(p) { - p('year').match(/^year$/i).using('YEAR(%s) = %s'); - p('month').match(/^month$/i).using('MONTH(%s) = %s'); - p('day').match(/^day$/i).using('DAY(%s) = %s'); - p('weekday').match(/^weekday$/i).using('WEEKDAY(%s) = %s') - .value(date.parseWeekdayToInt); - p('hour').match(/^hour$/i).using('HOUR(%s) = %s'); - p('minute').match(/^minute$/i).using('MINUTE(%s) = %s'); - p('second').match(/^second$/i).using('SECOND(%s) = %s'); - } + _yearRule: function(r) { r.using('YEAR(%s) = %s'); }, + _monthRule: function(r) { r.using('MONTH(%s) = %s'); }, + _dayRule: function(r) { r.using('DAY(%s) = %s'); }, + _weekdayRule: function(r) { r.using('WEEKDAY(%s) = %s') + .value(date.parseWeekdayToInt); }, + _hourRule: function(r) { r.using('HOUR(%s) = %s'); }, + _minuteRule: function(r) { r.using('MINUTE(%s) = %s'); }, + _secondRule: function(r) { r.using('SECOND(%s) = %s'); }, }); Translator.reopen(/** @lends Translator# */{