surrealdb/api/value/
mod.rs

1use crate::Error;
2use revision::revisioned;
3use serde::{de::DeserializeOwned, Deserialize, Serialize};
4use std::{
5	cmp::{Ordering, PartialEq, PartialOrd},
6	fmt,
7	ops::Deref,
8	str::FromStr,
9};
10use surrealdb_core::{
11	dbs::Action as CoreAction,
12	sql::{
13		Array as CoreArray, Datetime as CoreDatetime, Id as CoreId, Number as CoreNumber,
14		Thing as CoreThing, Value as CoreValue,
15	},
16	syn,
17};
18use uuid::Uuid;
19
20mod obj;
21pub use obj::{IntoIter, Iter, IterMut, Object};
22
23pub fn from_value<T: DeserializeOwned>(value: Value) -> Result<T, Error> {
24	Ok(surrealdb_core::sql::from_value(value.0)?)
25}
26
27pub fn to_value<T: Serialize + 'static>(value: T) -> Result<Value, Error> {
28	let v = surrealdb_core::sql::to_value(value)?;
29	Ok(Value(v))
30}
31
32// Keeping bytes implementation minimal since it might be a good idea to use bytes crate here
33// instead of a plain Vec<u8>.
34#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
35#[revisioned(revision = 1)]
36pub struct Bytes(Vec<u8>);
37
38impl Bytes {
39	pub fn copy_from_slice(slice: &[u8]) -> Self {
40		slice.to_vec().into()
41	}
42
43	pub fn len(&self) -> usize {
44		self.0.len()
45	}
46
47	pub fn is_empty(&self) -> bool {
48		self.0.is_empty()
49	}
50}
51
52impl PartialEq<[u8]> for Bytes {
53	fn eq(&self, other: &[u8]) -> bool {
54		self.0 == other
55	}
56}
57
58impl PartialOrd<[u8]> for Bytes {
59	fn partial_cmp(&self, other: &[u8]) -> Option<Ordering> {
60		self.0.as_slice().partial_cmp(other)
61	}
62}
63
64impl Deref for Bytes {
65	type Target = [u8];
66
67	fn deref(&self) -> &Self::Target {
68		self.0.as_slice()
69	}
70}
71
72impl From<Vec<u8>> for Bytes {
73	fn from(value: Vec<u8>) -> Self {
74		Bytes(value)
75	}
76}
77
78transparent_wrapper!(
79	#[derive( Clone, Eq, PartialEq, Ord, PartialOrd)]
80	pub struct Datetime(CoreDatetime)
81);
82
83transparent_wrapper!(
84	/// The key of a [`RecordId`].
85	#[derive( Clone, PartialEq, PartialOrd)]
86	#[non_exhaustive]
87	pub struct RecordIdKey(CoreId)
88);
89
90impl From<Object> for RecordIdKey {
91	fn from(value: Object) -> Self {
92		Self::from_inner(CoreId::Object(value.into_inner()))
93	}
94}
95
96impl From<String> for RecordIdKey {
97	fn from(value: String) -> Self {
98		Self(CoreId::String(value))
99	}
100}
101
102impl From<&String> for RecordIdKey {
103	fn from(value: &String) -> Self {
104		Self(CoreId::String(value.clone()))
105	}
106}
107
108impl From<&str> for RecordIdKey {
109	fn from(value: &str) -> Self {
110		Self(CoreId::String(value.to_owned()))
111	}
112}
113
114impl From<i64> for RecordIdKey {
115	fn from(value: i64) -> Self {
116		Self(CoreId::Number(value))
117	}
118}
119
120impl From<Vec<Value>> for RecordIdKey {
121	fn from(value: Vec<Value>) -> Self {
122		let res = Value::array_to_core(value);
123		let mut array = CoreArray::default();
124		array.0 = res;
125		Self(CoreId::Array(array))
126	}
127}
128
129impl From<RecordIdKey> for Value {
130	fn from(key: RecordIdKey) -> Self {
131		match key.0 {
132			CoreId::String(x) => Value::from_inner(CoreValue::from(x)),
133			CoreId::Number(x) => Value::from_inner(CoreValue::from(x)),
134			CoreId::Object(x) => Value::from_inner(CoreValue::from(x)),
135			CoreId::Array(x) => Value::from_inner(CoreValue::from(x)),
136			_ => panic!("lib recieved generate variant of record id"),
137		}
138	}
139}
140
141impl From<RecordId> for Value {
142	fn from(key: RecordId) -> Self {
143		Value::from_inner(CoreValue::Thing(key.0))
144	}
145}
146
147impl FromStr for Value {
148	type Err = Error;
149
150	fn from_str(s: &str) -> Result<Self, Self::Err> {
151		Ok(Value::from_inner(surrealdb_core::syn::value(s)?))
152	}
153}
154
155#[derive(Debug)]
156pub struct RecordIdKeyFromValueError(());
157
158impl fmt::Display for RecordIdKeyFromValueError {
159	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160		writeln!(f,"tried to convert a value to a record id key with a value type that is not allowed in a record id key")
161	}
162}
163
164impl TryFrom<Value> for RecordIdKey {
165	type Error = RecordIdKeyFromValueError;
166
167	fn try_from(key: Value) -> Result<Self, Self::Error> {
168		match key.0 {
169			CoreValue::Strand(x) => Ok(RecordIdKey::from_inner(CoreId::String(x.0))),
170			CoreValue::Number(CoreNumber::Int(x)) => Ok(RecordIdKey::from_inner(CoreId::Number(x))),
171			CoreValue::Object(x) => Ok(RecordIdKey::from_inner(CoreId::Object(x))),
172			CoreValue::Array(x) => Ok(RecordIdKey::from_inner(CoreId::Array(x))),
173			_ => Err(RecordIdKeyFromValueError(())),
174		}
175	}
176}
177
178transparent_wrapper!(
179	/// Struct representing a record id.
180	///
181	/// Record id's consist of a table name and a key.
182	/// For example the record id `user:tkwse1j5o0anqjxonvzx` has the table `user` and the key `tkwse1j5o0anqjxonvzx`.
183	#[derive( Clone, PartialEq, PartialOrd)]
184	pub struct RecordId(CoreThing)
185);
186impl_serialize_wrapper!(RecordId);
187
188impl RecordId {
189	pub fn from_table_key<S, K>(table: S, key: K) -> Self
190	where
191		S: Into<String>,
192		K: Into<RecordIdKey>,
193	{
194		let tb = table.into();
195		let key = key.into();
196		Self(CoreThing::from((tb, key.0)))
197	}
198
199	pub fn table(&self) -> &str {
200		&self.0.tb
201	}
202
203	pub fn key(&self) -> &RecordIdKey {
204		RecordIdKey::from_inner_ref(&self.0.id)
205	}
206}
207
208impl FromStr for RecordId {
209	type Err = Error;
210
211	fn from_str(s: &str) -> Result<Self, Self::Err> {
212		syn::thing(s).map_err(crate::Error::Db).map(RecordId::from_inner)
213	}
214}
215
216impl<S, I> From<(S, I)> for RecordId
217where
218	S: Into<String>,
219	RecordIdKey: From<I>,
220{
221	fn from(value: (S, I)) -> Self {
222		Self::from_table_key(value.0, value.1)
223	}
224}
225
226transparent_wrapper!(
227	/// The number type of surrealql.
228	/// Can contain either a 64 bit float, 64 bit integer or a decimal.
229	#[derive( Clone, PartialEq, PartialOrd)]
230	pub struct Number(CoreNumber)
231);
232impl_serialize_wrapper!(Number);
233
234impl Number {
235	#[doc(hidden)]
236	pub fn cource_into_i64(self) -> Option<i64> {
237		match self.0 {
238			CoreNumber::Int(x) => Some(x),
239			CoreNumber::Float(x) if x.fract() == x => Some(x as i64),
240			CoreNumber::Decimal(x) => x.try_into().ok(),
241			_ => None,
242		}
243	}
244}
245
246transparent_wrapper!(
247	#[derive( Clone, Default, PartialEq, PartialOrd)]
248	pub struct Value(pub(crate) CoreValue)
249);
250impl_serialize_wrapper!(Value);
251
252impl Value {
253	// TODO: Check if all of theses are actually used.
254	#[allow(dead_code)]
255	pub(crate) fn core_to_array(v: Vec<CoreValue>) -> Vec<Value> {
256		unsafe {
257			// SAFETY: Because Value is `repr(transparent)` transmuting between value and corevalue
258			// is safe.
259			std::mem::transmute::<Vec<CoreValue>, Vec<Value>>(v)
260		}
261	}
262
263	#[allow(dead_code)]
264	pub(crate) fn core_to_array_ref(v: &Vec<CoreValue>) -> &Vec<Value> {
265		unsafe {
266			// SAFETY: Because Value is `repr(transparent)` transmuting between value and corevalue
267			// is safe.
268			std::mem::transmute::<&Vec<CoreValue>, &Vec<Value>>(v)
269		}
270	}
271
272	#[allow(dead_code)]
273	pub(crate) fn core_to_array_mut(v: &mut Vec<CoreValue>) -> &mut Vec<Value> {
274		unsafe {
275			// SAFETY: Because Value is `repr(transparent)` transmuting between value and corevalue
276			// is safe.
277			std::mem::transmute::<&mut Vec<CoreValue>, &mut Vec<Value>>(v)
278		}
279	}
280
281	#[allow(dead_code)]
282	pub(crate) fn array_to_core(v: Vec<Value>) -> Vec<CoreValue> {
283		unsafe {
284			// SAFETY: Because Value is `repr(transparent)` transmuting between value and corevalue
285			// is safe.
286			std::mem::transmute::<Vec<Value>, Vec<CoreValue>>(v)
287		}
288	}
289
290	#[allow(dead_code)]
291	pub(crate) fn array_to_core_ref(v: &Vec<Value>) -> &Vec<CoreValue> {
292		unsafe {
293			// SAFETY: Because Value is `repr(transparent)` transmuting between value and corevalue
294			// is safe.
295			std::mem::transmute::<&Vec<Value>, &Vec<CoreValue>>(v)
296		}
297	}
298
299	#[allow(dead_code)]
300	pub(crate) fn array_to_core_mut(v: &mut Vec<Value>) -> &mut Vec<CoreValue> {
301		unsafe {
302			// SAFETY: Because Value is `repr(transparent)` transmuting between value and corevalue
303			// is safe.
304			std::mem::transmute::<&mut Vec<Value>, &mut Vec<CoreValue>>(v)
305		}
306	}
307}
308
309pub struct ConversionError {
310	from: &'static str,
311	expected: &'static str,
312}
313
314impl fmt::Display for ConversionError {
315	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316		writeln!(
317			f,
318			"failed to convert into `{}` from value with type `{:?}`",
319			self.expected, self.from
320		)
321	}
322}
323
324/// The action performed on a record
325///
326/// This is used in live query notifications.
327#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
328#[non_exhaustive]
329pub enum Action {
330	Create,
331	Update,
332	Delete,
333}
334
335impl Action {
336	pub(crate) fn from_core(action: CoreAction) -> Self {
337		match action {
338			CoreAction::Create => Self::Create,
339			CoreAction::Update => Self::Update,
340			CoreAction::Delete => Self::Delete,
341			_ => panic!("unimplemented variant of action"),
342		}
343	}
344}
345
346/// A live query notification
347///
348/// Live queries return a stream of notifications. The notification contains an `action` that triggered the change in the database record and `data` itself.
349/// For deletions the data is the record before it was deleted. For everything else, it's the newly created record or updated record depending on whether
350/// the action is create or update.
351#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
352#[non_exhaustive]
353pub struct Notification<R> {
354	pub query_id: Uuid,
355	pub action: Action,
356	pub data: R,
357}
358
359impl Notification<CoreValue> {
360	pub fn map_deserialize<R>(self) -> Result<Notification<R>, crate::error::Db>
361	where
362		R: DeserializeOwned,
363	{
364		let data = surrealdb_core::sql::from_value(self.data)?;
365		Ok(Notification {
366			query_id: self.query_id,
367			action: self.action,
368			data,
369		})
370	}
371}