1use std::time::Duration;
2
3use serde::{Deserialize, Serialize};
4use surrealdb_types::{Error as TypesError, kind, object};
5use uuid::Uuid;
6
7use crate::dbs;
8use crate::dbs::{QueryResult, QueryType};
9use crate::rpc::request::SESSION_ID;
10use crate::types::{
11 PublicArray, PublicKind, PublicNotification, PublicObject, PublicValue, SurrealValue,
12};
13
14#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16#[non_exhaustive]
17pub struct DbResultStats {
18 pub execution_time: Option<Duration>,
22 pub query_type: Option<QueryType>,
23}
24
25impl DbResultStats {
26 pub fn with_execution_time(mut self, execution_time: Duration) -> Self {
27 self.execution_time = Some(execution_time);
28 self
29 }
30
31 pub fn with_query_type(mut self, query_type: QueryType) -> Self {
32 self.query_type = Some(query_type);
33 self
34 }
35}
36
37#[derive(Debug, Serialize, Deserialize)]
41pub enum DbResult {
42 Other(PublicValue),
44 Query(Vec<dbs::QueryResult>),
46 Live(PublicNotification),
48 }
50
51impl SurrealValue for DbResult {
52 fn kind_of() -> PublicKind {
53 kind!(array | {
54 id: uuid,
55 session: uuid | none,
56 action: string,
57 record: any,
58 result: any,
59 } | any)
60 }
61
62 fn is_value(_value: &PublicValue) -> bool {
63 true
64 }
65
66 fn into_value(self) -> PublicValue {
67 match self {
68 DbResult::Query(v) => {
69 let converted: Vec<PublicValue> = v.into_iter().map(|x| x.into_value()).collect();
70 PublicValue::Array(PublicArray::from(converted))
71 }
72 DbResult::Live(v) => PublicValue::Object(object! {
73 id: PublicValue::Uuid(v.id),
74 session: v.session.map(PublicValue::Uuid),
75 action: v.action.into_value(),
76 record: v.record,
77 result: v.result,
78 }),
79 DbResult::Other(v) => v,
80 }
81 }
82
83 fn from_value(value: PublicValue) -> Result<Self, TypesError> {
84 match value {
85 PublicValue::Array(arr) => {
86 let results = arr
87 .into_inner()
88 .into_iter()
89 .map(QueryResult::from_value)
90 .collect::<Result<Vec<_>, TypesError>>()?;
91 Ok(DbResult::Query(results))
92 }
93 PublicValue::Object(obj) => {
94 if obj.get("id").is_some() && obj.get("action").is_some() {
96 let mut obj = obj.into_inner();
97 let id = obj
98 .remove("id")
99 .ok_or_else(|| TypesError::internal("Missing id".to_string()))?;
100 let action = obj
101 .remove("action")
102 .ok_or_else(|| TypesError::internal("Missing action".to_string()))?;
103 let record = obj.remove("record").unwrap_or(PublicValue::None);
104 let result = obj.remove("result").unwrap_or(PublicValue::None);
105
106 let PublicValue::Uuid(uuid) = id else {
107 return Err(TypesError::internal("Expected UUID for id field".to_string()));
108 };
109 let PublicValue::String(action_str) = action else {
110 return Err(TypesError::internal(
111 "Expected string for action field".to_string(),
112 ));
113 };
114
115 let session = match obj.remove(SESSION_ID) {
116 Some(session) => SurrealValue::from_value(session)?,
117 None => None,
118 };
119
120 let action = match action_str.as_str() {
122 "CREATE" => crate::types::PublicAction::Create,
123 "UPDATE" => crate::types::PublicAction::Update,
124 "DELETE" => crate::types::PublicAction::Delete,
125 _ => {
126 return Err(TypesError::internal(format!(
127 "Invalid action: {}",
128 action_str
129 )));
130 }
131 };
132
133 Ok(DbResult::Live(PublicNotification::new(
134 uuid, session, action, record, result,
135 )))
136 } else {
137 Ok(DbResult::Other(PublicValue::Object(obj)))
138 }
139 }
140 other => Ok(DbResult::Other(other)),
141 }
142 }
143}
144
145#[derive(Debug)]
146pub struct DbResponse {
147 pub id: Option<PublicValue>,
148 pub session_id: Option<Uuid>,
149 pub result: Result<DbResult, TypesError>,
151}
152
153impl DbResponse {
154 pub fn new(
155 id: Option<PublicValue>,
156 session_id: Option<Uuid>,
157 result: Result<DbResult, TypesError>,
158 ) -> Self {
159 Self {
160 id,
161 session_id,
162 result,
163 }
164 }
165
166 pub fn failure(
168 id: Option<PublicValue>,
169 session_id: Option<Uuid>,
170 error: impl Into<TypesError>,
171 ) -> Self {
172 Self {
173 id,
174 session_id,
175 result: Err(error.into()),
176 }
177 }
178
179 pub fn success(id: Option<PublicValue>, session_id: Option<Uuid>, result: DbResult) -> Self {
180 Self {
181 id,
182 session_id,
183 result: Ok(result),
184 }
185 }
186
187 pub fn from_bytes(bytes: &[u8]) -> Result<Self, TypesError> {
188 let value = crate::rpc::format::flatbuffers::decode(bytes)
189 .map_err(|e| TypesError::internal(e.to_string()))?;
190 Self::from_value(value)
191 }
192}
193
194impl SurrealValue for DbResponse {
195 fn kind_of() -> PublicKind {
196 PublicKind::Object
197 }
198
199 fn is_value(value: &PublicValue) -> bool {
200 matches!(value, PublicValue::Object(_))
201 }
202
203 fn into_value(self) -> PublicValue {
204 let mut value = match self.result {
205 Ok(result) => map! { "result" => result.into_value() },
206 Err(err) => map! {
207 "error" => SurrealValue::into_value(err),
208 },
209 };
210 if let Some(id) = self.id {
211 value.insert("id", id);
212 }
213 if let Some(session_id) = self.session_id {
214 value.insert(SESSION_ID, PublicValue::Uuid(session_id.into()));
215 }
216 PublicValue::Object(PublicObject::from(
217 value.into_iter().collect::<std::collections::BTreeMap<_, _>>(),
218 ))
219 }
220
221 fn from_value(value: PublicValue) -> Result<Self, TypesError> {
222 let PublicValue::Object(mut obj) = value else {
223 return Err(TypesError::internal("Expected object for DbResponse".to_string()));
224 };
225
226 let session_id = SurrealValue::from_value(obj.remove(SESSION_ID).unwrap_or_default())?;
227
228 let id = obj.remove("id");
229
230 let result = if let Some(result) = obj.remove("result") {
231 Ok(DbResult::from_value(result)?)
232 } else if let Some(error) = obj.remove("error") {
233 Err(TypesError::from_value(error)?)
234 } else {
235 return Err(TypesError::internal(
236 "DbResponse must have either 'result' or 'error' field".to_string(),
237 ));
238 };
239
240 Ok(DbResponse {
241 id,
242 session_id,
243 result,
244 })
245 }
246}