@@ -3,8 +3,8 @@ use std::sync::Arc;
3
3
use notification:: ShowMessage ;
4
4
use pg_commands:: CommandType ;
5
5
use pg_workspace:: Workspace ;
6
- use tokio:: sync:: { Mutex , RwLock } ;
7
- use tower_lsp:: jsonrpc:: Result ;
6
+ use tokio:: sync:: RwLock ;
7
+ use tower_lsp:: jsonrpc:: Error ;
8
8
use tower_lsp:: lsp_types:: * ;
9
9
use tower_lsp:: { Client , LanguageServer } ;
10
10
@@ -14,7 +14,7 @@ use crate::server::options::ClientConfigurationOptions;
14
14
15
15
struct Server {
16
16
client : Client ,
17
- db : Mutex < Option < DbConnection > > ,
17
+ db : RwLock < Option < DbConnection > > ,
18
18
ide : Arc < RwLock < Workspace > > ,
19
19
client_capabilities : RwLock < Option < ClientFlags > > ,
20
20
}
@@ -24,7 +24,7 @@ impl Server {
24
24
let ide = Arc :: new ( RwLock :: new ( Workspace :: new ( ) ) ) ;
25
25
Self {
26
26
client,
27
- db : Mutex :: new ( None ) ,
27
+ db : RwLock :: new ( None ) ,
28
28
ide,
29
29
client_capabilities : RwLock :: new ( None ) ,
30
30
}
@@ -34,13 +34,13 @@ impl Server {
34
34
fn parse_options_from_client (
35
35
& self ,
36
36
mut value : serde_json:: Value ,
37
- ) -> Result < ClientConfigurationOptions > {
37
+ ) -> Option < ClientConfigurationOptions > {
38
38
let options = match value. get_mut ( "pglsp" ) {
39
39
Some ( section) => section. take ( ) ,
40
40
None => value,
41
41
} ;
42
42
43
- let options = match serde_json:: from_value :: < ClientConfigurationOptions > ( options) {
43
+ match serde_json:: from_value :: < ClientConfigurationOptions > ( options) {
44
44
Ok ( new_options) => Some ( new_options) ,
45
45
Err ( why) => {
46
46
let message = format ! (
@@ -51,19 +51,21 @@ impl Server {
51
51
. send_notification :: < ShowMessage > ( ShowMessageParams { message, typ } ) ;
52
52
None
53
53
}
54
- } ;
55
-
56
- Ok ( options. unwrap_or_default ( ) )
54
+ }
57
55
}
58
56
57
+ /// `update_db_connection` will update `Self`'s database connection.
58
+ /// If the passed-in connection string is the same that we're already connected to, it's a noop.
59
+ /// Otherwise, it'll first open a new connection, replace `Self`'s connection, and then close
60
+ /// the old one.
59
61
async fn update_db_connection (
60
62
& self ,
61
63
options : ClientConfigurationOptions ,
62
64
) -> anyhow:: Result < ( ) > {
63
65
if options. db_connection_string . is_none ( )
64
66
|| self
65
67
. db
66
- . lock ( )
68
+ . read ( )
67
69
. await
68
70
. as_ref ( )
69
71
// if the connection is already connected to the same database, do nothing
@@ -81,7 +83,7 @@ impl Server {
81
83
let _guard = ide. blocking_write ( ) . set_schema_cache ( schema) ;
82
84
} ) ;
83
85
84
- let mut current_db = self . db . lock ( ) . await ;
86
+ let mut current_db = self . db . blocking_write ( ) ;
85
87
let old_db = current_db. replace ( db) ;
86
88
87
89
if old_db. is_some ( ) {
@@ -91,11 +93,48 @@ impl Server {
91
93
92
94
Ok ( ( ) )
93
95
}
96
+
97
+ async fn request_opts_from_client ( & self ) -> Option < ClientConfigurationOptions > {
98
+ let params = ConfigurationParams {
99
+ items : vec ! [ ConfigurationItem {
100
+ section: Some ( "pglsp" . to_string( ) ) ,
101
+ scope_uri: None ,
102
+ } ] ,
103
+ } ;
104
+
105
+ match self
106
+ . client
107
+ . send_request :: < request:: WorkspaceConfiguration > ( params)
108
+ . await
109
+ {
110
+ Ok ( json) => {
111
+ // The client reponse fits the requested `ConfigurationParams.items`,
112
+ // so the first value is what we're looking for.
113
+ let relevant = json
114
+ . into_iter ( )
115
+ . next ( )
116
+ . expect ( "workspace/configuration request did not yield expected response." ) ;
117
+
118
+ let opts = self . parse_options_from_client ( relevant) ;
119
+
120
+ opts
121
+ }
122
+ Err ( why) => {
123
+ let message = format ! (
124
+ "Unable to pull client options via workspace/configuration request: {}" ,
125
+ why
126
+ ) ;
127
+ println ! ( "{}" , message) ;
128
+ self . client . log_message ( MessageType :: ERROR , message) ;
129
+ None
130
+ }
131
+ }
132
+ }
94
133
}
95
134
96
135
#[ tower_lsp:: async_trait]
97
136
impl LanguageServer for Server {
98
- async fn initialize ( & self , params : InitializeParams ) -> Result < InitializeResult > {
137
+ async fn initialize ( & self , params : InitializeParams ) -> tower_lsp :: jsonrpc :: Result < InitializeResult > {
99
138
let flags = ClientFlags :: from_initialize_request_params ( & params) ;
100
139
self . client_capabilities . blocking_write ( ) . replace ( flags) ;
101
140
@@ -135,25 +174,86 @@ impl LanguageServer for Server {
135
174
. await ;
136
175
}
137
176
138
- async fn shutdown ( & self ) -> Result < ( ) > {
177
+ async fn shutdown ( & self ) -> anyhow :: Result < ( ) > {
139
178
self . client
140
179
. log_message ( MessageType :: INFO , "Postgres LSP terminated." )
141
180
. await ;
142
181
Ok ( ( ) )
143
182
}
144
183
145
-
146
184
async fn did_change_configuration ( & self , params : DidChangeConfigurationParams ) {
147
- match self . parse_options_from_client ( params. settings ) {
148
- Ok ( opts) => {
149
- self . update_db_connection ( opts) . await ;
185
+ let capabilities = self . client_capabilities . read ( ) . await ;
186
+
187
+ if capabilities. as_ref ( ) . unwrap ( ) . supports_pull_opts {
188
+ let opts = self . request_opts_from_client ( ) . await ;
189
+ if opts. is_some ( ) {
190
+ self . update_db_connection ( opts. unwrap ( ) ) . await ;
191
+ return ;
192
+ }
193
+ }
194
+
195
+ let opts = self . parse_options_from_client ( params. settings ) ;
196
+
197
+ if opts. is_some ( ) {
198
+ self . update_db_connection ( opts. unwrap ( ) ) . await ;
199
+ }
200
+ }
201
+
202
+ async fn execute_command (
203
+ & self ,
204
+ params : ExecuteCommandParams ,
205
+ ) -> tower_lsp:: jsonrpc:: Result < Option < serde_json:: Value > > {
206
+ match CommandType :: from_id ( params. command . replace ( "pglsp." , "" ) . as_str ( ) ) {
207
+ Some ( CommandType :: ExecuteStatement ) => {
208
+ if params. arguments . is_empty ( ) {
209
+ return tower_lsp:: jsonrpc:: Result :: Err ( Error :: new ( "No arguments provided!" ) ) ;
210
+ }
211
+
212
+ let stmt = params
213
+ . arguments
214
+ . into_iter ( )
215
+ . next ( )
216
+ . map ( |v| serde_json:: from_value ( v) )
217
+ . unwrap ( ) ?;
218
+
219
+ let conn = self . db . read ( ) . await ;
220
+ match conn
221
+ . as_ref ( )
222
+ . expect ( "No connection to the database." )
223
+ . run_stmt ( stmt)
224
+ . await
225
+ {
226
+ Ok ( pg_result) => {
227
+ self . client
228
+ . send_notification :: < ShowMessage > ( ShowMessageParams {
229
+ typ : MessageType :: INFO ,
230
+ message : format ! (
231
+ "Success! Affected rows: {}" ,
232
+ pg_result. rows_affected( )
233
+ ) ,
234
+ } )
235
+ . await ;
236
+ }
237
+ Err ( why) => {
238
+ self . client
239
+ . send_notification :: < ShowMessage > ( ShowMessageParams {
240
+ typ : MessageType :: ERROR ,
241
+ message : format ! ( "Error! Statement exectuion failed: {}" , why) ,
242
+ } )
243
+ . await ;
244
+ }
245
+ } ;
150
246
}
151
- Err ( e ) => {
247
+ None => {
152
248
self . client
153
- . log_message ( MessageType :: ERROR , format ! ( "Error parsing configuration: {}" , e) )
249
+ . show_message (
250
+ MessageType :: ERROR ,
251
+ format ! ( "Unknown command: {}" , params. command) ,
252
+ )
154
253
. await ;
155
254
}
156
255
} ;
157
256
257
+ Ok ( None )
158
258
}
159
259
}
0 commit comments