diff --git a/package.json b/package.json index d971222..728c4f8 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,11 @@ "main": "./dist/parser/sqlParser.js", "scripts": { "build": "jison -m js ./src/sqlParser.jison -o ./dist/parser/sqlParser.js && npm run build-concat", - "build-concat": "cat src/stringify.js src/suffix.js >> ./dist/parser/sqlParser.js", + "build-concat": "minicat src/stringify.js src/suffix.js >> dist/parser/sqlParser.js", "postbuild": "npm run test:build", "test": "npm run build", "test:all": "mocha --require babel-register", - "test:build": "mocha --require babel-register 'test/*.test.js'", + "test:build": "mocha --require babel-register test/*.test.js", "test:benchmark": "mocha --require babel-register test/benchmark.js" }, "repository": { @@ -33,6 +33,7 @@ "concat": "^1.0.3", "debug": "^3.1.0", "jison": "^0.4.17", + "minicat": "^1.0.0", "mocha": "^3.2.0" } } diff --git a/src/stringify.js b/src/stringify.js index 14b7e05..57ea74e 100644 --- a/src/stringify.js +++ b/src/stringify.js @@ -6,13 +6,13 @@ function Sql() { this.buffer = ''; } -sqlParser.stringify = function (ast) { +sqlParser.stringify = function(ast) { var sql = new Sql(); sql.travelMain(ast); return sql.buffer; -} +}; -Sql.prototype.travel = function (ast) { +Sql.prototype.travel = function(ast) { if (!ast) return; if (typeof ast === 'string') { @@ -21,7 +21,7 @@ Sql.prototype.travel = function (ast) { var processor = this['travel' + ast.type]; processor.call(this, ast); -} +}; var noSuffixFlag = false; Sql.prototype.appendKeyword = function(keyword, noPrefix, noSuffix) { @@ -38,7 +38,7 @@ Sql.prototype.appendKeyword = function(keyword, noPrefix, noSuffix) { if (noSuffix) { noSuffixFlag = true; } -} +}; Sql.prototype.append = function(word, noPrefix, noSuffix) { if (noSuffixFlag) { noPrefix = true; @@ -53,13 +53,13 @@ Sql.prototype.append = function(word, noPrefix, noSuffix) { if (noSuffix) { noSuffixFlag = true; } -} +}; Sql.prototype.travelMain = function(ast) { this.travel(ast.value); if (ast.hasSemicolon) { this.append(';', true); } -} +}; Sql.prototype.travelSelect = function(ast) { this.appendKeyword('select'); if (ast.distinctOpt) { @@ -107,6 +107,7 @@ Sql.prototype.travelSelect = function(ast) { this.travel(ast.groupBy); } if (ast.having) { + this.appendKeyword('having'); this.travel(ast.having); } if (ast.orderBy) { @@ -122,8 +123,8 @@ Sql.prototype.travelSelect = function(ast) { if (ast.updateLockMode) { this.appendKeyword(ast.updateLockMode); } -} -Sql.prototype.travelSelectExpr = function (ast) { +}; +Sql.prototype.travelSelectExpr = function(ast) { var exprList = ast.value; for (var i = 0; i < exprList.length; i++) { if (typeof ast === 'string') { @@ -141,69 +142,69 @@ Sql.prototype.travelSelectExpr = function (ast) { this.append(',', true); } } -} -Sql.prototype.travelIsExpression = function (ast) { +}; +Sql.prototype.travelIsExpression = function(ast) { this.travel(ast.left); this.appendKeyword('in'); if (ast.hasNot) { this.appendKeyword('not'); } this.append(ast.right); -} -Sql.prototype.travelNotExpression = function (ast) { +}; +Sql.prototype.travelNotExpression = function(ast) { this.appendKeyword('not'); this.travel(ast.value); -} -Sql.prototype.travelOrExpression = -Sql.prototype.travelAndExpression = -Sql.prototype.travelXORExpression = function (ast) { +}; +Sql.prototype.travelOrExpression = Sql.prototype.travelAndExpression = Sql.prototype.travelXORExpression = function( + ast +) { this.travel(ast.left); this.appendKeyword(ast.operator); this.travel(ast.right); -} -Sql.prototype.travelNull = -Sql.prototype.travelBoolean = -Sql.prototype.travelBooleanExtra = function (ast) { +}; +Sql.prototype.travelNull = Sql.prototype.travelBoolean = Sql.prototype.travelBooleanExtra = function( + ast +) { this.appendKeyword(ast.value); -} -Sql.prototype.travelNumber = function (ast) { +}; +Sql.prototype.travelNumber = function(ast) { this.append(ast.value); -} -Sql.prototype.travelString = function (ast) { +}; +Sql.prototype.travelString = function(ast) { this.append(ast.value); -} -Sql.prototype.travelFunctionCall = function (ast) { +}; +Sql.prototype.travelFunctionCall = function(ast) { this.append(ast.name); this.append('(', true, true); var params = ast.params; for (var i = 0; i < params.length; i++) { var param = params[i]; this.travel(param); - if (i !== params.length -1) { + if (i !== params.length - 1) { this.append(',', true); } } this.append(')', true); -} -Sql.prototype.travelFunctionCallParam = function (ast) { +}; +Sql.prototype.travelFunctionCallParam = function(ast) { if (ast.distinctOpt) { this.appendKeyword(ast.distinctOpt); } this.travel(ast.value); -} -Sql.prototype.travelIdentifier = function (ast) { +}; +Sql.prototype.travelIdentifier = function(ast) { this.append(ast.value); -} -Sql.prototype.travelIdentifierList = function (ast) { +}; +Sql.prototype.travelIdentifierList = function(ast) { var list = ast.value; for (var i = 0; i < list.length; i++) { this.travel(list[i]); - if (i !== list.length -1) { + if (i !== list.length - 1) { this.append(',', true); } } -} -Sql.prototype.travelWhenThenList = function (ast) { +}; +Sql.prototype.travelWhenThenList = function(ast) { var list = ast.value; for (var i = 0; i < list.length; i++) { this.appendKeyword('when'); @@ -211,8 +212,8 @@ Sql.prototype.travelWhenThenList = function (ast) { this.appendKeyword('then'); this.travel(list[i].then); } -} -Sql.prototype.travelCaseWhen = function (ast) { +}; +Sql.prototype.travelCaseWhen = function(ast) { this.appendKeyword('case'); if (ast.caseExprOpt) { this.travel(ast.caseExprOpt); @@ -223,39 +224,39 @@ Sql.prototype.travelCaseWhen = function (ast) { this.travel(ast.else); } this.appendKeyword('end'); -} -Sql.prototype.travelPrefix = function (ast) { +}; +Sql.prototype.travelPrefix = function(ast) { this.appendKeyword(ast.prefix); this.travel(ast.value); -} -Sql.prototype.travelSimpleExprParentheses = function (ast) { +}; +Sql.prototype.travelSimpleExprParentheses = function(ast) { if (ast.hasRow) { this.appendKeyword('row'); } this.append('(', false, true); this.travel(ast.value); this.append(')', true); -} -Sql.prototype.travelSubQuery = function (ast) { +}; +Sql.prototype.travelSubQuery = function(ast) { if (ast.hasExists) { this.appendKeyword('exists'); } this.append('(', false, true); this.travel(ast.value); this.append(')', true); -} -Sql.prototype.travelIdentifierExpr = function (ast) { +}; +Sql.prototype.travelIdentifierExpr = function(ast) { this.append('{'); this.travel(ast.identifier); this.travel(ast.value); this.append('}'); -} -Sql.prototype.travelBitExpression = function (ast) { +}; +Sql.prototype.travelBitExpression = function(ast) { this.travel(ast.left); this.appendKeyword(ast.operator); this.travel(ast.right); -} -Sql.prototype.travelInSubQueryPredicate = function (ast) { +}; +Sql.prototype.travelInSubQueryPredicate = function(ast) { this.travel(ast.left); if (ast.hasNot) { this.appendKeyword('not'); @@ -264,8 +265,8 @@ Sql.prototype.travelInSubQueryPredicate = function (ast) { this.append('(', false, true); this.travel(ast.right); this.append(')'); -} -Sql.prototype.travelInExpressionListPredicate = function (ast) { +}; +Sql.prototype.travelInExpressionListPredicate = function(ast) { this.travel(ast.left); if (ast.hasNot) { this.appendKeyword('not'); @@ -274,8 +275,8 @@ Sql.prototype.travelInExpressionListPredicate = function (ast) { this.append('(', false, true); this.travel(ast.right); this.append(')'); -} -Sql.prototype.travelBetweenPredicate = function (ast) { +}; +Sql.prototype.travelBetweenPredicate = function(ast) { this.travel(ast.left); if (ast.hasNot) { this.appendKeyword('not'); @@ -284,14 +285,14 @@ Sql.prototype.travelBetweenPredicate = function (ast) { this.travel(ast.right.left); this.appendKeyword('and'); this.travel(ast.right.right); -} -Sql.prototype.travelSoundsLikePredicate = function (ast) { +}; +Sql.prototype.travelSoundsLikePredicate = function(ast) { this.travel(ast.left); this.appendKeyword('sounds'); this.appendKeyword('like'); this.travel(ast.right); -} -Sql.prototype.travelLikePredicate = function (ast) { +}; +Sql.prototype.travelLikePredicate = function(ast) { this.travel(ast.left); if (ast.hasNot) { this.appendKeyword('not'); @@ -299,40 +300,40 @@ Sql.prototype.travelLikePredicate = function (ast) { this.appendKeyword('like'); this.travel(ast.right); if (ast.escape) { - this.appendKeyword('escape') + this.appendKeyword('escape'); this.travel(ast.escape); } -} -Sql.prototype.travelRegexpPredicate = function (ast) { +}; +Sql.prototype.travelRegexpPredicate = function(ast) { this.travel(ast.left); if (ast.hasNot) { this.appendKeyword('not'); } this.appendKeyword('regexp'); this.travel(ast.right); -} -Sql.prototype.travelIsNullBooleanPrimary = function (ast) { +}; +Sql.prototype.travelIsNullBooleanPrimary = function(ast) { this.travel(ast.value); this.appendKeyword('is'); if (ast.hasNot) { this.appendKeyword('not'); } this.appendKeyword('null'); -} -Sql.prototype.travelComparisonBooleanPrimary = function (ast) { +}; +Sql.prototype.travelComparisonBooleanPrimary = function(ast) { this.travel(ast.left); this.append(ast.operator); this.travel(ast.right); -} -Sql.prototype.travelComparisonSubQueryBooleanPrimary = function (ast) { +}; +Sql.prototype.travelComparisonSubQueryBooleanPrimary = function(ast) { this.travel(ast.left); this.append(ast.operator); this.appendKeyword(ast.subQueryOpt); this.append('(', false, true); this.travel(ast.right); this.append(')'); -} -Sql.prototype.travelExpressionList = function (ast) { +}; +Sql.prototype.travelExpressionList = function(ast) { var list = ast.value; for (var i = 0; i < list.length; i++) { this.travel(list[i]); @@ -340,8 +341,8 @@ Sql.prototype.travelExpressionList = function (ast) { this.append(',', true); } } -} -Sql.prototype.travelGroupBy = function (ast) { +}; +Sql.prototype.travelGroupBy = function(ast) { this.appendKeyword('group by'); var list = ast.value; for (var i = 0; i < list.length; i++) { @@ -350,8 +351,8 @@ Sql.prototype.travelGroupBy = function (ast) { this.append(',', true); } } -} -Sql.prototype.travelOrderBy = function (ast) { +}; +Sql.prototype.travelOrderBy = function(ast) { this.appendKeyword('order by'); var list = ast.value; for (var i = 0; i < list.length; i++) { @@ -363,14 +364,14 @@ Sql.prototype.travelOrderBy = function (ast) { if (ast.rollUp) { this.appendKeyword('with rollup'); } -} -Sql.prototype.travelGroupByOrderByItem = function (ast) { +}; +Sql.prototype.travelGroupByOrderByItem = function(ast) { this.travel(ast.value); if (ast.sortOpt) { this.appendKeyword(ast.sortOpt); } -} -Sql.prototype.travelLimit = function (ast) { +}; +Sql.prototype.travelLimit = function(ast) { this.appendKeyword('limit'); var list = ast.value; if (list.length === 1) { @@ -386,8 +387,8 @@ Sql.prototype.travelLimit = function (ast) { this.append(list[1]); } } -} -Sql.prototype.travelTableReferences = function (ast) { +}; +Sql.prototype.travelTableReferences = function(ast) { var list = ast.value; if (ast.TableReferences) { this.append('(', false, true); @@ -401,8 +402,8 @@ Sql.prototype.travelTableReferences = function (ast) { if (ast.TableReferences) { this.append(')'); } -} -Sql.prototype.travelTableReference = function (ast) { +}; +Sql.prototype.travelTableReference = function(ast) { if (ast.hasOj) { this.append('{'); this.appendKeyword('oj'); @@ -411,8 +412,8 @@ Sql.prototype.travelTableReference = function (ast) { } else { this.travel(ast.value); } -} -Sql.prototype.travelInnerCrossJoinTable = function (ast) { +}; +Sql.prototype.travelInnerCrossJoinTable = function(ast) { this.travel(ast.left); if (ast.innerCrossOpt) { this.appendKeyword(ast.innerCrossOpt); @@ -422,14 +423,14 @@ Sql.prototype.travelInnerCrossJoinTable = function (ast) { if (ast.condition) { this.travel(ast.condition); } -} -Sql.prototype.travelStraightJoinTable = function (ast) { +}; +Sql.prototype.travelStraightJoinTable = function(ast) { this.travel(ast.left); this.appendKeyword('straight_join'); this.travel(ast.right); this.travel(ast.condition); -} -Sql.prototype.travelLeftRightJoinTable = function (ast) { +}; +Sql.prototype.travelLeftRightJoinTable = function(ast) { this.travel(ast.left); this.appendKeyword(ast.leftRight); if (ast.outOpt) { @@ -438,8 +439,8 @@ Sql.prototype.travelLeftRightJoinTable = function (ast) { this.appendKeyword('join'); this.travel(ast.right); this.travel(ast.condition); -} -Sql.prototype.travelNaturalJoinTable = function (ast) { +}; +Sql.prototype.travelNaturalJoinTable = function(ast) { this.travel(ast.left); this.appendKeyword('natural'); if (ast.leftRight) { @@ -450,18 +451,18 @@ Sql.prototype.travelNaturalJoinTable = function (ast) { } this.appendKeyword('join'); this.travel(ast.right); -} -Sql.prototype.travelOnJoinCondition = function (ast) { +}; +Sql.prototype.travelOnJoinCondition = function(ast) { this.appendKeyword('on'); this.travel(ast.value); -} -Sql.prototype.travelUsingJoinCondition = function (ast) { +}; +Sql.prototype.travelUsingJoinCondition = function(ast) { this.appendKeyword('using'); this.appendKeyword('(', false, true); this.travel(ast.value); this.appendKeyword(')'); -} -Sql.prototype.travelPartitions = function (ast) { +}; +Sql.prototype.travelPartitions = function(ast) { this.appendKeyword('partition'); this.appendKeyword('(', false, true); var list = ast.value; @@ -472,12 +473,12 @@ Sql.prototype.travelPartitions = function (ast) { } } this.appendKeyword(')'); -} -Sql.prototype.travelForOptIndexHint = function (ast) { +}; +Sql.prototype.travelForOptIndexHint = function(ast) { this.appendKeyword('for'); this.appendKeyword(ast.value); -} -Sql.prototype.travelIndexList = function (ast) { +}; +Sql.prototype.travelIndexList = function(ast) { var list = ast.value; for (var i = 0; i < list.length; i++) { this.travel(list[i]); @@ -485,8 +486,8 @@ Sql.prototype.travelIndexList = function (ast) { this.append(',', true); } } -} -Sql.prototype.travelUseIndexHint = function (ast) { +}; +Sql.prototype.travelUseIndexHint = function(ast) { this.appendKeyword('use'); this.appendKeyword(ast.indexOrKey); if (ast.forOpt) { @@ -497,8 +498,8 @@ Sql.prototype.travelUseIndexHint = function (ast) { this.travel(ast.value); } this.appendKeyword(')'); -} -Sql.prototype.travelIgnoreIndexHint = function (ast) { +}; +Sql.prototype.travelIgnoreIndexHint = function(ast) { this.appendKeyword('ignore'); this.appendKeyword(ast.indexOrKey); if (ast.forOpt) { @@ -509,8 +510,8 @@ Sql.prototype.travelIgnoreIndexHint = function (ast) { this.travel(ast.value); } this.appendKeyword(')'); -} -Sql.prototype.travelForceIndexHint = function (ast) { +}; +Sql.prototype.travelForceIndexHint = function(ast) { this.appendKeyword('force'); this.appendKeyword(ast.indexOrKey); if (ast.forOpt) { @@ -521,8 +522,8 @@ Sql.prototype.travelForceIndexHint = function (ast) { this.travel(ast.value); } this.appendKeyword(')'); -} -Sql.prototype.travelTableFactor = function (ast) { +}; +Sql.prototype.travelTableFactor = function(ast) { this.travel(ast.value); if (ast.partition) { this.travel(ast.partition); @@ -536,17 +537,17 @@ Sql.prototype.travelTableFactor = function (ast) { if (ast.indexHintOpt) { this.travel(ast.indexHintOpt); } -} -Sql.prototype.travelUnion = function (ast) { +}; +Sql.prototype.travelUnion = function(ast) { this.travel(ast.left); this.appendKeyword('UNION'); if (ast.distinctOpt) { - this.appendKeyword(ast.distinctOpt) + this.appendKeyword(ast.distinctOpt); } this.travel(ast.right); -} -Sql.prototype.travelSelectParenthesized = function (ast) { +}; +Sql.prototype.travelSelectParenthesized = function(ast) { this.appendKeyword('('); this.travel(ast.value); this.appendKeyword(')'); -} +}; diff --git a/test/main.test.js b/test/main.test.js index 8908c22..988c1cc 100644 --- a/test/main.test.js +++ b/test/main.test.js @@ -3,7 +3,7 @@ const debug = require('debug')('js-sql-parser'); const parser = require('../'); -const testParser = function (sql) { +const testParser = function(sql) { let firstAst = parser.parse(sql); debug(JSON.stringify(firstAst, null, 2)); let firstSql = parser.stringify(firstAst); @@ -16,30 +16,30 @@ const testParser = function (sql) { if (firstSql !== secondSql) { console.log('firstSql', firstSql); console.log('secondSql', secondSql); - throw 'err firstSql don\'t equals secondSql. '; + throw "err firstSql don't equals secondSql. "; } return secondAst; -} +}; -describe('select grammar support', function () { - it('test0', function () { +describe('select grammar support', function() { + it('test0', function() { testParser('select a from b where c > 1 group by d order by e desc;'); }); - it('test1', function () { + it('test1', function() { testParser('select distinct max_statement_time = 1.2 a '); }); - it('test2', function () { + it('test2', function() { testParser('select all 0x1f'); }); - it('test3', function () { + it('test3', function() { testParser('select distinctrow "xx", a in (1,2)'); }); - it('test4', function () { + it('test4', function() { testParser(` select tag_basic.gender as gender, @@ -58,17 +58,17 @@ describe('select grammar support', function () { `); }); - it ('test5', function () { + it('test5', function() { testParser('select function(), function(1, "sd", 0x1F)'); }); - it ('test6 unicode', function () { + it('test6 unicode', function() { testParser(` select in中文 from tags `); }); - it ('test7', function () { + it('test7', function() { testParser(` SELECT DISTINCT high_priority MAX_STATEMENT_TIME=1 STRAIGHT_JOIN SQL_SMALL_RESULT SQL_BIG_RESULT SQL_BUFFER_RESULT SQL_CACHE SQL_CALC_FOUND_ROWS fm_customer.lname AS name1, @@ -89,7 +89,7 @@ describe('select grammar support', function () { `); }); - it ('test8', function () { + it('test8', function() { testParser(` SELECT P1.PAYMENTNO, P1.AMOUNT, (P1.AMOUNT * 100) / SUM(P2.AMOUNT) @@ -99,7 +99,7 @@ describe('select grammar support', function () { `); }); - it ('test9', function () { + it('test9', function() { testParser(` SELECT PLAYERS.PLAYERNO, NAME, (SELECT COUNT(*) @@ -114,7 +114,7 @@ describe('select grammar support', function () { `); }); - it ('test10', function () { + it('test10', function() { testParser(` SELECT rd.*, rd.rd_numberofrooms - ( SELECT SUM(rn.reservation_numberofrooms) AS count_reserve_room @@ -148,11 +148,11 @@ describe('select grammar support', function () { `); }); - it ('test11 SELECT `LEFT`(a, 3) FROM b support.', function () { + it('test11 SELECT `LEFT`(a, 3) FROM b support.', function() { testParser('SELECT `LEFT`(a, 3) FROM b'); }); - it ('test12', function () { + it('test12', function() { testParser(` select a.product_id, @@ -202,7 +202,7 @@ describe('select grammar support', function () { `); }); - it ('test13', function () { + it('test13', function() { testParser(` SELECT a.*, f.ORG_NAME DEPT_NAME, @@ -286,7 +286,7 @@ describe('select grammar support', function () { `); }); - it ('test14', function () { + it('test14', function() { testParser(` SELECT k.*, @@ -345,37 +345,46 @@ describe('select grammar support', function () { `); }); - it ('limit support.', function () { + it('test15', function() { + testParser(` + SELECT P1.PAYMENTNO, P1.AMOUNT, (P1.AMOUNT * 100) / SUM(P2.AMOUNT) + FROM PENALTIES AS P1, PENALTIES AS P2 + GROUP BY P1.PAYMENTNO, P1.AMOUNT + HAVING MAX(P2.AMOUNT) > 0 + `); + }); + + it('limit support.', function() { testParser('select a from b limit 2, 3'); }); - it ('fix not equal.', function () { + it('fix not equal.', function() { testParser('select a from b where a <> 1 limit 2, 3'); }); - it ('restore semicolon.', function () { + it('restore semicolon.', function() { testParser('select a from b limit 2;'); }); - it ('recognoce alias for sql-function calls in stringify function.', function () { + it('recognoce alias for sql-function calls in stringify function.', function() { testParser('SELECT COUNT(*) AS total, a b, b as c, c/2 d, d & e an FROM b'); }); - it ('union support, https://dev.mysql.com/doc/refman/8.0/en/union.html', function () { + it('union support, https://dev.mysql.com/doc/refman/8.0/en/union.html', function() { testParser('select a from dual union select a from foo;'); }); - it ('union Parenthesized support, https://dev.mysql.com/doc/refman/8.0/en/union.html', function () { + it('union Parenthesized support, https://dev.mysql.com/doc/refman/8.0/en/union.html', function() { testParser('(select a from dual) union (select a from foo) order by a desc limit 100, 100;'); }); - it ('union all support, https://dev.mysql.com/doc/refman/8.0/en/union.html', function () { + it('union all support, https://dev.mysql.com/doc/refman/8.0/en/union.html', function() { testParser('(select a from dual) union all (select a from foo) order by a limit 100'); }); - it ('union distinct support, https://dev.mysql.com/doc/refman/8.0/en/union.html', function () { - testParser('select a from dual order by a desc limit 1, 1 union distinct select a from foo order by a limit 1'); + it('union distinct support, https://dev.mysql.com/doc/refman/8.0/en/union.html', function() { + testParser( + 'select a from dual order by a desc limit 1, 1 union distinct select a from foo order by a limit 1' + ); }); - }); -