1use linkrs_core::ErrorCode;
4use linkrs_core::Value;
5use parking_lot::RwLock;
6use std::collections::HashMap;
7use std::sync::Arc;
8use std::time::Instant;
9
10use super::session_manager::SessionInfo;
11
12#[derive(Debug, Clone)]
14pub struct RequestParams {
15 pub query: String,
16 pub parameters: HashMap<String, Value>,
17}
18
19impl RequestParams {
20 pub fn new(query: String) -> Self {
21 Self {
22 query,
23 parameters: HashMap::new(),
24 }
25 }
26
27 pub fn with_parameters(mut self, params: HashMap<String, Value>) -> Self {
28 self.parameters = params;
29 self
30 }
31}
32
33#[derive(Debug, Clone)]
35pub struct Response {
36 pub success: bool,
37 pub error_code: ErrorCode,
38 pub data: Option<Value>,
39 pub error_message: Option<String>,
40 pub execution_time_ms: u64,
41 pub affected_rows: u64,
42 pub warnings: Vec<String>,
43}
44
45impl Response {
46 pub fn new(success: bool) -> Self {
47 Self {
48 success,
49 error_code: if success {
50 ErrorCode::Success
51 } else {
52 ErrorCode::Unknown
53 },
54 data: None,
55 error_message: None,
56 execution_time_ms: 0,
57 affected_rows: 0,
58 warnings: Vec::new(),
59 }
60 }
61
62 pub fn with_data(mut self, data: Value) -> Self {
63 self.data = Some(data);
64 self
65 }
66
67 pub fn with_error(mut self, error: String) -> Self {
68 self.error_message = Some(error);
69 self.success = false;
70 self.error_code = ErrorCode::ExecutionError;
71 self
72 }
73
74 pub fn with_error_code(mut self, code: ErrorCode) -> Self {
75 self.error_code = code;
76 if code != ErrorCode::Success {
77 self.success = false;
78 }
79 self
80 }
81
82 pub fn with_execution_time(mut self, time_ms: u64) -> Self {
83 self.execution_time_ms = time_ms;
84 self
85 }
86
87 pub fn with_affected_rows(mut self, rows: u64) -> Self {
88 self.affected_rows = rows;
89 self
90 }
91
92 pub fn with_warning(mut self, warning: String) -> Self {
93 self.warnings.push(warning);
94 self
95 }
96
97 pub fn is_success(&self) -> bool {
98 self.success
99 }
100
101 pub fn get_data(&self) -> Option<&Value> {
102 self.data.as_ref()
103 }
104
105 pub fn get_error(&self) -> Option<&String> {
106 self.error_message.as_ref()
107 }
108}
109
110#[derive(Debug)]
117pub struct RequestContext {
118 session_info: Option<SessionInfo>,
120
121 request_params: Arc<RequestParams>,
123
124 response: Arc<RwLock<Response>>,
126
127 query_start_time: Instant,
129}
130
131impl RequestContext {
132 pub fn new(session_info: Option<SessionInfo>, request_params: RequestParams) -> Self {
134 Self {
135 session_info,
136 request_params: Arc::new(request_params),
137 response: Arc::new(RwLock::new(Response::new(true))),
138 query_start_time: Instant::now(),
139 }
140 }
141
142 pub fn with_session(
144 query: String,
145 session_id: &str,
146 user_name: &str,
147 client_ip: &str,
148 client_port: u16,
149 ) -> Result<Self, String> {
150 let session_info =
151 SessionInfo::from_params(session_id, user_name, None, client_ip, client_port)?;
152 let request_params = RequestParams::new(query);
153 Ok(Self::new(Some(session_info), request_params))
154 }
155
156 pub fn with_parameters(
158 query: String,
159 parameters: HashMap<String, Value>,
160 session_id: &str,
161 user_name: &str,
162 client_ip: &str,
163 client_port: u16,
164 ) -> Result<Self, String> {
165 let session_info =
166 SessionInfo::from_params(session_id, user_name, None, client_ip, client_port)?;
167 let request_params = RequestParams::new(query).with_parameters(parameters);
168 Ok(Self::new(Some(session_info), request_params))
169 }
170
171 pub fn session_info(&self) -> Option<&SessionInfo> {
173 self.session_info.as_ref()
174 }
175
176 pub fn request_params(&self) -> &RequestParams {
178 &self.request_params
179 }
180
181 pub fn query(&self) -> &str {
183 &self.request_params.query
184 }
185
186 pub fn parameters(&self) -> &HashMap<String, Value> {
188 &self.request_params.parameters
189 }
190
191 pub fn response(&self) -> Response {
193 self.response.read().clone()
194 }
195
196 pub fn set_response(&self, response: Response) {
198 let mut guard = self.response.write();
199 *guard = response;
200 }
201
202 pub fn session_id(&self) -> Option<i64> {
204 self.session_info.as_ref().map(|s| s.session_id)
205 }
206
207 pub fn user_name(&self) -> Option<&str> {
209 self.session_info.as_ref().map(|s| s.user_name.as_str())
210 }
211
212 pub fn space_name(&self) -> Option<&str> {
214 self.session_info
215 .as_ref()
216 .and_then(|s| s.space_name.as_deref())
217 }
218
219 pub fn set_space_name(&mut self, space_name: String) {
221 if let Some(ref mut session) = self.session_info {
222 session.space_name = Some(space_name);
223 }
224 }
225
226 pub fn set_response_error(&self, error: String) {
228 let mut guard = self.response.write();
229 guard.success = false;
230 guard.error_code = ErrorCode::ExecutionError;
231 guard.error_message = Some(error);
232 }
233
234 pub fn set_response_error_with_code(&self, error: String, code: ErrorCode) {
236 let mut guard = self.response.write();
237 guard.success = false;
238 guard.error_code = code;
239 guard.error_message = Some(error);
240 }
241
242 pub fn add_warning(&self, warning: String) {
244 let mut guard = self.response.write();
245 guard.warnings.push(warning);
246 }
247
248 pub fn set_execution_time(&self) {
250 let elapsed = self.query_start_time.elapsed().as_millis() as u64;
251 let mut guard = self.response.write();
252 guard.execution_time_ms = elapsed;
253 }
254
255 pub fn elapsed_ms(&self) -> u64 {
257 self.query_start_time.elapsed().as_millis() as u64
258 }
259
260 pub fn get_parameter(&self, param: &str) -> Option<Value> {
262 self.request_params.parameters.get(param).cloned()
263 }
264
265 pub fn touch_session(&mut self) {
267 if let Some(ref mut session) = self.session_info {
268 session.touch();
269 }
270 }
271}
272
273impl Default for RequestContext {
274 fn default() -> Self {
275 Self {
276 session_info: None,
277 request_params: Arc::new(RequestParams::new(String::new())),
278 response: Arc::new(RwLock::new(Response::new(true))),
279 query_start_time: Instant::now(),
280 }
281 }
282}
283
284impl Clone for RequestContext {
285 fn clone(&self) -> Self {
286 Self {
287 session_info: self.session_info.clone(),
288 request_params: self.request_params.clone(),
289 response: self.response.clone(),
290 query_start_time: self.query_start_time,
291 }
292 }
293}
294
295pub fn build_query_request_context(
299 session: &super::ClientSession,
300 query: String,
301 parameters: std::collections::HashMap<String, linkrs_core::Value>,
302) -> crate::query::QueryRequestContext {
303 use crate::query::QueryRequestContext;
304
305 QueryRequestContext {
306 session_id: Some(session.id()),
307 isolation_level: None,
308 user_name: Some(session.user()),
309 space_name: session.space_name(),
310 query,
311 parameters,
312 session_variables: session.variables_snapshot(),
313 query_id: None,
314 parsed_statement: None,
315 transaction_id: session.current_transaction(),
316 auto_commit: session.is_auto_commit(),
317 read_only: false,
318 operation_context: None,
319 operation_storage: None,
320 ryw_config: None,
321 }
322}