From 26a58cf0872e64fdaa2e8edab73834eb6dbbd7a6 Mon Sep 17 00:00:00 2001 From: Claire Neveu Date: Sat, 19 Sep 2020 11:53:08 -0400 Subject: [PATCH 1/3] Add overrideable identifier preparation methods --- sql-bricks.js | 43 +++++++++++++++++++++++++++------------- tests/tests.js | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 14 deletions(-) diff --git a/sql-bricks.js b/sql-bricks.js index 33942f6..ef7a00b 100644 --- a/sql-bricks.js +++ b/sql-bricks.js @@ -759,8 +759,8 @@ return new Binary(this.op, this.col, this.val); }; Binary.prototype.toString = function toString(opts) { - var sql = handleColumn(this.col, opts); - return sql + ' ' + this.op + ' ' + this.quantifier + handleValue(this.val, opts); + var res = handleColumn(this.col, opts); + return res + ' ' + this.op + ' ' + this.quantifier + handleValue(this.val, opts); } sql.like = function like(col, val, escape_char) { return new Like(col, val, escape_char); }; @@ -774,10 +774,10 @@ return new Like(this.col, this.val, this.escape_char); }; Like.prototype.toString = function toString(opts) { - var sql = handleColumn(this.col, opts) + ' LIKE ' + handleValue(this.val, opts); + var res = handleColumn(this.col, opts) + ' LIKE ' + handleValue(this.val, opts); if (this.escape_char) - sql += " ESCAPE '" + this.escape_char + "'"; - return sql; + res += " ESCAPE '" + this.escape_char + "'"; + return res; } sql.between = function between(col, val1, val2) { return new Between(col, val1, val2); }; @@ -827,13 +827,13 @@ }; In.prototype.toString = function toString(opts) { var col_sql = handleColumn(this.col, opts); - var sql; + var res; if (_.isArray(this.list)) - sql = handleValues(this.list, opts).join(', '); + res = handleValues(this.list, opts).join(', '); else if (this.list instanceof Statement) - sql = this.list._toString(opts); + res = this.list._toString(opts); - return col_sql + ' IN (' + sql + ')'; + return col_sql + ' IN (' + res + ')'; }; sql.exists = function(subquery) { return new Exists(subquery); } @@ -933,24 +933,39 @@ }; function handleTables(tables, opts) { - return tables.map(function(tbl) { return handleTable(tbl, opts); }).join(', '); + var foo = tables.map(function(tbl) { return handleTable(tbl, opts); }).join(', '); + return foo; } sql._handleTables = handleTables; function handleTable(table, opts) { - return handleColumn(expandAlias(table), opts); + if (typeof table === 'string') { + return sql._prepareTableIdentifier(table, opts); + } + return prepareTableIdentifier(table, opts); + } + + function prepareTableIdentifier(table, opts) { + return prepareColumnIdentifier(expandAlias(table), opts); } - sql._handleTable = handleTable; + sql._prepareTableIdentifier = prepareTableIdentifier; function handleColumns(cols, opts) { return cols.map(function(col) { return handleColumn(col, opts); }).join(', '); } sql._handleColumns = handleColumns; + var function_regex = /\(/g; + function handleColumn(expr, opts) { + if (typeof expr === 'string' && !function_regex.test(expr)) { + return sql._prepareColumnIdentifier(expr, opts); + } + return prepareColumnIdentifier(expr, opts); + } // handles prefixes before a '.' and suffixes after a ' ' // for example: 'tbl.order AS tbl_order' -> 'tbl."order" AS tbl_order' var unquoted_regex = /^[\w\.]+(( AS)? \w+)?$/i; - function handleColumn(expr, opts) { + function prepareColumnIdentifier(expr, opts) { if (expr instanceof Statement) return expr._toNestedString(opts); @@ -965,7 +980,7 @@ else return expr; } - sql._handleColumn = handleColumn; + sql._prepareColumnIdentifier = prepareColumnIdentifier; function quoteColOrTbl(expr) { var prefix = ''; diff --git a/tests/tests.js b/tests/tests.js index c834045..2b594b9 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -944,6 +944,59 @@ describe('SQL Bricks', function() { }); }); + describe('overriding _prepareTableIdentifier', function() { + var sql; + var oldFunc; + before('override _prepareTableIdentifier', function() { + sql = is_common_js ? require('../sql-bricks.js') : window.SqlBricks; + oldFunc = sql._prepareTableIdentifier; + sql._prepareTableIdentifier = function(expr, opts) { + if (typeof expr === 'string') { + var snake = expr.replace(/[A-Z]/g, l => `_${l.toLowerCase()}`).replace(/^_/, ''); + return oldFunc(snake, opts); + } + return oldFunc(expr, opts); + }; + }); + + after('restore _prepareTableIdentifier', function() { + sql._prepareTableIdentifier = oldFunc; + }); + it('should allow camelCase conversions', function() { + check(sql.select('myColumn').from('myTable'), + 'SELECT "myColumn" FROM my_table') + }); + }); + + describe('overriding _prepareColumnIdentifier', function() { + var sql; + var oldFunc; + before('override _prepareColumnIdentifier', function() { + sql = is_common_js ? require('../sql-bricks.js') : window.SqlBricks; + oldFunc = sql._prepareColumnIdentifier; + sql._prepareColumnIdentifier = function(expr, opts) { + var snake = expr.replace(/[A-Z]/g, l => `_${l.toLowerCase()}`).replace(/^_/, ''); + return oldFunc(snake, opts); + }; + }); + + after('restore _prepareColumnIdentifier', function() { + sql._prepareColumnIdentifier = oldFunc; + }); + it('should allow camelCase conversions', function() { + check(sql.select('myColumn').from('my_table'), + 'SELECT my_column FROM my_table') + }); + it('should not affect table names', function() { + check(sql.select('myColumn').from('myTable'), + 'SELECT my_column FROM "myTable"') + }); + it('should not affect functions', function() { + check(sql.select('COUNT(*)').from('myTable'), + 'SELECT COUNT(*) FROM "myTable"') + }); + }); + describe('_extension()', function() { it('should shield base', function() { var ext = sql._extension(); From 0b7af4358b7ac12f921fb8d24b760d6602e374e2 Mon Sep 17 00:00:00 2001 From: Claire Neveu Date: Sun, 20 Sep 2020 18:30:16 -0400 Subject: [PATCH 2/3] Add test --- sql-bricks.js | 17 ++++++++--------- tests/tests.js | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/sql-bricks.js b/sql-bricks.js index ef7a00b..7876bb9 100644 --- a/sql-bricks.js +++ b/sql-bricks.js @@ -933,15 +933,14 @@ }; function handleTables(tables, opts) { - var foo = tables.map(function(tbl) { return handleTable(tbl, opts); }).join(', '); - return foo; + return tables.map(function(tbl) { return handleTable(tbl, opts); }).join(', '); } sql._handleTables = handleTables; function handleTable(table, opts) { - if (typeof table === 'string') { - return sql._prepareTableIdentifier(table, opts); - } + if (typeof table === 'string') { + return sql._prepareTableIdentifier(table, opts); + } return prepareTableIdentifier(table, opts); } @@ -957,10 +956,10 @@ var function_regex = /\(/g; function handleColumn(expr, opts) { - if (typeof expr === 'string' && !function_regex.test(expr)) { - return sql._prepareColumnIdentifier(expr, opts); - } - return prepareColumnIdentifier(expr, opts); + if (typeof expr === 'string' && !function_regex.test(expr)) { + return sql._prepareColumnIdentifier(expr, opts); + } + return prepareColumnIdentifier(expr, opts); } // handles prefixes before a '.' and suffixes after a ' ' // for example: 'tbl.order AS tbl_order' -> 'tbl."order" AS tbl_order' diff --git a/tests/tests.js b/tests/tests.js index 2b594b9..f5f3493 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -997,6 +997,30 @@ describe('SQL Bricks', function() { }); }); + describe('overriding _prepareColumnIdentifier 2', function() { + var sql; + var oldFunc; + before('override _prepareColumnIdentifier', function() { + sql = is_common_js ? require('../sql-bricks.js') : window.SqlBricks; + oldFunc = sql._prepareColumnIdentifier; + sql._prepareColumnIdentifier = function(expr, opts) { + if (/[A-Z]/g.test(expr)) { + var snake = expr.replace(/[A-Z]/g, l => `_${l.toLowerCase()}`).replace(/^_/, ''); + return oldFunc(`${snake} AS "${expr}"`, opts); + } + return oldFunc(expr, opts); + }; + }); + + after('restore _prepareColumnIdentifier', function() { + sql._prepareColumnIdentifier = oldFunc; + }); + it('should allow emitting complex expressions', function() { + check(sql.select('myColumn').from('my_table'), + 'SELECT my_column AS "myColumn" FROM my_table') + }); + }); + describe('_extension()', function() { it('should shield base', function() { var ext = sql._extension(); From c789f5ecdb9d21e3dd9846c694ab62cedf697f30 Mon Sep 17 00:00:00 2001 From: Claire Neveu Date: Sun, 20 Sep 2020 18:34:13 -0400 Subject: [PATCH 3/3] Undo incidental changes --- sql-bricks.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sql-bricks.js b/sql-bricks.js index 7876bb9..486b134 100644 --- a/sql-bricks.js +++ b/sql-bricks.js @@ -759,8 +759,8 @@ return new Binary(this.op, this.col, this.val); }; Binary.prototype.toString = function toString(opts) { - var res = handleColumn(this.col, opts); - return res + ' ' + this.op + ' ' + this.quantifier + handleValue(this.val, opts); + var sql = handleColumn(this.col, opts); + return sql + ' ' + this.op + ' ' + this.quantifier + handleValue(this.val, opts); } sql.like = function like(col, val, escape_char) { return new Like(col, val, escape_char); }; @@ -774,10 +774,10 @@ return new Like(this.col, this.val, this.escape_char); }; Like.prototype.toString = function toString(opts) { - var res = handleColumn(this.col, opts) + ' LIKE ' + handleValue(this.val, opts); + var sql = handleColumn(this.col, opts) + ' LIKE ' + handleValue(this.val, opts); if (this.escape_char) - res += " ESCAPE '" + this.escape_char + "'"; - return res; + sql += " ESCAPE '" + this.escape_char + "'"; + return sql; } sql.between = function between(col, val1, val2) { return new Between(col, val1, val2); }; @@ -827,13 +827,13 @@ }; In.prototype.toString = function toString(opts) { var col_sql = handleColumn(this.col, opts); - var res; + var sql; if (_.isArray(this.list)) - res = handleValues(this.list, opts).join(', '); + sql = handleValues(this.list, opts).join(', '); else if (this.list instanceof Statement) - res = this.list._toString(opts); + sql = this.list._toString(opts); - return col_sql + ' IN (' + res + ')'; + return col_sql + ' IN (' + sql + ')'; }; sql.exists = function(subquery) { return new Exists(subquery); }