Skip to content

Commit 298f767

Browse files
refactor: replace schema_or_alias
1 parent 65cc053 commit 298f767

File tree

6 files changed

+69
-60
lines changed

6 files changed

+69
-60
lines changed

crates/pgls_completions/src/providers/helper.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub(crate) fn with_schema_or_alias(
4545
item_name: &str,
4646
schema_or_alias_name: Option<&str>,
4747
) -> String {
48-
let is_already_prefixed_with_schema_name = ctx.schema_or_alias_name.is_some();
48+
let is_already_prefixed_with_schema_name = matches!(ctx.identifier_qualifiers, (_, Some(_)));
4949

5050
let with_quotes = node_text_surrounded_by_quotes(ctx);
5151
let single_leading_quote = only_leading_quote(ctx);

crates/pgls_completions/src/relevance/filtering.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ impl CompletionFilter<'_> {
225225
(ctx.matches_ancestor_history(&[
226226
"grantable_on_table",
227227
"object_reference",
228-
]) && ctx.schema_or_alias_name.is_none())
228+
]) && ctx.identifier_qualifiers.1.is_none())
229229
|| ctx.matches_ancestor_history(&["grantable_on_all"])
230230
}
231231

@@ -308,17 +308,22 @@ impl CompletionFilter<'_> {
308308
}
309309

310310
fn check_mentioned_schema_or_alias(&self, ctx: &TreesitterContext) -> Option<()> {
311-
if ctx.schema_or_alias_name.is_none() {
311+
if ctx.identifier_qualifiers.1.is_none() {
312312
return Some(());
313313
}
314314

315-
let schema_or_alias = ctx.schema_or_alias_name.as_ref().unwrap().replace('"', "");
315+
let second_qualifier = ctx
316+
.identifier_qualifiers
317+
.1
318+
.as_ref()
319+
.unwrap()
320+
.replace('"', "");
316321

317322
let matches = match self.data {
318-
CompletionRelevanceData::Table(table) => table.schema == schema_or_alias,
319-
CompletionRelevanceData::Function(f) => f.schema == schema_or_alias,
323+
CompletionRelevanceData::Table(table) => table.schema == second_qualifier,
324+
CompletionRelevanceData::Function(f) => f.schema == second_qualifier,
320325
CompletionRelevanceData::Column(col) => ctx
321-
.get_mentioned_table_for_alias(&schema_or_alias)
326+
.get_mentioned_table_for_alias(&second_qualifier)
322327
.is_some_and(|t| t == &col.table_name),
323328

324329
// we should never allow schema suggestions if there already was one.

crates/pgls_completions/src/relevance/scoring.rs

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl CompletionScore<'_> {
7979
};
8080

8181
let has_mentioned_tables = ctx.has_any_mentioned_relations();
82-
let has_mentioned_schema = ctx.schema_or_alias_name.is_some();
82+
let has_qualifier = ctx.identifier_qualifiers.1.is_some();
8383

8484
self.score += match self.data {
8585
CompletionRelevanceData::Table(_) => match clause_type {
@@ -122,13 +122,13 @@ impl CompletionScore<'_> {
122122
_ => -15,
123123
},
124124
CompletionRelevanceData::Schema(_) => match clause_type {
125-
WrappingClause::From if !has_mentioned_schema => 15,
126-
WrappingClause::Join { .. } if !has_mentioned_schema => 15,
127-
WrappingClause::Update if !has_mentioned_schema => 15,
128-
WrappingClause::Delete if !has_mentioned_schema => 15,
129-
WrappingClause::AlterPolicy if !has_mentioned_schema => 15,
130-
WrappingClause::DropPolicy if !has_mentioned_schema => 15,
131-
WrappingClause::CreatePolicy if !has_mentioned_schema => 15,
125+
WrappingClause::From if !has_qualifier => 15,
126+
WrappingClause::Join { .. } if !has_qualifier => 15,
127+
WrappingClause::Update if !has_qualifier => 15,
128+
WrappingClause::Delete if !has_qualifier => 15,
129+
WrappingClause::AlterPolicy if !has_qualifier => 15,
130+
WrappingClause::DropPolicy if !has_qualifier => 15,
131+
WrappingClause::CreatePolicy if !has_qualifier => 15,
132132
_ => -50,
133133
},
134134
CompletionRelevanceData::Policy(_) => match clause_type {
@@ -149,15 +149,15 @@ impl CompletionScore<'_> {
149149
Some(wn) => wn,
150150
};
151151

152-
let has_mentioned_schema = ctx.schema_or_alias_name.is_some();
152+
let has_single_qualifier = matches!(ctx.identifier_qualifiers, (None, Some(_)));
153153
let has_node_text = ctx
154154
.get_node_under_cursor_content()
155155
.is_some_and(|txt| !sanitization::is_sanitized_token(txt.as_str()));
156156

157157
self.score += match self.data {
158158
CompletionRelevanceData::Table(_) => match wrapping_node {
159-
WrappingNode::Relation if has_mentioned_schema => 15,
160-
WrappingNode::Relation if !has_mentioned_schema => 10,
159+
WrappingNode::Relation if has_single_qualifier => 15,
160+
WrappingNode::Relation if !has_single_qualifier => 10,
161161
WrappingNode::BinaryExpression => 5,
162162
_ => -50,
163163
},
@@ -172,8 +172,8 @@ impl CompletionScore<'_> {
172172
_ => -15,
173173
},
174174
CompletionRelevanceData::Schema(_) => match wrapping_node {
175-
WrappingNode::Relation if !has_mentioned_schema && !has_node_text => 15,
176-
WrappingNode::Relation if !has_mentioned_schema && has_node_text => 0,
175+
WrappingNode::Relation if !has_single_qualifier && !has_node_text => 15,
176+
WrappingNode::Relation if !has_single_qualifier && has_node_text => 0,
177177
_ => -50,
178178
},
179179
CompletionRelevanceData::Policy(_) => 0,
@@ -191,20 +191,27 @@ impl CompletionScore<'_> {
191191
}
192192

193193
fn check_matches_schema(&mut self, ctx: &TreesitterContext) {
194-
let schema_name = match ctx.schema_or_alias_name.as_ref() {
195-
None => return,
196-
Some(n) => n.replace('"', ""),
197-
};
194+
if matches!(ctx.identifier_qualifiers, (None, None)) {
195+
return;
196+
}
197+
198+
let schema_from_qualifier = ctx
199+
.identifier_qualifiers
200+
.1
201+
.as_ref()
202+
.map(|n| n.replace('"', ""));
198203

199204
let data_schema = match self.get_schema_name() {
200205
Some(s) => s,
201206
None => return,
202207
};
203208

204-
if schema_name == data_schema {
205-
self.score += 25;
206-
} else {
207-
self.score -= 10;
209+
if let Some(schema_name) = schema_from_qualifier {
210+
if schema_name == data_schema {
211+
self.score += 25;
212+
} else {
213+
self.score -= 10;
214+
}
208215
}
209216
}
210217

crates/pgls_hover/src/hoverables/column.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl ContextualPriority for Column {
7474
let mut score = 0.0;
7575

7676
// high score if we match the specific alias or table being referenced in the cursor context
77-
if let Some(table_or_alias) = ctx.schema_or_alias_name.as_ref() {
77+
if let Some(table_or_alias) = ctx.identifier_qualifiers.1.as_ref() {
7878
if table_or_alias.replace('"', "") == self.table_name.as_str() {
7979
score += 250.0;
8080
} else if let Some(table_name) = ctx.get_mentioned_table_for_alias(table_or_alias) {

crates/pgls_hover/src/hovered_node.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ impl HoveredNode {
3535
}
3636

3737
Some(HoveredNode::Table((
38-
ctx.schema_or_alias_name.clone(),
38+
ctx.identifier_qualifiers.1.clone(),
3939
node_content,
4040
)))
4141
}
@@ -52,22 +52,22 @@ impl HoveredNode {
5252
}) =>
5353
{
5454
Some(HoveredNode::Table((
55-
ctx.schema_or_alias_name.clone(),
55+
ctx.identifier_qualifiers.1.clone(),
5656
node_content,
5757
)))
5858
}
5959

6060
"column_identifier" => Some(HoveredNode::Column((
6161
None,
62-
ctx.schema_or_alias_name.clone(),
62+
ctx.identifier_qualifiers.1.clone(),
6363
node_content,
6464
))),
6565

6666
"any_identifier"
6767
if ctx.matches_ancestor_history(&["invocation", "object_reference"]) =>
6868
{
6969
Some(HoveredNode::Function((
70-
ctx.schema_or_alias_name.clone(),
70+
ctx.identifier_qualifiers.1.clone(),
7171
node_content,
7272
)))
7373
}
@@ -103,7 +103,7 @@ impl HoveredNode {
103103
{
104104
let sanitized = node_content.replace(['(', ')'], "");
105105
Some(HoveredNode::PostgresType((
106-
ctx.schema_or_alias_name.clone(),
106+
ctx.identifier_qualifiers.1.clone(),
107107
sanitized,
108108
)))
109109
}
@@ -114,7 +114,7 @@ impl HoveredNode {
114114
}
115115

116116
"grant_table" => Some(HoveredNode::Table((
117-
ctx.schema_or_alias_name.clone(),
117+
ctx.identifier_qualifiers.1.clone(),
118118
node_content,
119119
))),
120120

crates/pgls_treesitter/src/context/mod.rs

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -101,25 +101,12 @@ pub struct TreesitterContext<'a> {
101101
pub text: &'a str,
102102
pub position: usize,
103103

104-
/// If the cursor is on a node that uses dot notation
105-
/// to specify an alias or schema, this will hold the schema's or
106-
/// alias's name.
107-
///
108-
/// Here, `auth` is a schema name:
109-
/// ```sql
110-
/// select * from auth.users;
111-
/// ```
112-
///
113-
/// Here, `u` is an alias name:
114-
/// ```sql
115-
/// select
116-
/// *
117-
/// from
118-
/// auth.users u
119-
/// left join identities i
120-
/// on u.id = i.user_id;
121-
/// ```
122-
pub schema_or_alias_name: Option<String>,
104+
/// Tuple containing up to two qualifier identifiers from dot notation.
105+
/// For example:
106+
/// - `table.column` -> (None, Some("table"))
107+
/// - `schema.table.column` -> (Some("schema"), Some("table"))
108+
/// - `column` -> (None, None)
109+
pub identifier_qualifiers: (Option<String>, Option<String>),
123110

124111
pub wrapping_clause_type: Option<WrappingClause<'a>>,
125112

@@ -140,7 +127,7 @@ impl<'a> TreesitterContext<'a> {
140127
text: params.text,
141128
position: usize::from(params.position),
142129
node_under_cursor: None,
143-
schema_or_alias_name: None,
130+
identifier_qualifiers: (None, None),
144131
wrapping_clause_type: None,
145132
wrapping_node_kind: None,
146133
wrapping_statement_range: None,
@@ -333,10 +320,20 @@ impl<'a> TreesitterContext<'a> {
333320
let content = self.get_ts_node_content(&current_node);
334321
if let Some(txt) = content {
335322
let parts: Vec<&str> = txt.split('.').collect();
336-
// we do not want to set it if we're on the schema or alias node itself
337-
let is_on_schema_node = start + parts[0].len() >= self.position;
338-
if parts.len() == 2 && !is_on_schema_node {
339-
self.schema_or_alias_name = Some(parts[0].to_string());
323+
// we do not want to set it if we're on the first qualifier itself
324+
let is_on_first_part = start + parts[0].len() >= self.position;
325+
326+
if parts.len() == 2 && !is_on_first_part {
327+
self.identifier_qualifiers = (None, Some(parts[0].to_string()));
328+
} else if parts.len() == 3 && !is_on_first_part {
329+
let is_on_second_part =
330+
start + parts[0].len() + 1 + parts[1].len() >= self.position;
331+
if !is_on_second_part {
332+
self.identifier_qualifiers =
333+
(Some(parts[0].to_string()), Some(parts[1].to_string()));
334+
} else {
335+
self.identifier_qualifiers = (None, Some(parts[0].to_string()));
336+
}
340337
}
341338
}
342339
}
@@ -926,7 +923,7 @@ mod tests {
926923
let ctx = TreesitterContext::new(params);
927924

928925
assert_eq!(
929-
ctx.schema_or_alias_name,
926+
ctx.identifier_qualifiers.1,
930927
expected_schema.map(|f| f.to_string())
931928
);
932929
}

0 commit comments

Comments
 (0)