surrealdb_expr/val/
array.rs1use std::collections::{BTreeSet, HashSet, VecDeque};
2use std::ops::{Deref, DerefMut};
3
4use anyhow::{Result, ensure};
5use revision::revisioned;
6use storekey::{BorrowDecode, Encode};
7use surrealdb_types::{SqlFormat, ToSql};
8
9use crate::expr::{Error, Expr};
10use crate::val::{IndexFormat, Set, Value};
11
12#[revisioned(revision(1), revision(2, optimised))]
20#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Hash, Encode, BorrowDecode)]
21#[storekey(format = "()")]
22#[storekey(format = "IndexFormat")]
23pub struct Array(#[revision(indexed_seq)] pub Vec<Value>);
24
25impl<T> From<Vec<T>> for Array
26where
27 Value: From<T>,
28{
29 fn from(v: Vec<T>) -> Self {
30 v.into_iter().map(Value::from).collect()
31 }
32}
33
34impl From<Array> for Vec<Value> {
35 fn from(s: Array) -> Self {
36 s.0
37 }
38}
39
40impl TryFrom<Array> for crate::types::PublicArray {
41 type Error = anyhow::Error;
42
43 fn try_from(s: Array) -> Result<Self, Self::Error> {
44 Ok(crate::types::PublicArray::from(
45 s.0.into_iter()
46 .map(crate::types::PublicValue::try_from)
47 .collect::<Result<Vec<_>, _>>()?,
48 ))
49 }
50}
51
52impl From<crate::types::PublicArray> for Array {
53 fn from(s: crate::types::PublicArray) -> Self {
54 Array(s.into_iter().map(Value::from).collect())
55 }
56}
57
58impl FromIterator<Value> for Array {
59 fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self {
60 Array(iter.into_iter().collect())
61 }
62}
63
64impl Deref for Array {
65 type Target = Vec<Value>;
66 fn deref(&self) -> &Self::Target {
67 &self.0
68 }
69}
70
71impl DerefMut for Array {
72 fn deref_mut(&mut self) -> &mut Self::Target {
73 &mut self.0
74 }
75}
76
77impl IntoIterator for Array {
78 type Item = Value;
79 type IntoIter = std::vec::IntoIter<Self::Item>;
80 fn into_iter(self) -> Self::IntoIter {
81 self.0.into_iter()
82 }
83}
84
85impl Array {
86 pub fn new() -> Self {
88 Self::default()
89 }
90 pub fn with_capacity(len: usize) -> Self {
92 Self(Vec::with_capacity(len))
93 }
94 pub fn len(&self) -> usize {
96 self.0.len()
97 }
98 pub fn is_empty(&self) -> bool {
100 self.0.is_empty()
101 }
102
103 pub fn into_literal(self) -> Vec<Expr> {
104 self.into_iter().map(|x| x.into_literal()).collect()
105 }
106
107 pub fn is_all_none_or_null(&self) -> bool {
108 self.0.iter().all(|v| v.is_nullish())
109 }
110
111 pub fn is_any_none_or_null(&self) -> bool {
112 self.0.iter().any(|v| v.is_nullish())
113 }
114
115 pub fn remove_value(mut self, other: &Value) -> Self {
117 self.retain(|x| x != other);
118 self
119 }
120
121 pub fn remove_all(mut self, other: &[Value]) -> Self {
123 self.retain(|x| !other.contains(x));
124 self
125 }
126
127 pub fn remove_all_set(mut self, other: &Set) -> Self {
129 self.retain(|x| !other.contains(x));
130 self
131 }
132
133 pub fn concat(mut self, mut other: Array) -> Self {
135 self.0.append(&mut other.0);
136 self
137 }
138
139 pub fn concat_set(mut self, other: Set) -> Self {
141 self.0.append(&mut other.0.into_iter().collect());
142 self
143 }
144
145 pub fn with_push(mut self, other: Value) -> Self {
147 self.0.push(other);
148 self
149 }
150
151 pub fn transpose(self) -> Array {
185 if self.is_empty() {
186 return self;
187 }
188
189 let height = self
190 .iter()
191 .map(|x| {
192 if let Some(x) = x.as_array() {
193 x.len()
194 } else {
195 1
196 }
197 })
198 .max()
199 .unwrap_or(0);
200
201 let mut transposed_vec = vec![vec![Value::None; self.len()]; height];
202
203 for (idx, i) in self.into_iter().enumerate() {
204 match i {
205 Value::Array(j) => {
206 for (jdx, j) in j.into_iter().enumerate() {
207 transposed_vec[jdx][idx] = j;
208 }
209 }
210 x => {
211 transposed_vec[0][idx] = x;
212 }
213 }
214 }
215
216 transposed_vec.into()
217 }
218}
219
220impl ToSql for Array {
221 fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
222 f.push('[');
223 if !self.is_empty() {
224 let inner_fmt = fmt.increment();
225 if fmt.is_pretty() {
226 f.push('\n');
227 inner_fmt.write_indent(f);
228 }
229 for (i, value) in self.0.iter().enumerate() {
230 if i > 0 {
231 inner_fmt.write_separator(f);
232 }
233 value.fmt_sql(f, inner_fmt);
234 }
235 if fmt.is_pretty() {
236 f.push('\n');
237 fmt.write_indent(f);
238 }
239 }
240 f.push(']');
241 }
242}
243
244pub trait Clump<T> {
247 fn clump(self, clump_size: usize) -> Result<T>;
248}
249
250impl Clump<Array> for Array {
251 fn clump(self, clump_size: usize) -> Result<Array> {
252 ensure!(
253 clump_size >= 1,
254 Error::InvalidFunctionArguments {
255 name: "array::clump".to_string(),
256 message: "The second argument must be an integer greater than 0".to_string(),
257 }
258 );
259
260 Ok(self
261 .0
262 .chunks(clump_size)
263 .map::<Value, _>(|chunk| chunk.to_vec().into())
264 .collect::<Vec<_>>()
265 .into())
266 }
267}
268
269pub trait Combine<T> {
272 fn combine(self, other: T) -> T;
273}
274
275impl Combine<Array> for Array {
276 fn combine(self, other: Self) -> Array {
277 let mut out = Self::with_capacity(self.len().saturating_mul(other.len()));
278 for a in self.iter() {
279 for b in other.iter() {
280 out.push(vec![a.clone(), b.clone()].into());
281 }
282 }
283 out
284 }
285}
286
287pub trait Complement<T> {
290 fn complement(self, other: T) -> T;
291}
292
293impl Complement<Array> for Array {
294 #[expect(clippy::mutable_key_type)]
295 fn complement(self, other: Self) -> Array {
296 let mut out = Array::with_capacity(self.len());
297 let mut set = BTreeSet::new();
298 for i in other.iter() {
299 set.insert(i);
300 }
301 for v in self {
302 if !set.contains(&v) {
303 out.push(v)
304 }
305 }
306 out
307 }
308}
309
310pub trait Difference<T> {
313 fn difference(self, other: T) -> T;
314}
315
316impl Difference<Array> for Array {
317 fn difference(self, other: Array) -> Array {
318 let mut out = Array::with_capacity(self.len() + other.len());
319 let mut other = VecDeque::from(other.0);
320 for v in self {
321 if let Some(pos) = other.iter().position(|w| v == *w) {
322 other.remove(pos);
323 } else {
324 out.push(v);
325 }
326 }
327 out.append(&mut Vec::from(other));
328 out
329 }
330}
331
332pub trait Flatten<T> {
335 fn flatten(self) -> T;
336}
337
338impl Flatten<Array> for Array {
339 fn flatten(self) -> Array {
340 let mut out = Array::with_capacity(self.len());
341 for v in self {
342 match v {
343 Value::Array(mut a) => out.append(&mut a),
344 _ => out.push(v),
345 }
346 }
347 out
348 }
349}
350
351pub trait Intersect<T> {
354 fn intersect(self, other: T) -> T;
355}
356
357impl Intersect<Self> for Array {
358 fn intersect(self, mut other: Self) -> Self {
359 let mut out = Self::new();
360 for v in self.0 {
361 if let Some(pos) = other.iter().position(|w| v == *w) {
362 other.remove(pos);
363 out.push(v);
364 }
365 }
366 out
367 }
368}
369
370pub trait Matches<T> {
374 fn matches(self, compare_val: Value) -> T;
381}
382
383impl Matches<Array> for Array {
384 fn matches(self, compare_val: Value) -> Array {
385 self.iter().map(|arr_val| (arr_val == &compare_val).into()).collect::<Vec<Value>>().into()
386 }
387}
388
389pub trait Union<T> {
392 fn union(self, other: T) -> T;
393}
394
395impl Union<Self> for Array {
396 fn union(mut self, mut other: Self) -> Array {
397 self.append(&mut other);
398 self.uniq()
399 }
400}
401
402pub trait Uniq<T> {
405 fn uniq(self) -> T;
406}
407
408impl Uniq<Array> for Array {
409 fn uniq(self) -> Array {
410 #[expect(clippy::mutable_key_type)]
411 let mut set = HashSet::with_capacity(self.len());
412 let mut to_return = Array::with_capacity(self.len());
413 for i in self.iter() {
414 if set.insert(i) {
415 to_return.push(i.clone());
416 }
417 }
418 to_return
419 }
420}
421
422pub trait Windows<T> {
425 fn windows(self, window_size: usize) -> Result<T>;
426}
427
428impl Windows<Array> for Array {
429 fn windows(self, window_size: usize) -> Result<Array> {
430 ensure!(
431 window_size >= 1,
432 Error::InvalidFunctionArguments {
433 name: "array::windows".to_string(),
434 message: "The second argument must be an integer greater than 0".to_string(),
435 }
436 );
437
438 Ok(self
439 .0
440 .windows(window_size)
441 .map::<Value, _>(|chunk| chunk.to_vec().into())
442 .collect::<Vec<_>>()
443 .into())
444 }
445}