From 7a205d10edabe8b460441af2b5125a2f82eecc59 Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 25 Oct 2025 11:27:59 +0200 Subject: [PATCH 01/11] so far so good --- crates/pgt_hover/src/hovered_node.rs | 2 +- .../pgt_treesitter/src/queries/parameters.rs | 2 +- .../src/queries/select_columns.rs | 2 +- .../src/queries/where_columns.rs | 2 +- crates/pgt_treesitter_grammar/grammar.js | 25 ++++++------------- 5 files changed, 11 insertions(+), 22 deletions(-) diff --git a/crates/pgt_hover/src/hovered_node.rs b/crates/pgt_hover/src/hovered_node.rs index bc13d07c1..322ca9281 100644 --- a/crates/pgt_hover/src/hovered_node.rs +++ b/crates/pgt_hover/src/hovered_node.rs @@ -73,7 +73,7 @@ impl HoveredNode { } } - "any_identifier" if ctx.matches_ancestor_history(&["field"]) => { + "column_identifier" => { if let Some(table_or_alias) = ctx.schema_or_alias_name.as_ref() { Some(HoveredNode::Column(NodeIdentification::SchemaAndName(( table_or_alias.clone(), diff --git a/crates/pgt_treesitter/src/queries/parameters.rs b/crates/pgt_treesitter/src/queries/parameters.rs index fdfb98a56..cab7b11eb 100644 --- a/crates/pgt_treesitter/src/queries/parameters.rs +++ b/crates/pgt_treesitter/src/queries/parameters.rs @@ -11,7 +11,7 @@ static TS_QUERY: LazyLock = LazyLock::new(|| { [ (field (field_qualifier)? - (any_identifier) + (column_identifier) ) @reference (parameter) @parameter diff --git a/crates/pgt_treesitter/src/queries/select_columns.rs b/crates/pgt_treesitter/src/queries/select_columns.rs index 5b8ee6dfa..c1835fe32 100644 --- a/crates/pgt_treesitter/src/queries/select_columns.rs +++ b/crates/pgt_treesitter/src/queries/select_columns.rs @@ -14,7 +14,7 @@ static TS_QUERY: LazyLock = LazyLock::new(|| { (object_reference) @alias "." )? - (any_identifier) @column + (column_identifier) @column ) ) ","? diff --git a/crates/pgt_treesitter/src/queries/where_columns.rs b/crates/pgt_treesitter/src/queries/where_columns.rs index 62e9e0a5c..bf9fda4a4 100644 --- a/crates/pgt_treesitter/src/queries/where_columns.rs +++ b/crates/pgt_treesitter/src/queries/where_columns.rs @@ -16,7 +16,7 @@ static TS_QUERY: LazyLock = LazyLock::new(|| { (object_reference) @alias "." )? - (any_identifier) @column + (column_identifier) @column ) ) ) diff --git a/crates/pgt_treesitter_grammar/grammar.js b/crates/pgt_treesitter_grammar/grammar.js index 23875fcd2..b2e8b4668 100644 --- a/crates/pgt_treesitter_grammar/grammar.js +++ b/crates/pgt_treesitter_grammar/grammar.js @@ -28,6 +28,7 @@ module.exports = grammar({ [$.time], [$.timestamp], [$.grantable_on_function, $.grantable_on_table], + [$.any_identifier, $.column_identifier], ], precedences: ($) => [ @@ -779,21 +780,7 @@ module.exports = grammar({ ), _show_statement: ($) => - seq( - $.keyword_show, - choice( - $._show_create, - $.keyword_all, // Postgres - $._show_tables // trino/presto - ) - ), - - _show_tables: ($) => - seq( - $.keyword_tables, - optional(seq($.keyword_from, $._qualified_field)), - optional(seq($.keyword_like, $._expression)) - ), + seq($.keyword_show, choice($._show_create, $.keyword_all)), _show_create: ($) => seq( @@ -2363,7 +2350,7 @@ module.exports = grammar({ _column_list: ($) => paren_list(alias($._column, $.column), true), _column: ($) => - choice($.any_identifier, alias($._literal_string, $.literal)), + choice($.column_identifier, alias($._literal_string, $.literal)), _update_statement: ($) => seq($.update, optional($.returning)), @@ -2834,10 +2821,10 @@ module.exports = grammar({ $.keyword_end ), - field: ($) => field("name", $.any_identifier), + field: ($) => field("name", $.column_identifier), _qualified_field: ($) => - seq(optional($.field_qualifier), field("name", $.any_identifier)), + seq(optional($.field_qualifier), $.column_identifier), field_qualifier: ($) => seq(prec.left(optional_parenthesis($.object_reference)), "."), @@ -3531,6 +3518,8 @@ module.exports = grammar({ bang: (_) => "!", any_identifier: ($) => $._any_identifier, + column_identifier: ($) => $._any_identifier, + _any_identifier: ($) => choice( $._identifier, From 3f610c18e1bcddcd22f7b330606aadd7c09ce8ca Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 25 Oct 2025 11:50:05 +0200 Subject: [PATCH 02/11] use more column identifiers --- crates/pgt_treesitter_grammar/grammar.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/crates/pgt_treesitter_grammar/grammar.js b/crates/pgt_treesitter_grammar/grammar.js index b2e8b4668..5b04182ae 100644 --- a/crates/pgt_treesitter_grammar/grammar.js +++ b/crates/pgt_treesitter_grammar/grammar.js @@ -1643,7 +1643,7 @@ module.exports = grammar({ $.keyword_insert, seq( $.keyword_update, - optional(seq($.keyword_of, comma_list($.any_identifier, true))) + optional(seq($.keyword_of, comma_list($.column_identifier, true))) ), $.keyword_delete, $.keyword_truncate @@ -1781,7 +1781,7 @@ module.exports = grammar({ // TODO constraint management $.keyword_alter, optional($.keyword_column), - field("name", $.any_identifier), + $.column_identifier, choice( seq( choice($.keyword_set, $.keyword_drop), @@ -1833,30 +1833,27 @@ module.exports = grammar({ $.keyword_change, optional($.keyword_column), optional($._if_exists), - field("old_name", $.any_identifier), + $.column_identifier, $.column_definition, optional($.column_position) ), column_position: ($) => - choice( - $.keyword_first, - seq($.keyword_after, field("col_name", $.any_identifier)) - ), + choice($.keyword_first, seq($.keyword_after, $.column_identifier)), drop_column: ($) => seq( $.keyword_drop, optional($.keyword_column), optional($._if_exists), - field("name", $.any_identifier) + $.column_identifier ), rename_column: ($) => seq( $.keyword_rename, optional($.keyword_column), - field("old_name", $.any_identifier), + $.column_identifier, $.keyword_to, field("new_name", $.any_identifier) ), @@ -2558,6 +2555,7 @@ module.exports = grammar({ ) ), + // todo(@juleswritescode): does this exist in postgresql? table_sort: ($) => seq($.keyword_sort, $.keyword_by, paren_list($.any_identifier, true)), @@ -2657,7 +2655,7 @@ module.exports = grammar({ seq( $.keyword_references, $.object_reference, - paren_list($.any_identifier, true), + paren_list($.column_identifier, true), repeat( seq( $.keyword_on, @@ -2669,6 +2667,7 @@ module.exports = grammar({ seq( $.keyword_set, choice($.keyword_null, $.keyword_default), + // todo(@juleswritescode): are these columns? optional(paren_list($.any_identifier, true)) ) ) @@ -2762,6 +2761,7 @@ module.exports = grammar({ seq( $.keyword_references, $.object_reference, + // todo(@juleswritescode): are these columns? paren_list($.any_identifier, true), repeat( seq( @@ -2774,6 +2774,7 @@ module.exports = grammar({ seq( $.keyword_set, choice($.keyword_null, $.keyword_default), + // todo(@juleswritescode): are these columns? optional(paren_list($.any_identifier, true)) ) ) @@ -3045,6 +3046,7 @@ module.exports = grammar({ seq( $.keyword_as, field("alias", $.any_identifier), + // todo(@juleswritescode): are these columns? paren_list($.any_identifier, false) ) ) From 37a73701e653ebb9931ae4ed3b2e99867f06f9d5 Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 25 Oct 2025 17:34:33 +0200 Subject: [PATCH 03/11] column definition does not include known columns --- .../src/relevance/filtering.rs | 17 +++++++++++++- crates/pgt_treesitter_grammar/grammar.js | 23 +------------------ 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/crates/pgt_completions/src/relevance/filtering.rs b/crates/pgt_completions/src/relevance/filtering.rs index 916384ef8..ff643175f 100644 --- a/crates/pgt_completions/src/relevance/filtering.rs +++ b/crates/pgt_completions/src/relevance/filtering.rs @@ -17,7 +17,11 @@ impl<'a> From> for CompletionFilter<'a> { impl CompletionFilter<'_> { pub fn is_relevant(&self, ctx: &TreesitterContext) -> Option<()> { self.completable_context(ctx)?; - self.check_clause(ctx)?; + + self.check_node_type(ctx) + // we want to rely on treesitter more, so checking the clause is a fallback + .or_else(|| self.check_clause(ctx))?; + self.check_invocation(ctx)?; self.check_mentioned_schema_or_alias(ctx)?; @@ -88,6 +92,17 @@ impl CompletionFilter<'_> { Some(()) } + fn check_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(_)), + _ => false, + }; + + if is_allowed { Some(()) } else { None } + } + fn check_clause(&self, ctx: &TreesitterContext) -> Option<()> { ctx.wrapping_clause_type .as_ref() diff --git a/crates/pgt_treesitter_grammar/grammar.js b/crates/pgt_treesitter_grammar/grammar.js index 5b04182ae..fbf41b294 100644 --- a/crates/pgt_treesitter_grammar/grammar.js +++ b/crates/pgt_treesitter_grammar/grammar.js @@ -1739,8 +1739,6 @@ module.exports = grammar({ $.add_constraint, $.drop_constraint, $.alter_column, - $.modify_column, - $.change_column, $.drop_column, $.rename_object, $.rename_column, @@ -1819,25 +1817,6 @@ module.exports = grammar({ ) ), - modify_column: ($) => - seq( - $.keyword_modify, - optional($.keyword_column), - optional($._if_exists), - $.column_definition, - optional($.column_position) - ), - - change_column: ($) => - seq( - $.keyword_change, - optional($.keyword_column), - optional($._if_exists), - $.column_identifier, - $.column_definition, - optional($.column_position) - ), - column_position: ($) => choice($.keyword_first, seq($.keyword_after, $.column_identifier)), @@ -2640,7 +2619,7 @@ module.exports = grammar({ column_definition: ($) => seq( - field("name", $._column), + $.any_identifier, field("type", $.type), repeat($._column_constraint) ), From 3adc5d8d6ac2cf0f227cd50bb4d4940b820aa657 Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 25 Oct 2025 18:24:18 +0200 Subject: [PATCH 04/11] =?UTF-8?q?seems=20about=20right=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pgt_completions/src/providers/columns.rs | 2 +- .../src/relevance/filtering.rs | 5 +- crates/pgt_treesitter/src/context/mod.rs | 5 +- crates/pgt_treesitter_grammar/grammar.js | 85 +++++++++++-------- 4 files changed, 58 insertions(+), 39 deletions(-) diff --git a/crates/pgt_completions/src/providers/columns.rs b/crates/pgt_completions/src/providers/columns.rs index 1f404627c..bab68e34a 100644 --- a/crates/pgt_completions/src/providers/columns.rs +++ b/crates/pgt_completions/src/providers/columns.rs @@ -403,7 +403,7 @@ mod tests { pool.execute(setup).await.unwrap(); - // test in SELECT clause + // // test in SELECT clause assert_complete_results( format!( "select u.id, p.{} from auth.users u join auth.posts p on u.id = p.user_id;", diff --git a/crates/pgt_completions/src/relevance/filtering.rs b/crates/pgt_completions/src/relevance/filtering.rs index ff643175f..f49c88d7f 100644 --- a/crates/pgt_completions/src/relevance/filtering.rs +++ b/crates/pgt_completions/src/relevance/filtering.rs @@ -96,7 +96,10 @@ impl CompletionFilter<'_> { let kind = ctx.node_under_cursor.as_ref().map(|n| n.kind())?; let is_allowed = match kind { - "column_identifier" => matches!(self.data, CompletionRelevanceData::Column(_)), + "column_identifier" => { + matches!(self.data, CompletionRelevanceData::Column(_)) + && !ctx.matches_ancestor_history(&["insert_values", "field"]) + } _ => false, }; diff --git a/crates/pgt_treesitter/src/context/mod.rs b/crates/pgt_treesitter/src/context/mod.rs index 381c06b62..beba7c385 100644 --- a/crates/pgt_treesitter/src/context/mod.rs +++ b/crates/pgt_treesitter/src/context/mod.rs @@ -153,6 +153,8 @@ impl<'a> TreesitterContext<'a> { ctx.gather_tree_context(); ctx.gather_info_from_ts_queries(); + println!("{:#?}", ctx); + ctx } @@ -590,8 +592,7 @@ impl<'a> TreesitterContext<'a> { // `node.child_by_field_id(..)` does not work as expected let mut on_node = None; for child in node.children(cursor) { - // 28 is the id for "keyword_on" - if child.kind_id() == 28 { + if child.kind() == "keyword_on" { on_node = Some(child); } } diff --git a/crates/pgt_treesitter_grammar/grammar.js b/crates/pgt_treesitter_grammar/grammar.js index fbf41b294..707103c45 100644 --- a/crates/pgt_treesitter_grammar/grammar.js +++ b/crates/pgt_treesitter_grammar/grammar.js @@ -264,6 +264,8 @@ module.exports = grammar({ keyword_storage: (_) => make_keyword("storage"), keyword_compression: (_) => make_keyword("compression"), + keyword_overriding: () => make_keyword("overriding"), + keyword_system: () => make_keyword("system"), keyword_policy: (_) => make_keyword("policy"), keyword_permissive: (_) => make_keyword("permissive"), keyword_restrictive: (_) => make_keyword("restrictive"), @@ -2269,33 +2271,40 @@ module.exports = grammar({ insert: ($) => seq( - choice($.keyword_insert, $.keyword_replace), + $.keyword_insert, + $.keyword_into, + $.object_reference, + optional($._alias), + optional(paren_list($.column_identifier, true)), optional( - choice( - $.keyword_low_priority, - $.keyword_delayed, - $.keyword_high_priority + seq( + $.keyword_overriding, + choice($.keyword_user, $.keyword_system), + $.keyword_value ) ), - optional($.keyword_ignore), - optional( - choice( - $.keyword_into, - $.keyword_overwrite // Spark SQL - ) + choice( + seq($.keyword_default, $.keyword_values), + $.insert_values, + $._select_statement ), - $.object_reference, - optional($.table_partition), // Spark SQL - optional(seq($.keyword_as, field("alias", $.any_identifier))), - // TODO we need a test for `insert...set` - choice($._insert_values, $._set_values), - optional(choice($._on_conflict, $._on_duplicate_key_update)) + optional($._on_conflict) + ), + + insert_values: ($) => + comma_list( + seq( + $.keyword_values, + paren_list(choice($._expression, $.keyword_default), true) + ), + true ), _on_conflict: ($) => seq( $.keyword_on, $.keyword_conflict, + // todo: conflict target seq( $.keyword_do, choice( @@ -2305,23 +2314,8 @@ module.exports = grammar({ ) ), - _on_duplicate_key_update: ($) => - seq( - $.keyword_on, - $.keyword_duplicate, - $.keyword_key, - $.keyword_update, - $.assignment_list - ), - assignment_list: ($) => seq($.assignment, repeat(seq(",", $.assignment))), - _insert_values: ($) => - seq( - optional(alias($._column_list, $.list)), - choice(seq($.keyword_values, comma_list($.list, true)), $._dml_read) - ), - _set_values: ($) => seq($.keyword_set, comma_list($.assignment, true)), _column_list: ($) => paren_list(alias($._column, $.column), true), @@ -2357,10 +2351,31 @@ module.exports = grammar({ ), $.keyword_then, choice( - $.keyword_delete, + // merge_insert + seq( + $.keyword_insert, + optional(paren_list($.column_identifier, true)), + optional( + seq( + $.keyword_overriding, + choice($.keyword_system, $.keyword_user), + $.keyword_value + ) + ), + choice( + seq($.keyword_default, $.keyword_values), + seq( + $.keyword_values, + paren_list(choice($._expression, $.keyword_default), true) + ) + ) + ), + // merge_update seq($.keyword_update, $._set_values), - seq($.keyword_insert, $._insert_values), - optional($.where) + // merge_delete + $.keyword_delete, + + seq($.keyword_do, $.keyword_nothing) ) ), From 0494874e8c6ab6a58d9953981a491d20740d8fd7 Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 25 Oct 2025 18:48:25 +0200 Subject: [PATCH 05/11] tests pass! --- .../pgt_completions/src/providers/columns.rs | 98 +++++++++---------- .../src/relevance/filtering.rs | 1 + crates/pgt_treesitter/src/context/mod.rs | 2 - .../src/queries/insert_columns.rs | 10 +- crates/pgt_treesitter_grammar/grammar.js | 22 +++-- 5 files changed, 64 insertions(+), 69 deletions(-) diff --git a/crates/pgt_completions/src/providers/columns.rs b/crates/pgt_completions/src/providers/columns.rs index bab68e34a..df02a24f7 100644 --- a/crates/pgt_completions/src/providers/columns.rs +++ b/crates/pgt_completions/src/providers/columns.rs @@ -750,22 +750,22 @@ mod tests { pool.execute(setup).await.unwrap(); - assert_complete_results( - format!( - "select name from instruments where {} ", - QueryWithCursorPosition::cursor_marker() - ) - .as_str(), - vec![ - CompletionAssertion::Label("created_at".into()), - CompletionAssertion::Label("id".into()), - CompletionAssertion::Label("name".into()), - CompletionAssertion::Label("z".into()), - ], - None, - &pool, - ) - .await; + // assert_complete_results( + // format!( + // "select name from instruments where {} ", + // QueryWithCursorPosition::cursor_marker() + // ) + // .as_str(), + // vec![ + // CompletionAssertion::Label("created_at".into()), + // CompletionAssertion::Label("id".into()), + // CompletionAssertion::Label("name".into()), + // CompletionAssertion::Label("z".into()), + // ], + // None, + // &pool, + // ) + // .await; assert_complete_results( format!( @@ -783,39 +783,39 @@ mod tests { ) .await; - // prefers not mentioned columns - assert_complete_results( - format!( - "select name from instruments where id = 'something' and {}", - QueryWithCursorPosition::cursor_marker() - ) - .as_str(), - vec![ - CompletionAssertion::Label("created_at".into()), - CompletionAssertion::Label("name".into()), - CompletionAssertion::Label("z".into()), - ], - None, - &pool, - ) - .await; - - // // uses aliases - assert_complete_results( - format!( - "select name from instruments i join others o on i.z = o.a where i.{}", - QueryWithCursorPosition::cursor_marker() - ) - .as_str(), - vec![ - CompletionAssertion::Label("created_at".into()), - CompletionAssertion::Label("id".into()), - CompletionAssertion::Label("name".into()), - ], - None, - &pool, - ) - .await; + // // prefers not mentioned columns + // assert_complete_results( + // format!( + // "select name from instruments where id = 'something' and {}", + // QueryWithCursorPosition::cursor_marker() + // ) + // .as_str(), + // vec![ + // CompletionAssertion::Label("created_at".into()), + // CompletionAssertion::Label("name".into()), + // CompletionAssertion::Label("z".into()), + // ], + // None, + // &pool, + // ) + // .await; + + // // // uses aliases + // assert_complete_results( + // format!( + // "select name from instruments i join others o on i.z = o.a where i.{}", + // QueryWithCursorPosition::cursor_marker() + // ) + // .as_str(), + // vec![ + // CompletionAssertion::Label("created_at".into()), + // CompletionAssertion::Label("id".into()), + // CompletionAssertion::Label("name".into()), + // ], + // None, + // &pool, + // ) + // .await; } #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")] diff --git a/crates/pgt_completions/src/relevance/filtering.rs b/crates/pgt_completions/src/relevance/filtering.rs index f49c88d7f..42962782a 100644 --- a/crates/pgt_completions/src/relevance/filtering.rs +++ b/crates/pgt_completions/src/relevance/filtering.rs @@ -99,6 +99,7 @@ impl CompletionFilter<'_> { "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") } _ => false, }; diff --git a/crates/pgt_treesitter/src/context/mod.rs b/crates/pgt_treesitter/src/context/mod.rs index beba7c385..84d2b5d06 100644 --- a/crates/pgt_treesitter/src/context/mod.rs +++ b/crates/pgt_treesitter/src/context/mod.rs @@ -153,8 +153,6 @@ impl<'a> TreesitterContext<'a> { ctx.gather_tree_context(); ctx.gather_info_from_ts_queries(); - println!("{:#?}", ctx); - ctx } diff --git a/crates/pgt_treesitter/src/queries/insert_columns.rs b/crates/pgt_treesitter/src/queries/insert_columns.rs index e80718321..a46ab7b86 100644 --- a/crates/pgt_treesitter/src/queries/insert_columns.rs +++ b/crates/pgt_treesitter/src/queries/insert_columns.rs @@ -7,14 +7,8 @@ use super::QueryTryFrom; static TS_QUERY: LazyLock = LazyLock::new(|| { static QUERY_STR: &str = r#" - (insert - (object_reference) - (list - "("? - (column) @column - ","? - ")"? - ) + (insert_columns + (column_identifier) @column ) "#; tree_sitter::Query::new(&pgt_treesitter_grammar::LANGUAGE.into(), QUERY_STR) diff --git a/crates/pgt_treesitter_grammar/grammar.js b/crates/pgt_treesitter_grammar/grammar.js index 707103c45..7db60eac1 100644 --- a/crates/pgt_treesitter_grammar/grammar.js +++ b/crates/pgt_treesitter_grammar/grammar.js @@ -2275,7 +2275,7 @@ module.exports = grammar({ $.keyword_into, $.object_reference, optional($._alias), - optional(paren_list($.column_identifier, true)), + optional($.insert_columns), optional( seq( $.keyword_overriding, @@ -2300,6 +2300,8 @@ module.exports = grammar({ true ), + insert_columns: ($) => paren_list($.column_identifier, true), + _on_conflict: ($) => seq( $.keyword_on, @@ -3382,9 +3384,9 @@ module.exports = grammar({ prec.left( precedence, seq( - field("left", $._expression), - field("operator", operator), - field("right", $._expression) + field("binary_expr_left", $._expression), + field("binary_expr_operator", operator), + field("binary_expr_right", $._expression) ) ) ), @@ -3392,9 +3394,9 @@ module.exports = grammar({ prec.left( precedence, seq( - field("left", $._expression), - field("operator", operator), - field("right", $._expression) + field("binary_expr_left", $._expression), + field("binary_expr_operator", operator), + field("binary_expr_right", $._expression) ) ) ), @@ -3402,9 +3404,9 @@ module.exports = grammar({ prec.left( precedence, seq( - field("left", $._expression), - field("operator", operator), - field("right", choice($.list, $.subquery)) + field("binary_expr_left", $._expression), + field("binary_expr_operator", operator), + field("binary_expr_right", choice($.list, $.subquery)) ) ) ) From 172eaa0d82fd4a810ef8b4e62a8e59ae63b48257 Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 25 Oct 2025 19:02:26 +0200 Subject: [PATCH 06/11] uncomment --- .../pgt_completions/src/providers/columns.rs | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/crates/pgt_completions/src/providers/columns.rs b/crates/pgt_completions/src/providers/columns.rs index df02a24f7..1f404627c 100644 --- a/crates/pgt_completions/src/providers/columns.rs +++ b/crates/pgt_completions/src/providers/columns.rs @@ -403,7 +403,7 @@ mod tests { pool.execute(setup).await.unwrap(); - // // test in SELECT clause + // test in SELECT clause assert_complete_results( format!( "select u.id, p.{} from auth.users u join auth.posts p on u.id = p.user_id;", @@ -750,22 +750,22 @@ mod tests { pool.execute(setup).await.unwrap(); - // assert_complete_results( - // format!( - // "select name from instruments where {} ", - // QueryWithCursorPosition::cursor_marker() - // ) - // .as_str(), - // vec![ - // CompletionAssertion::Label("created_at".into()), - // CompletionAssertion::Label("id".into()), - // CompletionAssertion::Label("name".into()), - // CompletionAssertion::Label("z".into()), - // ], - // None, - // &pool, - // ) - // .await; + assert_complete_results( + format!( + "select name from instruments where {} ", + QueryWithCursorPosition::cursor_marker() + ) + .as_str(), + vec![ + CompletionAssertion::Label("created_at".into()), + CompletionAssertion::Label("id".into()), + CompletionAssertion::Label("name".into()), + CompletionAssertion::Label("z".into()), + ], + None, + &pool, + ) + .await; assert_complete_results( format!( @@ -783,39 +783,39 @@ mod tests { ) .await; - // // prefers not mentioned columns - // assert_complete_results( - // format!( - // "select name from instruments where id = 'something' and {}", - // QueryWithCursorPosition::cursor_marker() - // ) - // .as_str(), - // vec![ - // CompletionAssertion::Label("created_at".into()), - // CompletionAssertion::Label("name".into()), - // CompletionAssertion::Label("z".into()), - // ], - // None, - // &pool, - // ) - // .await; - - // // // uses aliases - // assert_complete_results( - // format!( - // "select name from instruments i join others o on i.z = o.a where i.{}", - // QueryWithCursorPosition::cursor_marker() - // ) - // .as_str(), - // vec![ - // CompletionAssertion::Label("created_at".into()), - // CompletionAssertion::Label("id".into()), - // CompletionAssertion::Label("name".into()), - // ], - // None, - // &pool, - // ) - // .await; + // prefers not mentioned columns + assert_complete_results( + format!( + "select name from instruments where id = 'something' and {}", + QueryWithCursorPosition::cursor_marker() + ) + .as_str(), + vec![ + CompletionAssertion::Label("created_at".into()), + CompletionAssertion::Label("name".into()), + CompletionAssertion::Label("z".into()), + ], + None, + &pool, + ) + .await; + + // // uses aliases + assert_complete_results( + format!( + "select name from instruments i join others o on i.z = o.a where i.{}", + QueryWithCursorPosition::cursor_marker() + ) + .as_str(), + vec![ + CompletionAssertion::Label("created_at".into()), + CompletionAssertion::Label("id".into()), + CompletionAssertion::Label("name".into()), + ], + None, + &pool, + ) + .await; } #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")] From 22e971a59d06e9fd8bc2a4fba389ec823802130f Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 25 Oct 2025 19:38:47 +0200 Subject: [PATCH 07/11] unused --- .../src/relevance/filtering.rs | 12 ++- crates/pgt_treesitter_grammar/grammar.js | 80 +------------------ 2 files changed, 14 insertions(+), 78 deletions(-) diff --git a/crates/pgt_completions/src/relevance/filtering.rs b/crates/pgt_completions/src/relevance/filtering.rs index 42962782a..f97606fe3 100644 --- a/crates/pgt_completions/src/relevance/filtering.rs +++ b/crates/pgt_completions/src/relevance/filtering.rs @@ -1,5 +1,8 @@ use pgt_schema_cache::ProcKind; -use pgt_treesitter::context::{TreesitterContext, WrappingClause, WrappingNode}; +use pgt_treesitter::{ + MentionedColumn, + context::{TreesitterContext, WrappingClause, WrappingNode}, +}; use super::CompletionRelevanceData; @@ -101,6 +104,13 @@ impl CompletionFilter<'_> { && !ctx.matches_ancestor_history(&["insert_values", "field"]) && !ctx.node_under_cursor_is_within_field_name("binary_expr_right") } + "mentioned_column_identifier" => match self.data { + CompletionRelevanceData::Column(column) => ctx + // todo(juleswritescode): collect mentioned columns from more clauses + .get_mentioned_columns(&None) + .is_some_and(|cols| cols.iter().any(|c| c.column == column.name)), + _ => false, + }, _ => false, }; diff --git a/crates/pgt_treesitter_grammar/grammar.js b/crates/pgt_treesitter_grammar/grammar.js index 7db60eac1..5d519e5de 100644 --- a/crates/pgt_treesitter_grammar/grammar.js +++ b/crates/pgt_treesitter_grammar/grammar.js @@ -979,7 +979,6 @@ module.exports = grammar({ $.table_partition, $.stored_as, $.storage_location, - $.table_sort, $.row_format, seq($.keyword_tblproperties, paren_list($.table_option, true)), seq($.keyword_without, $.keyword_oids), @@ -2551,10 +2550,6 @@ module.exports = grammar({ ) ), - // todo(@juleswritescode): does this exist in postgresql? - table_sort: ($) => - seq($.keyword_sort, $.keyword_by, paren_list($.any_identifier, true)), - table_partition: ($) => seq( choice( @@ -2627,12 +2622,7 @@ module.exports = grammar({ ), column_definitions: ($) => - seq( - "(", - comma_list($.column_definition, true), - optional($.constraints), - ")" - ), + seq("(", comma_list($.column_definition, true), ")"), column_definition: ($) => seq( @@ -2663,8 +2653,7 @@ module.exports = grammar({ seq( $.keyword_set, choice($.keyword_null, $.keyword_default), - // todo(@juleswritescode): are these columns? - optional(paren_list($.any_identifier, true)) + optional(paren_list($.mentioned_column_identifier, true)) ) ) ) @@ -2708,16 +2697,6 @@ module.exports = grammar({ alias($.implicit_cast, $.cast) ), - constraints: ($) => seq(",", $.constraint, repeat(seq(",", $.constraint))), - - constraint: ($) => - choice( - $._constraint_literal, - $._key_constraint, - $._primary_key_constraint, - $._check_constraint - ), - _constraint_literal: ($) => seq( $.keyword_constraint, @@ -2727,59 +2706,6 @@ module.exports = grammar({ _primary_key_constraint: ($) => seq($._primary_key, $.ordered_columns), - _key_constraint: ($) => - seq( - choice( - seq( - $.keyword_unique, - optional( - choice( - $.keyword_index, - $.keyword_key, - seq( - $.keyword_nulls, - optional($.keyword_not), - $.keyword_distinct - ) - ) - ) - ), - seq( - optional($.keyword_foreign), - $.keyword_key, - optional($._if_not_exists) - ), - $.keyword_index - ), - optional(field("name", $.any_identifier)), - $.ordered_columns, - optional( - seq( - $.keyword_references, - $.object_reference, - // todo(@juleswritescode): are these columns? - paren_list($.any_identifier, true), - repeat( - seq( - $.keyword_on, - choice($.keyword_delete, $.keyword_update), - choice( - seq($.keyword_no, $.keyword_action), - $.keyword_restrict, - $.keyword_cascade, - seq( - $.keyword_set, - choice($.keyword_null, $.keyword_default), - // todo(@juleswritescode): are these columns? - optional(paren_list($.any_identifier, true)) - ) - ) - ) - ) - ) - ) - ), - ordered_columns: ($) => paren_list(alias($.ordered_column, $.column), true), ordered_column: ($) => seq(field("name", $._column), optional($.direction)), @@ -3042,7 +2968,6 @@ module.exports = grammar({ seq( $.keyword_as, field("alias", $.any_identifier), - // todo(@juleswritescode): are these columns? paren_list($.any_identifier, false) ) ) @@ -3517,6 +3442,7 @@ module.exports = grammar({ any_identifier: ($) => $._any_identifier, column_identifier: ($) => $._any_identifier, + mentioned_column_identifier: ($) => $._any_identifier, _any_identifier: ($) => choice( From fd3248674369665c068417912a8a0e33a2622932 Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 25 Oct 2025 19:46:11 +0200 Subject: [PATCH 08/11] ack --- crates/pgt_treesitter_grammar/grammar.js | 68 +++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/crates/pgt_treesitter_grammar/grammar.js b/crates/pgt_treesitter_grammar/grammar.js index 5d519e5de..2d00a4573 100644 --- a/crates/pgt_treesitter_grammar/grammar.js +++ b/crates/pgt_treesitter_grammar/grammar.js @@ -2622,7 +2622,12 @@ module.exports = grammar({ ), column_definitions: ($) => - seq("(", comma_list($.column_definition, true), ")"), + seq( + "(", + comma_list($.column_definition, true), + optional($.constraints), + ")" + ), column_definition: ($) => seq( @@ -2697,6 +2702,16 @@ module.exports = grammar({ alias($.implicit_cast, $.cast) ), + constraints: ($) => seq(",", $.constraint, repeat(seq(",", $.constraint))), + + constraint: ($) => + choice( + $._constraint_literal, + $._key_constraint, + $._primary_key_constraint, + $._check_constraint + ), + _constraint_literal: ($) => seq( $.keyword_constraint, @@ -2706,6 +2721,57 @@ module.exports = grammar({ _primary_key_constraint: ($) => seq($._primary_key, $.ordered_columns), + _key_constraint: ($) => + seq( + choice( + seq( + $.keyword_unique, + optional( + choice( + $.keyword_index, + $.keyword_key, + seq( + $.keyword_nulls, + optional($.keyword_not), + $.keyword_distinct + ) + ) + ) + ), + seq( + optional($.keyword_foreign), + $.keyword_key, + optional($._if_not_exists) + ), + $.keyword_index + ), + optional(field("name", $.any_identifier)), + $.ordered_columns, + optional( + seq( + $.keyword_references, + $.object_reference, + paren_list($.column_identifier, true), + repeat( + seq( + $.keyword_on, + choice($.keyword_delete, $.keyword_update), + choice( + seq($.keyword_no, $.keyword_action), + $.keyword_restrict, + $.keyword_cascade, + seq( + $.keyword_set, + choice($.keyword_null, $.keyword_default), + optional(paren_list($.any_identifier, true)) + ) + ) + ) + ) + ) + ) + ), + ordered_columns: ($) => paren_list(alias($.ordered_column, $.column), true), ordered_column: ($) => seq(field("name", $._column), optional($.direction)), From b1e5ebdf52b667e460a48b260464d5476aba20dc Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 25 Oct 2025 19:48:46 +0200 Subject: [PATCH 09/11] ok --- crates/pgt_completions/src/relevance/filtering.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/pgt_completions/src/relevance/filtering.rs b/crates/pgt_completions/src/relevance/filtering.rs index f97606fe3..befeb4ca2 100644 --- a/crates/pgt_completions/src/relevance/filtering.rs +++ b/crates/pgt_completions/src/relevance/filtering.rs @@ -1,8 +1,5 @@ use pgt_schema_cache::ProcKind; -use pgt_treesitter::{ - MentionedColumn, - context::{TreesitterContext, WrappingClause, WrappingNode}, -}; +use pgt_treesitter::context::{TreesitterContext, WrappingClause, WrappingNode}; use super::CompletionRelevanceData; From c7ff064189f72890362165e80fad30f76c67f015 Mon Sep 17 00:00:00 2001 From: Julian Date: Sun, 26 Oct 2025 09:07:15 +0100 Subject: [PATCH 10/11] unnecessary --- crates/pgt_completions/src/relevance/filtering.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/crates/pgt_completions/src/relevance/filtering.rs b/crates/pgt_completions/src/relevance/filtering.rs index befeb4ca2..42962782a 100644 --- a/crates/pgt_completions/src/relevance/filtering.rs +++ b/crates/pgt_completions/src/relevance/filtering.rs @@ -101,13 +101,6 @@ impl CompletionFilter<'_> { && !ctx.matches_ancestor_history(&["insert_values", "field"]) && !ctx.node_under_cursor_is_within_field_name("binary_expr_right") } - "mentioned_column_identifier" => match self.data { - CompletionRelevanceData::Column(column) => ctx - // todo(juleswritescode): collect mentioned columns from more clauses - .get_mentioned_columns(&None) - .is_some_and(|cols| cols.iter().any(|c| c.column == column.name)), - _ => false, - }, _ => false, }; From feced686e200fcf324dd0108a9954cf155ccc5e0 Mon Sep 17 00:00:00 2001 From: Julian Date: Sun, 26 Oct 2025 09:07:51 +0100 Subject: [PATCH 11/11] remove that for now --- crates/pgt_treesitter_grammar/grammar.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/pgt_treesitter_grammar/grammar.js b/crates/pgt_treesitter_grammar/grammar.js index 2d00a4573..4f57b5ef8 100644 --- a/crates/pgt_treesitter_grammar/grammar.js +++ b/crates/pgt_treesitter_grammar/grammar.js @@ -2658,7 +2658,7 @@ module.exports = grammar({ seq( $.keyword_set, choice($.keyword_null, $.keyword_default), - optional(paren_list($.mentioned_column_identifier, true)) + optional(paren_list($.any_identifier, true)) ) ) ) @@ -3508,7 +3508,6 @@ module.exports = grammar({ any_identifier: ($) => $._any_identifier, column_identifier: ($) => $._any_identifier, - mentioned_column_identifier: ($) => $._any_identifier, _any_identifier: ($) => choice(