Skip to content

Commit 827d75c

Browse files
Merge branch 'main' of https://github.com/supabase-community/postgres_lsp into feat/policy-completions
2 parents 74cbacf + 4e57995 commit 827d75c

21 files changed

+909
-25
lines changed

.sqlx/query-df57cc22f7d63847abce1d0d15675ba8951faa1be2ea6b2bf6714b1aa9127a6f.json

Lines changed: 44 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/pgt_completions/src/context/mod.rs

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
sanitization::SanitizedCompletionParams,
1616
};
1717

18-
#[derive(Debug, PartialEq, Eq)]
18+
#[derive(Debug, PartialEq, Eq, Hash)]
1919
pub enum WrappingClause<'a> {
2020
Select,
2121
Where,
@@ -29,6 +29,12 @@ pub enum WrappingClause<'a> {
2929
ToRoleAssignment,
3030
}
3131

32+
#[derive(PartialEq, Eq, Hash, Debug)]
33+
pub(crate) struct MentionedColumn {
34+
pub(crate) column: String,
35+
pub(crate) alias: Option<String>,
36+
}
37+
3238
/// We can map a few nodes, such as the "update" node, to actual SQL clauses.
3339
/// That gives us a lot of insight for completions.
3440
/// Other nodes, such as the "relation" node, gives us less but still
@@ -150,8 +156,8 @@ pub(crate) struct CompletionContext<'a> {
150156
pub is_in_error_node: bool,
151157

152158
pub mentioned_relations: HashMap<Option<String>, HashSet<String>>,
153-
154159
pub mentioned_table_aliases: HashMap<String, String>,
160+
pub mentioned_columns: HashMap<Option<WrappingClause<'a>>, HashSet<MentionedColumn>>,
155161
}
156162

157163
impl<'a> CompletionContext<'a> {
@@ -169,6 +175,7 @@ impl<'a> CompletionContext<'a> {
169175
is_invocation: false,
170176
mentioned_relations: HashMap::new(),
171177
mentioned_table_aliases: HashMap::new(),
178+
mentioned_columns: HashMap::new(),
172179
is_in_error_node: false,
173180
};
174181

@@ -223,33 +230,46 @@ impl<'a> CompletionContext<'a> {
223230

224231
executor.add_query_results::<queries::RelationMatch>();
225232
executor.add_query_results::<queries::TableAliasMatch>();
233+
executor.add_query_results::<queries::SelectColumnMatch>();
226234

227235
for relation_match in executor.get_iter(stmt_range) {
228236
match relation_match {
229237
QueryResult::Relation(r) => {
230238
let schema_name = r.get_schema(sql);
231239
let table_name = r.get_table(sql);
232240

233-
let current = self.mentioned_relations.get_mut(&schema_name);
234-
235-
match current {
236-
Some(c) => {
237-
c.insert(table_name);
238-
}
239-
None => {
240-
let mut new = HashSet::new();
241-
new.insert(table_name);
242-
self.mentioned_relations.insert(schema_name, new);
243-
}
244-
};
241+
if let Some(c) = self.mentioned_relations.get_mut(&schema_name) {
242+
c.insert(table_name);
243+
} else {
244+
let mut new = HashSet::new();
245+
new.insert(table_name);
246+
self.mentioned_relations.insert(schema_name, new);
247+
}
245248
}
246-
247249
QueryResult::TableAliases(table_alias_match) => {
248250
self.mentioned_table_aliases.insert(
249251
table_alias_match.get_alias(sql),
250252
table_alias_match.get_table(sql),
251253
);
252254
}
255+
QueryResult::SelectClauseColumns(c) => {
256+
let mentioned = MentionedColumn {
257+
column: c.get_column(sql),
258+
alias: c.get_alias(sql),
259+
};
260+
261+
if let Some(cols) = self
262+
.mentioned_columns
263+
.get_mut(&Some(WrappingClause::Select))
264+
{
265+
cols.insert(mentioned);
266+
} else {
267+
let mut new = HashSet::new();
268+
new.insert(mentioned);
269+
self.mentioned_columns
270+
.insert(Some(WrappingClause::Select), new);
271+
}
272+
}
253273
};
254274
}
255275
}

crates/pgt_completions/src/providers/columns.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)