@@ -30,7 +30,7 @@ impl TryFrom<&str> for ClauseType {
3030 match value {
3131 "select" => Ok ( Self :: Select ) ,
3232 "where" => Ok ( Self :: Where ) ,
33- "from" | "keyword_from" => Ok ( Self :: From ) ,
33+ "from" => Ok ( Self :: From ) ,
3434 "update" => Ok ( Self :: Update ) ,
3535 "delete" => Ok ( Self :: Delete ) ,
3636 _ => {
@@ -49,8 +49,52 @@ impl TryFrom<&str> for ClauseType {
4949
5050impl TryFrom < String > for ClauseType {
5151 type Error = String ;
52- fn try_from ( value : String ) -> Result < ClauseType , Self :: Error > {
53- ClauseType :: try_from ( value. as_str ( ) )
52+ fn try_from ( value : String ) -> Result < Self , Self :: Error > {
53+ Self :: try_from ( value. as_str ( ) )
54+ }
55+ }
56+
57+ /// We can map a few nodes, such as the "update" node, to actual SQL clauses.
58+ /// That gives us a lot of insight for completions.
59+ /// Other nodes, such as the "relation" node, gives us less but still
60+ /// relevant information.
61+ /// `WrappingNode` maps to such nodes.
62+ ///
63+ /// Note: This is not the direct parent of the `node_under_cursor`, but the closest
64+ /// *relevant* parent.
65+ #[ derive( Debug , PartialEq , Eq ) ]
66+ pub enum WrappingNode {
67+ Relation ,
68+ BinaryExpression ,
69+ Assignment ,
70+ }
71+
72+ impl TryFrom < & str > for WrappingNode {
73+ type Error = String ;
74+
75+ fn try_from ( value : & str ) -> Result < Self , Self :: Error > {
76+ match value {
77+ "relation" => Ok ( Self :: Relation ) ,
78+ "assignment" => Ok ( Self :: Assignment ) ,
79+ "binary_expression" => Ok ( Self :: BinaryExpression ) ,
80+ _ => {
81+ let message = format ! ( "Unimplemented Relation: {}" , value) ;
82+
83+ // Err on tests, so we notice that we're lacking an implementation immediately.
84+ if cfg ! ( test) {
85+ panic ! ( "{}" , message) ;
86+ }
87+
88+ Err ( message)
89+ }
90+ }
91+ }
92+ }
93+
94+ impl TryFrom < String > for WrappingNode {
95+ type Error = String ;
96+ fn try_from ( value : String ) -> Result < Self , Self :: Error > {
97+ Self :: try_from ( value. as_str ( ) )
5498 }
5599}
56100
@@ -64,6 +108,9 @@ pub(crate) struct CompletionContext<'a> {
64108
65109 pub schema_name : Option < String > ,
66110 pub wrapping_clause_type : Option < ClauseType > ,
111+
112+ pub wrapping_node_kind : Option < WrappingNode > ,
113+
67114 pub is_invocation : bool ,
68115 pub wrapping_statement_range : Option < tree_sitter:: Range > ,
69116
@@ -80,6 +127,7 @@ impl<'a> CompletionContext<'a> {
80127 node_under_cursor : None ,
81128 schema_name : None ,
82129 wrapping_clause_type : None ,
130+ wrapping_node_kind : None ,
83131 wrapping_statement_range : None ,
84132 is_invocation : false ,
85133 mentioned_relations : HashMap :: new ( ) ,
@@ -133,6 +181,15 @@ impl<'a> CompletionContext<'a> {
133181 } )
134182 }
135183
184+ pub fn get_node_under_cursor_content ( & self ) -> Option < String > {
185+ self . node_under_cursor
186+ . and_then ( |n| self . get_ts_node_content ( n) )
187+ . and_then ( |txt| match txt {
188+ NodeText :: Replaced => None ,
189+ NodeText :: Original ( c) => Some ( c. to_string ( ) ) ,
190+ } )
191+ }
192+
136193 fn gather_tree_context ( & mut self ) {
137194 let mut cursor = self . tree . root_node ( ) . walk ( ) ;
138195
@@ -163,23 +220,26 @@ impl<'a> CompletionContext<'a> {
163220 ) {
164221 let current_node = cursor. node ( ) ;
165222
223+ let parent_node_kind = parent_node. kind ( ) ;
224+ let current_node_kind = current_node. kind ( ) ;
225+
166226 // prevent infinite recursion – this can happen if we only have a PROGRAM node
167- if current_node . kind ( ) == parent_node . kind ( ) {
227+ if current_node_kind == parent_node_kind {
168228 self . node_under_cursor = Some ( current_node) ;
169229 return ;
170230 }
171231
172- match parent_node . kind ( ) {
232+ match parent_node_kind {
173233 "statement" | "subquery" => {
174- self . wrapping_clause_type = current_node . kind ( ) . try_into ( ) . ok ( ) ;
234+ self . wrapping_clause_type = current_node_kind . try_into ( ) . ok ( ) ;
175235 self . wrapping_statement_range = Some ( parent_node. range ( ) ) ;
176236 }
177237 "invocation" => self . is_invocation = true ,
178238
179239 _ => { }
180240 }
181241
182- match current_node . kind ( ) {
242+ match current_node_kind {
183243 "object_reference" => {
184244 let content = self . get_ts_node_content ( current_node) ;
185245 if let Some ( node_txt) = content {
@@ -195,13 +255,12 @@ impl<'a> CompletionContext<'a> {
195255 }
196256 }
197257
198- // in Treesitter, the Where clause is nested inside other clauses
199- "where" => {
200- self . wrapping_clause_type = "where" . try_into ( ) . ok ( ) ;
258+ "where" | "update" | "select" | "delete" | "from" => {
259+ self . wrapping_clause_type = current_node_kind. try_into ( ) . ok ( ) ;
201260 }
202261
203- "keyword_from " => {
204- self . wrapping_clause_type = "keyword_from" . try_into ( ) . ok ( ) ;
262+ "relation" | "binary_expression" | "assignment " => {
263+ self . wrapping_node_kind = current_node_kind . try_into ( ) . ok ( ) ;
205264 }
206265
207266 _ => { }
@@ -406,10 +465,6 @@ mod tests {
406465 ctx. get_ts_node_content( node) ,
407466 Some ( NodeText :: Original ( "from" ) )
408467 ) ;
409- assert_eq ! (
410- ctx. wrapping_clause_type,
411- Some ( crate :: context:: ClauseType :: From )
412- ) ;
413468 }
414469
415470 #[ test]
0 commit comments