Skip to content
Merged
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
a4b03e9
removed parser
juleswritescode Oct 23, 2025
5f8e7b3
a little bit of support
juleswritescode Oct 23, 2025
019a3bc
ok
juleswritescode Oct 24, 2025
c34dd00
Merge branch 'main' of https://github.com/supabase-community/postgres…
juleswritescode Oct 24, 2025
2b2b637
rename, add grant grammar
juleswritescode Oct 24, 2025
15f7db1
ok ok
juleswritescode Oct 24, 2025
6e72b72
featuressss
juleswritescode Oct 24, 2025
bc477fa
refactor: remove custom NodeUnderCursor
juleswritescode Oct 25, 2025
2aa5c9f
readied
juleswritescode Oct 25, 2025
d82f7b3
ok
juleswritescode Oct 25, 2025
ce2f679
refactor: rename to any_identifier
juleswritescode Oct 25, 2025
2eca24d
ups
juleswritescode Oct 25, 2025
7a205d1
so far so good
juleswritescode Oct 25, 2025
3f610c1
use more column identifiers
juleswritescode Oct 25, 2025
37a7370
column definition does not include known columns
juleswritescode Oct 25, 2025
3adc5d8
seems about right…
juleswritescode Oct 25, 2025
0494874
tests pass!
juleswritescode Oct 25, 2025
172eaa0
uncomment
juleswritescode Oct 25, 2025
22e971a
unused
juleswritescode Oct 25, 2025
fd32486
ack
juleswritescode Oct 25, 2025
b1e5ebd
ok
juleswritescode Oct 25, 2025
c7ff064
unnecessary
juleswritescode Oct 26, 2025
feced68
remove that for now
juleswritescode Oct 26, 2025
a331f41
so far
juleswritescode Oct 26, 2025
b0336dc
intermediary
juleswritescode Oct 26, 2025
7a826bf
many intermediate yes yes
juleswritescode Oct 28, 2025
01a1456
removed parser
juleswritescode Oct 23, 2025
79cd1c3
[2] refactor: remove custom grant parser (#567)
juleswritescode Oct 28, 2025
f4de888
merge conflicts
juleswritescode Oct 28, 2025
e6452af
got it
juleswritescode Oct 28, 2025
c8c6b1b
very very cool
juleswritescode Oct 28, 2025
9182ffb
alrighty
juleswritescode Oct 28, 2025
2984f52
so far!
juleswritescode Oct 28, 2025
1fea886
ack ack
juleswritescode Oct 28, 2025
0c4ab8d
wow
juleswritescode Oct 28, 2025
3b078a0
so far
juleswritescode Oct 29, 2025
7b5b8c6
ok…
juleswritescode Oct 29, 2025
74b4cec
ok ok
juleswritescode Oct 29, 2025
5d371a7
ok
juleswritescode Oct 29, 2025
5526b43
so many changes
juleswritescode Oct 29, 2025
f58eb04
renamings
juleswritescode Oct 29, 2025
6bf8453
ack
juleswritescode Oct 29, 2025
f77c1b1
ack
juleswritescode Oct 29, 2025
06b3a17
dat wird leider n grosser
juleswritescode Oct 29, 2025
077cf68
tests green
juleswritescode Oct 30, 2025
d4df303
progres
juleswritescode Nov 1, 2025
05ad286
fix final stuff
juleswritescode Nov 1, 2025
e5422ee
readied
juleswritescode Nov 1, 2025
298f767
refactor: replace schema_or_alias
juleswritescode Nov 1, 2025
2cdb6b8
clarify
juleswritescode Nov 1, 2025
68f3645
fixie fixie
juleswritescode Nov 1, 2025
265c15d
awesome stuffings!
juleswritescode Nov 1, 2025
85c9517
whoops
juleswritescode Nov 1, 2025
c2c0f78
rebase
juleswritescode Nov 1, 2025
6467eb7
revert unnecessary changes
juleswritescode Nov 1, 2025
3f7ec89
use files from main
juleswritescode Nov 1, 2025
d08a08e
merged
juleswritescode Nov 7, 2025
962fcfd
file snapshots
juleswritescode Nov 7, 2025
646b884
[3] refactor: improve & simplify tree-sitter context-tracking (#595)
juleswritescode Nov 7, 2025
b5ff532
ready
juleswritescode Nov 7, 2025
212379b
ack
juleswritescode Nov 7, 2025
db93bfd
sql snap
juleswritescode Nov 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/pgls_completions/src/providers/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub(crate) fn with_schema_or_alias(
item_name: &str,
schema_or_alias_name: Option<&str>,
) -> String {
let is_already_prefixed_with_schema_name = ctx.schema_or_alias_name.is_some();
let is_already_prefixed_with_schema_name = ctx.has_any_qualifier();

let with_quotes = node_text_surrounded_by_quotes(ctx);
let single_leading_quote = only_leading_quote(ctx);
Expand Down
114 changes: 96 additions & 18 deletions crates/pgls_completions/src/relevance/filtering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl CompletionFilter<'_> {
pub fn is_relevant(&self, ctx: &TreesitterContext) -> Option<()> {
self.completable_context(ctx)?;

self.check_node_type(ctx)
self.check_specific_node_type(ctx)
// we want to rely on treesitter more, so checking the clause is a fallback
.or_else(|| self.check_clause(ctx))?;

Expand Down Expand Up @@ -70,6 +70,15 @@ impl CompletionFilter<'_> {
}
}

if ctx
.node_under_cursor
.as_ref()
.is_some_and(|n| n.kind() == "any_identifier")
&& ctx.matches_ancestor_history(&["alias"])
{
return None;
}

// No autocompletions if there are two identifiers without a separator.
if ctx.node_under_cursor.as_ref().is_some_and(|node| {
node.prev_sibling().is_some_and(|p| {
Expand All @@ -92,15 +101,79 @@ impl CompletionFilter<'_> {
Some(())
}

fn check_node_type(&self, ctx: &TreesitterContext) -> Option<()> {
fn check_specific_node_type(&self, ctx: &TreesitterContext) -> Option<()> {
let kind = ctx.node_under_cursor.as_ref().map(|n| n.kind())?;

let is_allowed = match kind {
"column_identifier" => {
matches!(self.data, CompletionRelevanceData::Column(_))
&& !ctx.matches_ancestor_history(&["insert_values", "field"])
&& !ctx.node_under_cursor_is_within_field_name("binary_expr_right")
"column_identifier" => matches!(self.data, CompletionRelevanceData::Column(_)),
"role_identifier" => matches!(self.data, CompletionRelevanceData::Role(_)),
"function_identifier" => matches!(self.data, CompletionRelevanceData::Function(_)),
"schema_identifier" => matches!(self.data, CompletionRelevanceData::Schema(_)),
"table_identifier" => matches!(self.data, CompletionRelevanceData::Table(_)),
"policy_identifier" => matches!(self.data, CompletionRelevanceData::Policy(_)),

"any_identifier" => {
if false || ctx.matches_ancestor_history(&["insert_values", "object_reference"]) {
false
} else {
match self.data {
CompletionRelevanceData::Column(_) => {
ctx.node_under_cursor_is_within_field_name(&[
"object_reference_1of1",
"object_reference_2of2",
"object_reference_3of3",
"column_reference_1of1",
"column_reference_2of2",
"column_reference_3of3",
]) && !ctx
.node_under_cursor_is_within_field_name(&["binary_expr_right"])
&& !ctx.matches_ancestor_history(&[
"insert_values",
"object_reference",
])
}

CompletionRelevanceData::Schema(_) => ctx
.node_under_cursor_is_within_field_name(&[
"object_reference_1of1",
"object_reference_1of2",
"object_reference_1of3",
"type_reference_1of1",
"table_reference_1of1",
"column_reference_1of1",
"column_reference_1of2",
"function_reference_1of1",
]),

CompletionRelevanceData::Function(f) => {
ctx.node_under_cursor_is_within_field_name(&[
"object_reference_1of1",
"object_reference_2of2",
"function_reference_1of1",
]) && !(ctx.matches_ancestor_history(&[
"check_or_using_clause",
"binary_expression",
"object_reference",
]) && matches!(f.kind, ProcKind::Aggregate))
}

CompletionRelevanceData::Table(_) => ctx
.node_under_cursor_is_within_field_name(&[
"object_reference_1of1",
"object_reference_1of2",
"object_reference_2of2",
"object_reference_2of3",
"table_reference_1of1",
"column_reference_1of1",
"column_reference_1of2",
"column_reference_2of2",
]),

_ => false,
}
}
}

_ => false,
};

Expand Down Expand Up @@ -216,7 +289,6 @@ impl CompletionFilter<'_> {

CompletionRelevanceData::Schema(_) => match clause {
WrappingClause::Select
| WrappingClause::From
| WrappingClause::Join { .. }
| WrappingClause::Update
| WrappingClause::Delete => true,
Expand All @@ -225,7 +297,7 @@ impl CompletionFilter<'_> {
(ctx.matches_ancestor_history(&[
"grantable_on_table",
"object_reference",
]) && ctx.schema_or_alias_name.is_none())
]) && !ctx.has_any_qualifier())
|| ctx.matches_ancestor_history(&["grantable_on_all"])
}

Expand Down Expand Up @@ -308,18 +380,24 @@ impl CompletionFilter<'_> {
}

fn check_mentioned_schema_or_alias(&self, ctx: &TreesitterContext) -> Option<()> {
if ctx.schema_or_alias_name.is_none() {
return Some(());
}

let schema_or_alias = ctx.schema_or_alias_name.as_ref().unwrap().replace('"', "");
let tail_qualifier = match ctx.tail_qualifier_sanitized() {
Some(q) => q,
None => return Some(()), // no qualifier = this check passes
};

let matches = match self.data {
CompletionRelevanceData::Table(table) => table.schema == schema_or_alias,
CompletionRelevanceData::Function(f) => f.schema == schema_or_alias,
CompletionRelevanceData::Column(col) => ctx
.get_mentioned_table_for_alias(&schema_or_alias)
.is_some_and(|t| t == &col.table_name),
CompletionRelevanceData::Table(table) => table.schema == tail_qualifier,
CompletionRelevanceData::Function(f) => f.schema == tail_qualifier,
CompletionRelevanceData::Column(col) => {
let table = ctx
.get_mentioned_table_for_alias(&tail_qualifier)
.unwrap_or(&tail_qualifier);

col.table_name == table.as_str()
&& ctx
.head_qualifier_sanitized()
.is_none_or(|schema| col.schema_name == schema.as_str())
}

// we should never allow schema suggestions if there already was one.
CompletionRelevanceData::Schema(_) => false,
Expand Down
47 changes: 30 additions & 17 deletions crates/pgls_completions/src/relevance/scoring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ impl CompletionScore<'_> {
};

let has_mentioned_tables = ctx.has_any_mentioned_relations();
let has_mentioned_schema = ctx.schema_or_alias_name.is_some();
let has_qualifier = ctx.has_any_qualifier();

self.score += match self.data {
CompletionRelevanceData::Table(_) => match clause_type {
Expand Down Expand Up @@ -122,13 +122,13 @@ impl CompletionScore<'_> {
_ => -15,
},
CompletionRelevanceData::Schema(_) => match clause_type {
WrappingClause::From if !has_mentioned_schema => 15,
WrappingClause::Join { .. } if !has_mentioned_schema => 15,
WrappingClause::Update if !has_mentioned_schema => 15,
WrappingClause::Delete if !has_mentioned_schema => 15,
WrappingClause::AlterPolicy if !has_mentioned_schema => 15,
WrappingClause::DropPolicy if !has_mentioned_schema => 15,
WrappingClause::CreatePolicy if !has_mentioned_schema => 15,
WrappingClause::From if !has_qualifier => 15,
WrappingClause::Join { .. } if !has_qualifier => 15,
WrappingClause::Update if !has_qualifier => 15,
WrappingClause::Delete if !has_qualifier => 15,
WrappingClause::AlterPolicy if !has_qualifier => 15,
WrappingClause::DropPolicy if !has_qualifier => 15,
WrappingClause::CreatePolicy if !has_qualifier => 15,
_ => -50,
},
CompletionRelevanceData::Policy(_) => match clause_type {
Expand All @@ -149,15 +149,15 @@ impl CompletionScore<'_> {
Some(wn) => wn,
};

let has_mentioned_schema = ctx.schema_or_alias_name.is_some();
let has_qualifier = ctx.has_any_qualifier();
let has_node_text = ctx
.get_node_under_cursor_content()
.is_some_and(|txt| !sanitization::is_sanitized_token(txt.as_str()));

self.score += match self.data {
CompletionRelevanceData::Table(_) => match wrapping_node {
WrappingNode::Relation if has_mentioned_schema => 15,
WrappingNode::Relation if !has_mentioned_schema => 10,
WrappingNode::Relation if has_qualifier => 15,
WrappingNode::Relation if !has_qualifier => 10,
WrappingNode::BinaryExpression => 5,
_ => -50,
},
Expand All @@ -172,8 +172,8 @@ impl CompletionScore<'_> {
_ => -15,
},
CompletionRelevanceData::Schema(_) => match wrapping_node {
WrappingNode::Relation if !has_mentioned_schema && !has_node_text => 15,
WrappingNode::Relation if !has_mentioned_schema && has_node_text => 0,
WrappingNode::Relation if !has_qualifier && !has_node_text => 15,
WrappingNode::Relation if !has_qualifier && has_node_text => 0,
_ => -50,
},
CompletionRelevanceData::Policy(_) => 0,
Expand All @@ -191,17 +191,30 @@ impl CompletionScore<'_> {
}

fn check_matches_schema(&mut self, ctx: &TreesitterContext) {
let schema_name = match ctx.schema_or_alias_name.as_ref() {
None => return,
Some(n) => n.replace('"', ""),
let schema_from_qualifier = match self.data {
CompletionRelevanceData::Table(_) | CompletionRelevanceData::Function(_) => {
ctx.tail_qualifier_sanitized()
}

CompletionRelevanceData::Column(_) | CompletionRelevanceData::Policy(_) => {
ctx.head_qualifier_sanitized()
}

CompletionRelevanceData::Schema(_) | CompletionRelevanceData::Role(_) => None,
};

if schema_from_qualifier.is_none() {
return;
}

let schema_from_qualifier = schema_from_qualifier.unwrap();

let data_schema = match self.get_schema_name() {
Some(s) => s,
None => return,
};

if schema_name == data_schema {
if schema_from_qualifier == data_schema {
self.score += 25;
} else {
self.score -= 10;
Expand Down
19 changes: 14 additions & 5 deletions crates/pgls_hover/src/hoverables/column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,21 @@ impl ContextualPriority for Column {
let mut score = 0.0;

// high score if we match the specific alias or table being referenced in the cursor context
if let Some(table_or_alias) = ctx.schema_or_alias_name.as_ref() {
if table_or_alias.replace('"', "") == self.table_name.as_str() {

if let Some(table_or_alias) = ctx.tail_qualifier_sanitized() {
let table = ctx
.get_mentioned_table_for_alias(&table_or_alias)
.unwrap_or(&table_or_alias);

if table == self.table_name.as_str()
&& ctx
.head_qualifier_sanitized()
.is_none_or(|s| self.schema_name == s.as_str())
{
score += 250.0;
} else if let Some(table_name) = ctx.get_mentioned_table_for_alias(table_or_alias) {
if table_name == self.table_name.as_str() {
score += 250.0;

if ctx.head_qualifier_sanitized().is_some() {
score += 50.0;
}
}
}
Expand Down
Loading