Merge branch '2.0'
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / js / 3rdParty / codemirror / addon / hint / sql-hint.js
1 (function(mod) {
2 if (typeof exports == "object" && typeof module == "object") // CommonJS
3 mod(require("../../lib/codemirror"), require("../../mode/sql/sql"));
4 else if (typeof define == "function" && define.amd) // AMD
5 define(["../../lib/codemirror", "../../mode/sql/sql"], mod);
6 else // Plain browser env
7 mod(CodeMirror);
8 })(function(CodeMirror) {
9 "use strict";
10
11 var tables;
12 var keywords;
13 var CONS = {
14 QUERY_DIV: ";",
15 ALIAS_KEYWORD: "AS"
16 };
17 var Pos = CodeMirror.Pos;
18
19 function getKeywords(editor) {
20 var mode = editor.doc.modeOption;
21 if(mode === "sql") mode = "text/x-sql";
22 return CodeMirror.resolveMode(mode).keywords;
23 }
24
25 function match(string, word) {
26 var len = string.length;
27 var sub = word.substr(0, len);
28 return string.toUpperCase() === sub.toUpperCase();
29 }
30
31 function addMatches(result, search, wordlist, formatter) {
32 for(var word in wordlist) {
33 if(!wordlist.hasOwnProperty(word)) continue;
34 if(Array.isArray(wordlist)) {
35 word = wordlist[word];
36 }
37 if(match(search, word)) {
38 result.push(formatter(word));
39 }
40 }
41 }
42
43 function columnCompletion(result, editor) {
44 var cur = editor.getCursor();
45 var token = editor.getTokenAt(cur);
46 var string = token.string.substr(1);
47 var prevCur = Pos(cur.line, token.start);
48 var table = editor.getTokenAt(prevCur).string;
49 if( !tables.hasOwnProperty( table ) ){
50 table = findTableByAlias(table, editor);
51 }
52 var columns = tables[table];
53 if(!columns) {
54 return;
55 }
56 addMatches(result, string, columns,
57 function(w) {return "." + w;});
58 }
59
60 function eachWord(lineText, f) {
61 if( !lineText ){return;}
62 var excepted = /[,;]/g;
63 var words = lineText.split( " " );
64 for( var i = 0; i < words.length; i++ ){
65 f( words[i]?words[i].replace( excepted, '' ) : '' );
66 }
67 }
68
69 function convertCurToNumber( cur ){
70 // max characters of a line is 999,999.
71 return cur.line + cur.ch / Math.pow( 10, 6 );
72 }
73
74 function convertNumberToCur( num ){
75 return Pos(Math.floor( num ), +num.toString().split( '.' ).pop());
76 }
77
78 function findTableByAlias(alias, editor) {
79 var doc = editor.doc;
80 var fullQuery = doc.getValue();
81 var aliasUpperCase = alias.toUpperCase();
82 var previousWord = "";
83 var table = "";
84 var separator = [];
85 var validRange = {
86 start: Pos( 0, 0 ),
87 end: Pos( editor.lastLine(), editor.getLineHandle( editor.lastLine() ).length )
88 };
89
90 //add separator
91 var indexOfSeparator = fullQuery.indexOf( CONS.QUERY_DIV );
92 while( indexOfSeparator != -1 ){
93 separator.push( doc.posFromIndex(indexOfSeparator));
94 indexOfSeparator = fullQuery.indexOf( CONS.QUERY_DIV, indexOfSeparator+1);
95 }
96 separator.unshift( Pos( 0, 0 ) );
97 separator.push( Pos( editor.lastLine(), editor.getLineHandle( editor.lastLine() ).text.length ) );
98
99 //find valieRange
100 var prevItem = 0;
101 var current = convertCurToNumber( editor.getCursor() );
102 for( var i=0; i< separator.length; i++){
103 var _v = convertCurToNumber( separator[i] );
104 if( current > prevItem && current <= _v ){
105 validRange = { start: convertNumberToCur( prevItem ), end: convertNumberToCur( _v ) };
106 break;
107 }
108 prevItem = _v;
109 }
110
111 var query = doc.getRange(validRange.start, validRange.end, false);
112
113 for(var i=0; i < query.length; i++){
114 var lineText = query[i];
115 eachWord( lineText, function( word ){
116 var wordUpperCase = word.toUpperCase();
117 if( wordUpperCase === aliasUpperCase && tables.hasOwnProperty( previousWord ) ){
118 table = previousWord;
119 }
120 if( wordUpperCase !== CONS.ALIAS_KEYWORD ){
121 previousWord = word;
122 }
123 });
124 if( table ){ break; }
125 }
126 return table;
127 }
128
129 function sqlHint(editor, options) {
130 tables = (options && options.tables) || {};
131 keywords = keywords || getKeywords(editor);
132 var cur = editor.getCursor();
133 var token = editor.getTokenAt(cur), end = token.end;
134 var result = [];
135 var search = token.string.trim();
136
137 if (search.charAt(0) == ".") {
138 columnCompletion(result, editor);
139 if (!result.length) {
140 while (token.start && search.charAt(0) == ".") {
141 token = editor.getTokenAt(Pos(cur.line, token.start - 1));
142 search = token.string + search;
143 }
144 addMatches(result, search, tables,
145 function(w) {return w;});
146 }
147 } else {
148 addMatches(result, search, keywords,
149 function(w) {return w.toUpperCase();});
150 addMatches(result, search, tables,
151 function(w) {return w;});
152 }
153
154 return {
155 list: result,
156 from: Pos(cur.line, token.start),
157 to: Pos(cur.line, end)
158 };
159 }
160 CodeMirror.registerHelper("hint", "sql", sqlHint);
161 });