surrealdb_core/sql/
array.rs

1use crate::ctx::Context;
2use crate::dbs::Options;
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::sql::{
6	fmt::{pretty_indent, Fmt, Pretty},
7	Number, Operation, Value,
8};
9use reblessive::tree::Stk;
10use revision::revisioned;
11use serde::{Deserialize, Serialize};
12use std::collections::HashSet;
13use std::fmt::{self, Display, Formatter, Write};
14use std::ops;
15use std::ops::Deref;
16use std::ops::DerefMut;
17
18pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Array";
19
20#[revisioned(revision = 1)]
21#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
22#[serde(rename = "$surrealdb::private::sql::Array")]
23#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
24#[non_exhaustive]
25pub struct Array(pub Vec<Value>);
26
27impl From<Value> for Array {
28	fn from(v: Value) -> Self {
29		vec![v].into()
30	}
31}
32
33impl From<Vec<Value>> for Array {
34	fn from(v: Vec<Value>) -> Self {
35		Self(v)
36	}
37}
38
39impl From<Vec<i32>> for Array {
40	fn from(v: Vec<i32>) -> Self {
41		Self(v.into_iter().map(Value::from).collect())
42	}
43}
44
45impl From<Vec<f32>> for Array {
46	fn from(v: Vec<f32>) -> Self {
47		Self(v.into_iter().map(Value::from).collect())
48	}
49}
50
51impl From<Vec<f64>> for Array {
52	fn from(v: Vec<f64>) -> Self {
53		Self(v.into_iter().map(Value::from).collect())
54	}
55}
56
57impl From<Vec<usize>> for Array {
58	fn from(v: Vec<usize>) -> Self {
59		Self(v.into_iter().map(Value::from).collect())
60	}
61}
62
63impl From<Vec<&str>> for Array {
64	fn from(v: Vec<&str>) -> Self {
65		Self(v.into_iter().map(Value::from).collect())
66	}
67}
68
69impl From<Vec<String>> for Array {
70	fn from(v: Vec<String>) -> Self {
71		Self(v.into_iter().map(Value::from).collect())
72	}
73}
74
75impl From<Vec<Number>> for Array {
76	fn from(v: Vec<Number>) -> Self {
77		Self(v.into_iter().map(Value::from).collect())
78	}
79}
80
81impl From<Vec<Operation>> for Array {
82	fn from(v: Vec<Operation>) -> Self {
83		Self(v.into_iter().map(Value::from).collect())
84	}
85}
86
87impl From<Vec<bool>> for Array {
88	fn from(v: Vec<bool>) -> Self {
89		Self(v.into_iter().map(Value::from).collect())
90	}
91}
92
93impl From<Array> for Vec<Value> {
94	fn from(s: Array) -> Self {
95		s.0
96	}
97}
98
99impl FromIterator<Value> for Array {
100	fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self {
101		Array(iter.into_iter().collect())
102	}
103}
104
105impl Deref for Array {
106	type Target = Vec<Value>;
107	fn deref(&self) -> &Self::Target {
108		&self.0
109	}
110}
111
112impl DerefMut for Array {
113	fn deref_mut(&mut self) -> &mut Self::Target {
114		&mut self.0
115	}
116}
117
118impl IntoIterator for Array {
119	type Item = Value;
120	type IntoIter = std::vec::IntoIter<Self::Item>;
121	fn into_iter(self) -> Self::IntoIter {
122		self.0.into_iter()
123	}
124}
125
126impl Array {
127	// Create a new empty array
128	pub fn new() -> Self {
129		Self::default()
130	}
131	// Create a new array with capacity
132	pub fn with_capacity(len: usize) -> Self {
133		Self(Vec::with_capacity(len))
134	}
135	// Get the length of the array
136	pub fn len(&self) -> usize {
137		self.0.len()
138	}
139	// Check if there array is empty
140	pub fn is_empty(&self) -> bool {
141		self.0.is_empty()
142	}
143}
144
145impl Array {
146	/// Process this type returning a computed simple Value
147	pub(crate) async fn compute(
148		&self,
149		stk: &mut Stk,
150		ctx: &Context,
151		opt: &Options,
152		doc: Option<&CursorDoc>,
153	) -> Result<Value, Error> {
154		let mut x = Self::with_capacity(self.len());
155		for v in self.iter() {
156			match v.compute(stk, ctx, opt, doc).await {
157				Ok(v) => x.push(v),
158				Err(e) => return Err(e),
159			};
160		}
161		Ok(Value::Array(x))
162	}
163
164	pub(crate) fn is_all_none_or_null(&self) -> bool {
165		self.0.iter().all(|v| v.is_none_or_null())
166	}
167
168	/// Checks whether all array values are static values
169	pub(crate) fn is_static(&self) -> bool {
170		self.iter().all(Value::is_static)
171	}
172
173	/// Validate that an Array contains only computed Values
174	pub fn validate_computed(&self) -> Result<(), Error> {
175		self.iter().try_for_each(|v| v.validate_computed())
176	}
177}
178
179impl Display for Array {
180	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
181		let mut f = Pretty::from(f);
182		f.write_char('[')?;
183		if !self.is_empty() {
184			let indent = pretty_indent();
185			write!(f, "{}", Fmt::pretty_comma_separated(self.as_slice()))?;
186			drop(indent);
187		}
188		f.write_char(']')
189	}
190}
191
192// ------------------------------
193
194impl ops::Add<Value> for Array {
195	type Output = Self;
196	fn add(mut self, other: Value) -> Self {
197		self.0.push(other);
198		self
199	}
200}
201
202impl ops::Add for Array {
203	type Output = Self;
204	fn add(mut self, mut other: Self) -> Self {
205		self.0.append(&mut other.0);
206		self
207	}
208}
209
210// ------------------------------
211
212impl ops::Sub<Value> for Array {
213	type Output = Self;
214	fn sub(mut self, other: Value) -> Self {
215		if let Some(p) = self.0.iter().position(|x| *x == other) {
216			self.0.remove(p);
217		}
218		self
219	}
220}
221
222impl ops::Sub for Array {
223	type Output = Self;
224	fn sub(mut self, other: Self) -> Self {
225		for v in other.0 {
226			if let Some(p) = self.0.iter().position(|x| *x == v) {
227				self.0.remove(p);
228			}
229		}
230		self
231	}
232}
233
234// ------------------------------
235
236pub trait Abolish<T> {
237	fn abolish<F>(&mut self, f: F)
238	where
239		F: FnMut(usize) -> bool;
240}
241
242impl<T> Abolish<T> for Vec<T> {
243	fn abolish<F>(&mut self, mut f: F)
244	where
245		F: FnMut(usize) -> bool,
246	{
247		let mut i = 0;
248		// FIXME: use drain_filter once stabilized (https://github.com/rust-lang/rust/issues/43244)
249		// to avoid negation of the predicate return value.
250		self.retain(|_| {
251			let retain = !f(i);
252			i += 1;
253			retain
254		});
255	}
256}
257
258// ------------------------------
259
260pub(crate) trait Clump<T> {
261	fn clump(self, clump_size: usize) -> Result<T, Error>;
262}
263
264impl Clump<Array> for Array {
265	fn clump(self, clump_size: usize) -> Result<Array, Error> {
266		if clump_size < 1 {
267			return Err(Error::InvalidArguments {
268				name: "array::clump".to_string(),
269				message: "The second argument must be an integer greater than 0".to_string(),
270			});
271		}
272
273		Ok(self
274			.0
275			.chunks(clump_size)
276			.map::<Value, _>(|chunk| chunk.to_vec().into())
277			.collect::<Vec<_>>()
278			.into())
279	}
280}
281
282// ------------------------------
283
284pub(crate) trait Combine<T> {
285	fn combine(self, other: T) -> T;
286}
287
288impl Combine<Array> for Array {
289	fn combine(self, other: Self) -> Array {
290		let mut out = Self::with_capacity(self.len().saturating_mul(other.len()));
291		for a in self.iter() {
292			for b in other.iter() {
293				out.push(vec![a.clone(), b.clone()].into());
294			}
295		}
296		out
297	}
298}
299
300// ------------------------------
301
302pub(crate) trait Complement<T> {
303	fn complement(self, other: T) -> T;
304}
305
306impl Complement<Array> for Array {
307	fn complement(self, other: Self) -> Array {
308		let mut out = Array::new();
309		for v in self.into_iter() {
310			if !other.contains(&v) {
311				out.push(v)
312			}
313		}
314		out
315	}
316}
317
318// ------------------------------
319
320#[allow(dead_code)]
321pub(crate) trait Concat<T> {
322	fn concat(self, other: T) -> T;
323}
324
325impl Concat<Array> for Array {
326	fn concat(mut self, mut other: Array) -> Array {
327		self.append(&mut other);
328		self
329	}
330}
331
332impl Concat<String> for String {
333	fn concat(self, other: String) -> String {
334		self + &other
335	}
336}
337
338// ------------------------------
339
340pub(crate) trait Difference<T> {
341	fn difference(self, other: T) -> T;
342}
343
344impl Difference<Array> for Array {
345	fn difference(self, mut other: Array) -> Array {
346		let mut out = Array::new();
347		for v in self.into_iter() {
348			if let Some(pos) = other.iter().position(|w| v == *w) {
349				other.remove(pos);
350			} else {
351				out.push(v);
352			}
353		}
354		out.append(&mut other);
355		out
356	}
357}
358
359// ------------------------------
360
361pub(crate) trait Flatten<T> {
362	fn flatten(self) -> T;
363}
364
365impl Flatten<Array> for Array {
366	fn flatten(self) -> Array {
367		let mut out = Array::new();
368		for v in self.into_iter() {
369			match v {
370				Value::Array(mut a) => out.append(&mut a),
371				_ => out.push(v),
372			}
373		}
374		out
375	}
376}
377
378// ------------------------------
379
380pub(crate) trait Intersect<T> {
381	fn intersect(self, other: T) -> T;
382}
383
384impl Intersect<Self> for Array {
385	fn intersect(self, mut other: Self) -> Self {
386		let mut out = Self::new();
387		for v in self.0.into_iter() {
388			if let Some(pos) = other.iter().position(|w| v == *w) {
389				other.remove(pos);
390				out.push(v);
391			}
392		}
393		out
394	}
395}
396
397// ------------------------------
398
399// Documented with the assumption that it is just for arrays.
400pub(crate) trait Matches<T> {
401	/// Returns an array complimenting the original where each value is true or false
402	/// depending on whether it is == to the compared value.
403	///
404	/// Admittedly, this is most often going to be used in `count(array::matches($arr, $val))`
405	/// to count the number of times an element appears in an array but it's nice to have
406	/// this in addition.
407	fn matches(self, compare_val: Value) -> T;
408}
409
410impl Matches<Array> for Array {
411	fn matches(self, compare_val: Value) -> Array {
412		self.iter().map(|arr_val| (arr_val == &compare_val).into()).collect::<Vec<Value>>().into()
413	}
414}
415
416// ------------------------------
417
418// Documented with the assumption that it is just for arrays.
419pub(crate) trait Transpose<T> {
420	/// Stacks arrays on top of each other. This can serve as 2d array transposition.
421	///
422	/// The input array can contain regular values which are treated as arrays with
423	/// a single element.
424	///
425	/// It's best to think of the function as creating a layered structure of the arrays
426	/// rather than transposing them when the input is not a 2d array. See the examples
427	/// for what happense when the input arrays are not all the same size.
428	///
429	/// Here's a diagram:
430	/// [0, 1, 2, 3], [4, 5, 6]
431	/// ->
432	/// [0    | 1    | 2   |  3]
433	/// [4    | 5    | 6   ]
434	///  ^      ^      ^      ^
435	/// [0, 4] [1, 5] [2, 6] [3]
436	///
437	/// # Examples
438	///
439	/// ```ignore
440	/// fn array(sql: &str) -> Array {
441	///     unimplemented!();
442	/// }
443	///
444	/// // Example of `transpose` doing what it says on the tin.
445	/// assert_eq!(array("[[0, 1], [2, 3]]").transpose(), array("[[0, 2], [1, 3]]"));
446	/// // `transpose` can be thought of layering arrays on top of each other so when
447	/// // one array runs out, it stops appearing in the output.
448	/// assert_eq!(array("[[0, 1], [2]]").transpose(), array("[[0, 2], [1]]"));
449	/// assert_eq!(array("[0, 1, 2]").transpose(), array("[[0, 1, 2]]"));
450	/// ```
451	fn transpose(self) -> T;
452}
453
454impl Transpose<Array> for Array {
455	fn transpose(self) -> Array {
456		if self.is_empty() {
457			return self;
458		}
459		// I'm sure there's a way more efficient way to do this that I don't know about.
460		// The new array will be at *least* this large so we can start there;
461		let mut transposed_vec = Vec::<Value>::with_capacity(self.len());
462		let mut iters = self
463			.iter()
464			.map(|v| {
465				if let Value::Array(arr) = v {
466					Box::new(arr.iter().cloned()) as Box<dyn ExactSizeIterator<Item = Value>>
467				} else {
468					Box::new(std::iter::once(v).cloned())
469						as Box<dyn ExactSizeIterator<Item = Value>>
470				}
471			})
472			.collect::<Vec<_>>();
473		// We know there is at least one element in the array therefore iters is not empty.
474		// This is safe.
475		let longest_length = iters.iter().map(|i| i.len()).max().unwrap();
476		for _ in 0..longest_length {
477			transposed_vec.push(
478				iters
479					.iter_mut()
480					.map(|i| i.next().unwrap_or(Value::None))
481					.collect::<Vec<_>>()
482					.into(),
483			);
484		}
485		transposed_vec.into()
486	}
487}
488
489// ------------------------------
490
491pub(crate) trait Union<T> {
492	fn union(self, other: T) -> T;
493}
494
495impl Union<Self> for Array {
496	fn union(mut self, mut other: Self) -> Array {
497		self.append(&mut other);
498		self.uniq()
499	}
500}
501
502// ------------------------------
503
504pub(crate) trait Uniq<T> {
505	fn uniq(self) -> T;
506}
507
508impl Uniq<Array> for Array {
509	fn uniq(mut self) -> Array {
510		#[allow(clippy::mutable_key_type)]
511		let mut set: HashSet<&Value> = HashSet::new();
512		let mut to_remove: Vec<usize> = Vec::new();
513		for (i, item) in self.iter().enumerate() {
514			if !set.insert(item) {
515				to_remove.push(i);
516			}
517		}
518		for i in to_remove.iter().rev() {
519			self.remove(*i);
520		}
521		self
522	}
523}
524
525// ------------------------------
526
527pub(crate) trait Windows<T> {
528	fn windows(self, window_size: usize) -> Result<T, Error>;
529}
530
531impl Windows<Array> for Array {
532	fn windows(self, window_size: usize) -> Result<Array, Error> {
533		if window_size < 1 {
534			return Err(Error::InvalidArguments {
535				name: "array::windows".to_string(),
536				message: "The second argument must be an integer greater than 0".to_string(),
537			});
538		}
539
540		Ok(self
541			.0
542			.windows(window_size)
543			.map::<Value, _>(|chunk| chunk.to_vec().into())
544			.collect::<Vec<_>>()
545			.into())
546	}
547}