1919def _stripQuotes (ident ):
2020 return ident .strip ('"\' `' )
2121
22+
2223# used for formatting output
2324def _stripQuotesOnDemand (ident , doStrip = True ):
2425 if doStrip :
2526 return _stripQuotes (ident )
2627 return ident
2728
29+
2830def _startsWithQuote (ident ):
2931 # str.startswith can be matched against a tuple
3032 quotes = ('`' , '"' )
3133 return ident .startswith (quotes )
3234
35+
3336def _stripPrefix (text , prefix ):
3437 if text .startswith (prefix ):
3538 return text [len (prefix ):]
3639 return text
3740
3841
39- class CompletionItem (namedtuple ('CompletionItem' , ['type' , 'ident' , 'score' ])):
42+ class CompletionItem (namedtuple ('CompletionItem' , ['type' , 'ident' ])):
4043 """
4144 Represents a potential or actual completion item.
4245 * type - Type of item e.g. (Table, Function, Column)
4346 * ident - identifier e.g. ("tablename.column", "database.table", "alias")
44- * score - the lower score, the better is match for completion item
4547 """
4648 __slots__ = ()
4749
@@ -100,9 +102,10 @@ def prefixMatchScore(self, search, exactly=False):
100102 targetList = target .split ('.' )
101103 targetObject = _stripQuotes (targetList .pop ())
102104 targetParent = _stripQuotes (targetList .pop ())
103- if (searchParent == targetParent and
104- self ._stringMatched (targetObject , searchObject , exactly )):
105- return 1 # highest score
105+ if (searchParent == targetParent ):
106+ if self ._stringMatched (targetObject , searchObject , exactly ):
107+ return 1 # highest score
108+ return 0
106109
107110 # second part matches ?
108111 if '.' in target :
@@ -119,6 +122,13 @@ def prefixMatchScore(self, search, exactly=False):
119122 return 0
120123 return 0
121124
125+ def prefixMatchListScore (self , searchList , exactly = False ):
126+ for item in searchList :
127+ score = self .prefixMatchScore (item , exactly )
128+ if score :
129+ return score
130+ return 0
131+
122132 # format completion item according to sublime text completions format
123133 def format (self , stripQuotes = False ):
124134 typeDisplay = ''
@@ -147,9 +157,9 @@ def format(self, stripQuotes=False):
147157
148158class Completion :
149159 def __init__ (self , uppercaseKeywords , allTables , allColumns , allFunctions ):
150- self .allTables = [CompletionItem ('Table' , table , 0 ) for table in allTables ]
151- self .allColumns = [CompletionItem ('Column' , column , 0 ) for column in allColumns ]
152- self .allFunctions = [CompletionItem ('Function' , func , 0 ) for func in allFunctions ]
160+ self .allTables = [CompletionItem ('Table' , table ) for table in allTables ]
161+ self .allColumns = [CompletionItem ('Column' , column ) for column in allColumns ]
162+ self .allFunctions = [CompletionItem ('Function' , func ) for func in allFunctions ]
153163
154164 self .allKeywords = []
155165 for keyword in keywords_list :
@@ -158,7 +168,7 @@ def __init__(self, uppercaseKeywords, allTables, allColumns, allFunctions):
158168 else :
159169 keyword = keyword .lower ()
160170
161- self .allKeywords .append (CompletionItem ('Keyword' , keyword , 0 ))
171+ self .allKeywords .append (CompletionItem ('Keyword' , keyword ))
162172
163173 def getBasicAutoCompleteList (self , prefix ):
164174 prefix = prefix .lower ()
@@ -168,17 +178,17 @@ def getBasicAutoCompleteList(self, prefix):
168178 for item in self .allColumns :
169179 score = item .prefixMatchScore (prefix )
170180 if score :
171- autocompleteList .append (CompletionItem ( item . type , item . ident , score ) )
181+ autocompleteList .append (item )
172182
173183 for item in self .allTables :
174184 score = item .prefixMatchScore (prefix )
175185 if score :
176- autocompleteList .append (CompletionItem ( item . type , item . ident , score ) )
186+ autocompleteList .append (item )
177187
178188 for item in self .allFunctions :
179189 score = item .prefixMatchScore (prefix )
180190 if score :
181- autocompleteList .append (CompletionItem ( item . type , item . ident , score ) )
191+ autocompleteList .append (item )
182192
183193 if len (autocompleteList ) == 0 :
184194 return None
@@ -263,94 +273,93 @@ def _noDotsCompletions(self, prefix, identifiers, joinAlias=None):
263273 Order: statement aliases -> statement cols -> statement tables -> statement functions,
264274 then: other cols -> other tables -> other functions that match the prefix in their names
265275 """
266- # get join conditions
267- joinConditions = []
268- if joinAlias :
269- joinConditions = self ._joinConditionCompletions (identifiers , joinAlias )
270276
271277 # use set, as we are interested only in unique identifiers
272278 sqlAliases = set ()
273- sqlTables = set ()
274- sqlColumns = set ()
275- sqlFunctions = set ()
279+ sqlTables = []
280+ sqlColumns = []
281+ sqlFunctions = []
282+ otherTables = []
283+ otherColumns = []
284+ otherFunctions = []
285+ otherKeywords = []
286+ otherJoinConditions = []
287+
288+ # utilitary temp lists
289+ identTables = set ()
290+ identColumns = set ()
291+ identFunctions = set ()
276292
277293 for ident in identifiers :
278294 if ident .has_alias ():
279- sqlAliases .add (CompletionItem ('Alias' , ident .alias , 0 ))
295+ aliasItem = CompletionItem ('Alias' , ident .alias )
296+ score = aliasItem .prefixMatchScore (prefix )
297+ if score and aliasItem .ident != prefix :
298+ sqlAliases .add (aliasItem )
280299
281300 if ident .is_function :
282- functions = [
283- fun
284- for fun in self .allFunctions
285- if fun .prefixMatchScore (ident .full_name , exactly = True ) > 0
286- ]
287- sqlFunctions .update (functions )
288- else :
289- tables = [
290- table
291- for table in self .allTables
292- if table .prefixMatchScore (ident .full_name , exactly = True ) > 0
293- ]
294- sqlTables .update (tables )
295- prefixForColumnMatch = ident .name + '.'
296- columns = [
297- col
298- for col in self .allColumns
299- if col .prefixMatchScore (prefixForColumnMatch , exactly = True ) > 0
300- ]
301- sqlColumns .update (columns )
302-
303- autocompleteList = []
304-
305- for condition in joinConditions :
306- if condition .ident .lower ().startswith (prefix ):
307- autocompleteList .append (CompletionItem (condition .type , condition .ident , 1 ))
308-
309- # first of all list aliases and identifiers related to currently parsed statement
310- for item in sqlAliases :
311- score = item .prefixMatchScore (prefix )
312- if score and item .ident != prefix :
313- autocompleteList .append (CompletionItem (item .type , item .ident , score ))
301+ identFunctions .add (ident .full_name )
302+ elif ident .is_table_alias :
303+ identTables .add (ident .full_name )
304+ identColumns .add (ident .name + '.' + prefix )
314305
315- for item in sqlColumns :
316- score = item .prefixMatchScore (prefix )
306+ for table in self . allTables :
307+ score = table .prefixMatchScore (prefix , exactly = False )
317308 if score :
318- autocompleteList .append (CompletionItem (item .type , item .ident , score ))
309+ if table .prefixMatchListScore (identTables , exactly = True ) > 0 :
310+ sqlTables .append (table )
311+ else :
312+ otherTables .append (table )
319313
320- for item in sqlTables :
321- score = item .prefixMatchScore (prefix )
314+ for col in self . allColumns :
315+ score = col .prefixMatchScore (prefix , exactly = False )
322316 if score :
323- autocompleteList .append (CompletionItem (item .type , item .ident , score ))
317+ if col .prefixMatchListScore (identColumns , exactly = False ) > 0 :
318+ sqlColumns .append (col )
319+ else :
320+ otherColumns .append (col )
324321
325- for item in sqlFunctions :
326- score = item .prefixMatchScore (prefix )
322+ for fun in self . allFunctions :
323+ score = fun .prefixMatchScore (prefix , exactly = False )
327324 if score :
328- autocompleteList .append (CompletionItem (item .type , item .ident , score ))
325+ if fun .prefixMatchListScore (identFunctions , exactly = True ) > 0 :
326+ sqlColumns .append (fun )
327+ else :
328+ otherColumns .append (fun )
329329
330- # add keywords to auto-complete results
330+ # keywords
331331 for item in self .allKeywords :
332332 score = item .prefixMatchScore (prefix )
333333 if score :
334- autocompleteList .append (CompletionItem ( item . type , item . ident , score ) )
334+ otherKeywords .append (item )
335335
336- # add the rest of the columns, tables and functions that also match the prefix
337- for item in self .allColumns :
338- score = item .prefixMatchScore (prefix )
339- if score :
340- if item not in sqlColumns :
341- autocompleteList .append (CompletionItem (item .type , item .ident , score ))
336+ # join conditions
337+ if joinAlias :
338+ joinConditions = self ._joinConditionCompletions (identifiers , joinAlias )
342339
343- for item in self .allTables :
344- score = item .prefixMatchScore (prefix )
345- if score :
346- if item not in sqlTables :
347- autocompleteList .append (CompletionItem (item .type , item .ident , score ))
340+ for condition in joinConditions :
341+ if condition .ident .lower ().startswith (prefix ):
342+ otherJoinConditions .append (condition )
348343
349- for item in self .allFunctions :
350- score = item .prefixMatchScore (prefix )
351- if score :
352- if item not in sqlFunctions :
353- autocompleteList .append (CompletionItem (item .type , item .ident , score ))
344+ # collect the results in prefered order
345+ autocompleteList = []
346+
347+ # first of all list join conditions (if applicable)
348+ autocompleteList .extend (otherJoinConditions )
349+
350+ # then aliases and identifiers related to currently parsed statement
351+ autocompleteList .extend (sqlAliases )
352+
353+ # then cols, tables, functions related to current statement
354+ autocompleteList .extend (sqlColumns )
355+ autocompleteList .extend (sqlTables )
356+ autocompleteList .extend (sqlFunctions )
357+
358+ # then other matching cols, tables, functions
359+ autocompleteList .extend (otherKeywords )
360+ autocompleteList .extend (otherColumns )
361+ autocompleteList .extend (otherTables )
362+ autocompleteList .extend (otherFunctions )
354363
355364 return autocompleteList , False
356365
@@ -390,7 +399,7 @@ def _singleDotCompletions(self, prefix, identifiers, joinAlias=None):
390399 aliasPrefix = prefixParent + '.'
391400 if condition .ident .lower ().startswith (aliasPrefix ):
392401 autocompleteList .append (CompletionItem (condition .type ,
393- _stripPrefix (condition .ident , aliasPrefix ), 1 ))
402+ _stripPrefix (condition .ident , aliasPrefix )))
394403
395404 # first of all expand table aliases to real table names and try
396405 # to match their columns with prefix of these expanded identifiers
@@ -400,23 +409,23 @@ def _singleDotCompletions(self, prefix, identifiers, joinAlias=None):
400409 for item in self .allColumns :
401410 score = item .prefixMatchScore (prefix_to_match )
402411 if score :
403- autocompleteList .append (CompletionItem ( item . type , item . ident , score ) )
412+ autocompleteList .append (item )
404413
405414 # try to match all our other objects (tables, columns, functions) with prefix
406415 for item in self .allColumns :
407416 score = item .prefixMatchScore (prefix )
408417 if score :
409- autocompleteList .append (CompletionItem ( item . type , item . ident , score ) )
418+ autocompleteList .append (item )
410419
411420 for item in self .allTables :
412421 score = item .prefixMatchScore (prefix )
413422 if score :
414- autocompleteList .append (CompletionItem ( item . type , item . ident , score ) )
423+ autocompleteList .append (item )
415424
416425 for item in self .allFunctions :
417426 score = item .prefixMatchScore (prefix )
418427 if score :
419- autocompleteList .append (CompletionItem ( item . type , item . ident , score ) )
428+ autocompleteList .append (item )
420429
421430 inhibit = len (autocompleteList ) > 0
422431 # in case prefix parent is a query alias we simply don't know what those
@@ -432,7 +441,7 @@ def _multiDotCompletions(self, prefix, identifiers):
432441 for item in self .allColumns :
433442 score = item .prefixMatchScore (prefix )
434443 if score :
435- autocompleteList .append (CompletionItem ( item . type , item . ident , score ) )
444+ autocompleteList .append (item )
436445
437446 if len (autocompleteList ) > 0 :
438447 return autocompleteList , True
@@ -450,7 +459,7 @@ def _joinConditionCompletions(self, identifiers, joinAlias=None):
450459
451460 for ident in identifiers :
452461 if ident .has_alias () and not ident .is_function :
453- sqlTableAliases .add (CompletionItem ('Alias' , ident .alias , 0 ))
462+ sqlTableAliases .add (CompletionItem ('Alias' , ident .alias ))
454463
455464 prefixForColumnMatch = ident .name + '.'
456465 columns = [
@@ -486,7 +495,7 @@ def _joinConditionCompletions(self, identifiers, joinAlias=None):
486495 sideA = joinAlias + '.' + joinColumn .name
487496 sideB = otherAlias + '.' + otherColumn .name
488497
489- joinCandidatesCompletions .append (CompletionItem ('Condition' , sideA + ' = ' + sideB , 0 ))
490- joinCandidatesCompletions .append (CompletionItem ('Condition' , sideB + ' = ' + sideA , 0 ))
498+ joinCandidatesCompletions .append (CompletionItem ('Condition' , sideA + ' = ' + sideB ))
499+ joinCandidatesCompletions .append (CompletionItem ('Condition' , sideB + ' = ' + sideA ))
491500
492501 return joinCandidatesCompletions
0 commit comments