11use crate :: {
22 CompletionItemKind ,
33 builder:: { CompletionBuilder , PossibleCompletionItem } ,
4- context:: CompletionContext ,
4+ context:: { CompletionContext , WrappingClause } ,
55 relevance:: { CompletionRelevanceData , filtering:: CompletionFilter , scoring:: CompletionScore } ,
66} ;
77
8+ use super :: helper:: { find_matching_alias_for_table, get_completion_text_with_schema_or_alias} ;
9+
810pub fn complete_columns < ' a > ( ctx : & CompletionContext < ' a > , builder : & mut CompletionBuilder < ' a > ) {
911 let available_columns = & ctx. schema_cache . columns ;
1012
1113 for col in available_columns {
1214 let relevance = CompletionRelevanceData :: Column ( col) ;
1315
14- let item = PossibleCompletionItem {
16+ let mut item = PossibleCompletionItem {
1517 label : col. name . clone ( ) ,
1618 score : CompletionScore :: from ( relevance. clone ( ) ) ,
1719 filter : CompletionFilter :: from ( relevance) ,
@@ -20,6 +22,14 @@ pub fn complete_columns<'a>(ctx: &CompletionContext<'a>, builder: &mut Completio
2022 completion_text : None ,
2123 } ;
2224
25+ // autocomplete with the alias in a join clause if we find one
26+ if matches ! ( ctx. wrapping_clause_type, Some ( WrappingClause :: Join { .. } ) ) {
27+ item. completion_text = find_matching_alias_for_table ( ctx, col. table_name . as_str ( ) )
28+ . and_then ( |alias| {
29+ get_completion_text_with_schema_or_alias ( ctx, col. name . as_str ( ) , alias. as_str ( ) )
30+ } ) ;
31+ }
32+
2333 builder. add_item ( item) ;
2434 }
2535}
@@ -273,60 +283,50 @@ mod tests {
273283 id1 serial primary key,
274284 name1 text,
275285 address1 text,
276- email1 text
286+ email1 text,
287+ user_settings jsonb
277288 );
278289
279290 create table public.users (
280291 id2 serial primary key,
281292 name2 text,
282293 address2 text,
283- email2 text
294+ email2 text,
295+ settings jsonb
284296 );
285297 "# ;
286298
287- {
288- let test_case = TestCase {
289- message : "" ,
290- query : format ! ( r#"select {} from users"# , CURSOR_POS ) ,
291- label : "suggests from table" ,
292- description : "" ,
293- } ;
294-
295- let ( tree, cache) = get_test_deps ( setup, test_case. get_input_query ( ) ) . await ;
296- let params = get_test_params ( & tree, & cache, test_case. get_input_query ( ) ) ;
297- let results = complete ( params) ;
298-
299- assert_eq ! (
300- results
301- . into_iter( )
302- . take( 4 )
303- . map( |item| item. label)
304- . collect:: <Vec <String >>( ) ,
305- vec![ "address2" , "email2" , "id2" , "name2" ]
306- ) ;
307- }
308-
309- {
310- let test_case = TestCase {
311- message : "" ,
312- query : format ! ( r#"select {} from private.users"# , CURSOR_POS ) ,
313- label : "suggests from table" ,
314- description : "" ,
315- } ;
299+ assert_complete_results (
300+ format ! ( r#"select {} from users"# , CURSOR_POS ) . as_str ( ) ,
301+ vec ! [
302+ CompletionAssertion :: Label ( "address2" . into( ) ) ,
303+ CompletionAssertion :: Label ( "email2" . into( ) ) ,
304+ CompletionAssertion :: Label ( "id2" . into( ) ) ,
305+ CompletionAssertion :: Label ( "name2" . into( ) ) ,
306+ ] ,
307+ setup,
308+ )
309+ . await ;
316310
317- let ( tree, cache) = get_test_deps ( setup, test_case. get_input_query ( ) ) . await ;
318- let params = get_test_params ( & tree, & cache, test_case. get_input_query ( ) ) ;
319- let results = complete ( params) ;
311+ assert_complete_results (
312+ format ! ( r#"select {} from private.users"# , CURSOR_POS ) . as_str ( ) ,
313+ vec ! [
314+ CompletionAssertion :: Label ( "address1" . into( ) ) ,
315+ CompletionAssertion :: Label ( "email1" . into( ) ) ,
316+ CompletionAssertion :: Label ( "id1" . into( ) ) ,
317+ CompletionAssertion :: Label ( "name1" . into( ) ) ,
318+ ] ,
319+ setup,
320+ )
321+ . await ;
320322
321- assert_eq ! (
322- results
323- . into_iter( )
324- . take( 4 )
325- . map( |item| item. label)
326- . collect:: <Vec <String >>( ) ,
327- vec![ "address1" , "email1" , "id1" , "name1" ]
328- ) ;
329- }
323+ // asserts fuzzy finding for "settings"
324+ assert_complete_results (
325+ format ! ( r#"select sett{} from private.users"# , CURSOR_POS ) . as_str ( ) ,
326+ vec ! [ CompletionAssertion :: Label ( "user_settings" . into( ) ) ] ,
327+ setup,
328+ )
329+ . await ;
330330 }
331331
332332 #[ tokio:: test]
@@ -484,4 +484,93 @@ mod tests {
484484 )
485485 . await ;
486486 }
487+
488+ #[ tokio:: test]
489+ async fn prefers_not_mentioned_columns ( ) {
490+ let setup = r#"
491+ create schema auth;
492+
493+ create table public.one (
494+ id serial primary key,
495+ a text,
496+ b text,
497+ z text
498+ );
499+
500+ create table public.two (
501+ id serial primary key,
502+ c text,
503+ d text,
504+ e text
505+ );
506+ "# ;
507+
508+ assert_complete_results (
509+ format ! (
510+ "select {} from public.one o join public.two on o.id = t.id;" ,
511+ CURSOR_POS
512+ )
513+ . as_str ( ) ,
514+ vec ! [
515+ CompletionAssertion :: Label ( "a" . to_string( ) ) ,
516+ CompletionAssertion :: Label ( "b" . to_string( ) ) ,
517+ CompletionAssertion :: Label ( "c" . to_string( ) ) ,
518+ CompletionAssertion :: Label ( "d" . to_string( ) ) ,
519+ CompletionAssertion :: Label ( "e" . to_string( ) ) ,
520+ ] ,
521+ setup,
522+ )
523+ . await ;
524+
525+ // "a" is already mentioned, so it jumps down
526+ assert_complete_results (
527+ format ! (
528+ "select a, {} from public.one o join public.two on o.id = t.id;" ,
529+ CURSOR_POS
530+ )
531+ . as_str ( ) ,
532+ vec ! [
533+ CompletionAssertion :: Label ( "b" . to_string( ) ) ,
534+ CompletionAssertion :: Label ( "c" . to_string( ) ) ,
535+ CompletionAssertion :: Label ( "d" . to_string( ) ) ,
536+ CompletionAssertion :: Label ( "e" . to_string( ) ) ,
537+ CompletionAssertion :: Label ( "id" . to_string( ) ) ,
538+ CompletionAssertion :: Label ( "z" . to_string( ) ) ,
539+ CompletionAssertion :: Label ( "a" . to_string( ) ) ,
540+ ] ,
541+ setup,
542+ )
543+ . await ;
544+
545+ // "id" of table one is mentioned, but table two isn't –
546+ // its priority stays up
547+ assert_complete_results (
548+ format ! (
549+ "select o.id, a, b, c, d, e, {} from public.one o join public.two on o.id = t.id;" ,
550+ CURSOR_POS
551+ )
552+ . as_str ( ) ,
553+ vec ! [
554+ CompletionAssertion :: LabelAndDesc (
555+ "id" . to_string( ) ,
556+ "Table: public.two" . to_string( ) ,
557+ ) ,
558+ CompletionAssertion :: Label ( "z" . to_string( ) ) ,
559+ ] ,
560+ setup,
561+ )
562+ . await ;
563+
564+ // "id" is ambiguous, so both "id" columns are lowered in priority
565+ assert_complete_results (
566+ format ! (
567+ "select id, a, b, c, d, e, {} from public.one o join public.two on o.id = t.id;" ,
568+ CURSOR_POS
569+ )
570+ . as_str ( ) ,
571+ vec ! [ CompletionAssertion :: Label ( "z" . to_string( ) ) ] ,
572+ setup,
573+ )
574+ . await ;
575+ }
487576}
0 commit comments