From a40988b1c1fcc20bac4de559609063bca2a5add9 Mon Sep 17 00:00:00 2001 From: Glavin Wiechert Date: Sat, 14 Jun 2014 01:28:02 -0300 Subject: [PATCH] See #14. Working SQL beautifier. TODO: Use config options. --- lib/atom-beautify.js | 4 ++ lib/sql-beautify.js | 134 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 lib/sql-beautify.js diff --git a/lib/atom-beautify.js b/lib/atom-beautify.js index 4f36c92..0b4c484 100644 --- a/lib/atom-beautify.js +++ b/lib/atom-beautify.js @@ -5,6 +5,7 @@ var beautifyJS = require('js-beautify'); var beautifyHTML = require('js-beautify').html; var beautifyCSS = require('js-beautify').css; +var beautifySQL = require('./sql-beautify'); var fs = require('fs'); var path = require('path'); var nopt = require('nopt'); @@ -266,6 +267,9 @@ function beautify() { case 'CSS': text = beautifyCSS(text, getOptions('css', allOptions)); break; + case 'SQL': + text = beautifySQL(text, getOptions('sql', allOptions)); + break; default: return; } diff --git a/lib/sql-beautify.js b/lib/sql-beautify.js new file mode 100644 index 0000000..03d3cf3 --- /dev/null +++ b/lib/sql-beautify.js @@ -0,0 +1,134 @@ +/** + +Original SQL Source code from https://github.com/vkiryukhin/pretty-data +*/ +'use strict'; + +module.exports = function (text, options) { + + console.log('SQL input', text); + + function SQL() { + var self = this; + + self.step = ' '; // 2 spaces + self.shift = ['\n']; // array of shifts + var maxdeep = 100, // nesting level + ix = 0; + + // initialize array with shifts // + for (ix = 0; ix < maxdeep; ix++) { + self.shift.push(self.shift[ix] + self.step); + } + } + + function isSubquery(str, parenthesisLevel) { + return parenthesisLevel - (str.replace(/\(/g, '').length - str.replace(/\)/g, '').length); + } + + function splitSql(str, tab) { + + return str.replace(/\s{1,}/g, ' ') + + .replace(/ AND /ig, '~::~' + tab + tab + 'AND ') + .replace(/ BETWEEN /ig, '~::~' + tab + 'BETWEEN ') + .replace(/ CASE /ig, '~::~' + tab + 'CASE ') + .replace(/ ELSE /ig, '~::~' + tab + 'ELSE ') + .replace(/ END /ig, '~::~' + tab + 'END ') + .replace(/ FROM /ig, '~::~FROM ') + .replace(/ GROUP\s{1,}BY/ig, '~::~GROUP BY ') + .replace(/ HAVING /ig, '~::~HAVING ') + //.replace(/ IN /ig,'~::~'+tab+'IN ') + .replace(/ IN /ig, ' IN ') + .replace(/ JOIN /ig, '~::~JOIN ') + .replace(/ CROSS~::~{1,}JOIN /ig, '~::~CROSS JOIN ') + .replace(/ INNER~::~{1,}JOIN /ig, '~::~INNER JOIN ') + .replace(/ LEFT~::~{1,}JOIN /ig, '~::~LEFT JOIN ') + .replace(/ RIGHT~::~{1,}JOIN /ig, '~::~RIGHT JOIN ') + .replace(/ ON /ig, '~::~' + tab + 'ON ') + .replace(/ OR /ig, '~::~' + tab + tab + 'OR ') + .replace(/ ORDER\s{1,}BY/ig, '~::~ORDER BY ') + .replace(/ OVER /ig, '~::~' + tab + 'OVER ') + .replace(/\(\s{0,}SELECT /ig, '~::~(SELECT ') + .replace(/\)\s{0,}SELECT /ig, ')~::~SELECT ') + .replace(/ THEN /ig, ' THEN~::~' + tab + '') + .replace(/ UNION /ig, '~::~UNION~::~') + .replace(/ USING /ig, '~::~USING ') + .replace(/ WHEN /ig, '~::~' + tab + 'WHEN ') + .replace(/ WHERE /ig, '~::~WHERE ') + .replace(/ WITH /ig, '~::~WITH ') + //.replace(/\,\s{0,}\(/ig,',~::~( ') + //.replace(/\,/ig,',~::~'+tab+tab+'') + .replace(/ ALL /ig, ' ALL ') + .replace(/ AS /ig, ' AS ') + .replace(/ ASC /ig, ' ASC ') + .replace(/ DESC /ig, ' DESC ') + .replace(/ DISTINCT /ig, ' DISTINCT ') + .replace(/ EXISTS /ig, ' EXISTS ') + .replace(/ NOT /ig, ' NOT ') + .replace(/ NULL /ig, ' NULL ') + .replace(/ LIKE /ig, ' LIKE ') + .replace(/\s{0,}SELECT /ig, 'SELECT ') + .replace(/~::~{1,}/g, '~::~') + .split('~::~'); + } + + SQL.prototype.beautify = function(text, options) { + + var arByQuote = text.replace(/\s{1,}/g, ' ') + .replace(/\'/ig, '~::~\'') + .split('~::~'), + len = arByQuote.length, + ar = [], + deep = 0, + tab = this.step, + inComment = true, + inQuote = false, + parenthesisLevel = 0, + str = '', + ix = 0; + + for (ix = 0; ix < len; ix++) { + + if (ix % 2) { + ar = ar.concat(arByQuote[ix]); + } else { + ar = ar.concat(splitSql(arByQuote[ix], tab)); + } + } + + len = ar.length; + for (ix = 0; ix < len; ix++) { + + parenthesisLevel = isSubquery(ar[ix], parenthesisLevel); + + if (/\s{0,}\s{0,}SELECT\s{0,}/.exec(ar[ix])) { + ar[ix] = ar[ix].replace(/\,/g, ',\n' + tab + tab + ''); + } + + if (/\s{0,}\(\s{0,}SELECT\s{0,}/.exec(ar[ix])) { + deep++; + str += this.shift[deep] + ar[ix]; + } else + if (/\'/.exec(ar[ix])) { + if (parenthesisLevel < 1 && deep) { + deep--; + } + str += ar[ix]; + } else { + str += this.shift[deep] + ar[ix]; + if (parenthesisLevel < 1 && deep) { + deep--; + } + } + } + + str = str.replace(/^\n{1,}/, '').replace(/\n{1,}/g, '\n'); + console.log('SQL output', str); + return str; + + }; + + return new SQL().beautify(text, options); + +};