surrealdb_core/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::err::Error;
10use crate::expr::Expr;
11use crate::val::{IndexFormat, Value};
12
13#[revisioned(revision = 1)]
14#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Hash, Encode, BorrowDecode)]
15#[storekey(format = "()")]
16#[storekey(format = "IndexFormat")]
17pub(crate) struct Array(pub(crate) Vec<Value>);
18
19impl<T> From<Vec<T>> for Array
20where
21 Value: From<T>,
22{
23 fn from(v: Vec<T>) -> Self {
24 v.into_iter().map(Value::from).collect()
25 }
26}
27
28impl From<Array> for Vec<Value> {
29 fn from(s: Array) -> Self {
30 s.0
31 }
32}
33
34impl TryFrom<Array> for crate::types::PublicArray {
35 type Error = anyhow::Error;
36
37 fn try_from(s: Array) -> Result<Self, Self::Error> {
38 Ok(crate::types::PublicArray::from(
39 s.0.into_iter()
40 .map(crate::types::PublicValue::try_from)
41 .collect::<Result<Vec<_>, _>>()?,
42 ))
43 }
44}
45
46impl From<crate::types::PublicArray> for Array {
47 fn from(s: crate::types::PublicArray) -> Self {
48 Array(s.into_iter().map(Value::from).collect())
49 }
50}
51
52impl FromIterator<Value> for Array {
53 fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self {
54 Array(iter.into_iter().collect())
55 }
56}
57
58impl Deref for Array {
59 type Target = Vec<Value>;
60 fn deref(&self) -> &Self::Target {
61 &self.0
62 }
63}
64
65impl DerefMut for Array {
66 fn deref_mut(&mut self) -> &mut Self::Target {
67 &mut self.0
68 }
69}
70
71impl IntoIterator for Array {
72 type Item = Value;
73 type IntoIter = std::vec::IntoIter<Self::Item>;
74 fn into_iter(self) -> Self::IntoIter {
75 self.0.into_iter()
76 }
77}
78
79impl Array {
80 pub fn new() -> Self {
82 Self::default()
83 }
84 pub fn with_capacity(len: usize) -> Self {
86 Self(Vec::with_capacity(len))
87 }
88 pub fn len(&self) -> usize {
90 self.0.len()
91 }
92 pub fn is_empty(&self) -> bool {
94 self.0.is_empty()
95 }
96
97 pub fn into_literal(self) -> Vec<Expr> {
98 self.into_iter().map(|x| x.into_literal()).collect()
99 }
100
101 pub(crate) fn is_all_none_or_null(&self) -> bool {
102 self.0.iter().all(|v| v.is_nullish())
103 }
104
105 pub(crate) fn is_any_none_or_null(&self) -> bool {
106 self.0.iter().any(|v| v.is_nullish())
107 }
108
109 pub fn remove_value(mut self, other: &Value) -> Self {
111 self.retain(|x| x != other);
112 self
113 }
114
115 pub fn remove_all(mut self, other: &[Value]) -> Self {
117 self.retain(|x| !other.contains(x));
118 self
119 }
120
121 pub fn concat(mut self, mut other: Array) -> Self {
123 self.0.append(&mut other.0);
124 self
125 }
126
127 pub fn with_push(mut self, other: Value) -> Self {
129 self.0.push(other);
130 self
131 }
132
133 pub(crate) fn transpose(self) -> Array {
167 if self.is_empty() {
168 return self;
169 }
170
171 let height = self
172 .iter()
173 .map(|x| {
174 if let Some(x) = x.as_array() {
175 x.len()
176 } else {
177 1
178 }
179 })
180 .max()
181 .unwrap_or(0);
182
183 let mut transposed_vec = vec![vec![Value::None; self.len()]; height];
184
185 for (idx, i) in self.into_iter().enumerate() {
186 match i {
187 Value::Array(j) => {
188 for (jdx, j) in j.into_iter().enumerate() {
189 transposed_vec[jdx][idx] = j;
190 }
191 }
192 x => {
193 transposed_vec[0][idx] = x;
194 }
195 }
196 }
197
198 transposed_vec.into()
199 }
200}
201
202impl ToSql for Array {
203 fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
204 f.push('[');
205 if !self.is_empty() {
206 let inner_fmt = fmt.increment();
207 if fmt.is_pretty() {
208 f.push('\n');
209 inner_fmt.write_indent(f);
210 }
211 for (i, value) in self.0.iter().enumerate() {
212 if i > 0 {
213 inner_fmt.write_separator(f);
214 }
215 value.fmt_sql(f, inner_fmt);
216 }
217 if fmt.is_pretty() {
218 f.push('\n');
219 fmt.write_indent(f);
220 }
221 }
222 f.push(']');
223 }
224}
225
226pub(crate) trait Clump<T> {
229 fn clump(self, clump_size: usize) -> Result<T>;
230}
231
232impl Clump<Array> for Array {
233 fn clump(self, clump_size: usize) -> Result<Array> {
234 ensure!(
235 clump_size >= 1,
236 Error::InvalidFunctionArguments {
237 name: "array::clump".to_string(),
238 message: "The second argument must be an integer greater than 0".to_string(),
239 }
240 );
241
242 Ok(self
243 .0
244 .chunks(clump_size)
245 .map::<Value, _>(|chunk| chunk.to_vec().into())
246 .collect::<Vec<_>>()
247 .into())
248 }
249}
250
251pub(crate) trait Combine<T> {
254 fn combine(self, other: T) -> T;
255}
256
257impl Combine<Array> for Array {
258 fn combine(self, other: Self) -> Array {
259 let mut out = Self::with_capacity(self.len().saturating_mul(other.len()));
260 for a in self.iter() {
261 for b in other.iter() {
262 out.push(vec![a.clone(), b.clone()].into());
263 }
264 }
265 out
266 }
267}
268
269pub(crate) trait Complement<T> {
272 fn complement(self, other: T) -> T;
273}
274
275impl Complement<Array> for Array {
276 #[expect(clippy::mutable_key_type)]
277 fn complement(self, other: Self) -> Array {
278 let mut out = Array::with_capacity(self.len());
279 let mut set = BTreeSet::new();
280 for i in other.iter() {
281 set.insert(i);
282 }
283 for v in self {
284 if !set.contains(&v) {
285 out.push(v)
286 }
287 }
288 out
289 }
290}
291
292pub(crate) trait Difference<T> {
295 fn difference(self, other: T) -> T;
296}
297
298impl Difference<Array> for Array {
299 fn difference(self, other: Array) -> Array {
300 let mut out = Array::with_capacity(self.len() + other.len());
301 let mut other = VecDeque::from(other.0);
302 for v in self {
303 if let Some(pos) = other.iter().position(|w| v == *w) {
304 other.remove(pos);
305 } else {
306 out.push(v);
307 }
308 }
309 out.append(&mut Vec::from(other));
310 out
311 }
312}
313
314pub(crate) trait Flatten<T> {
317 fn flatten(self) -> T;
318}
319
320impl Flatten<Array> for Array {
321 fn flatten(self) -> Array {
322 let mut out = Array::with_capacity(self.len());
323 for v in self {
324 match v {
325 Value::Array(mut a) => out.append(&mut a),
326 _ => out.push(v),
327 }
328 }
329 out
330 }
331}
332
333pub(crate) trait Intersect<T> {
336 fn intersect(self, other: T) -> T;
337}
338
339impl Intersect<Self> for Array {
340 fn intersect(self, mut other: Self) -> Self {
341 let mut out = Self::new();
342 for v in self.0 {
343 if let Some(pos) = other.iter().position(|w| v == *w) {
344 other.remove(pos);
345 out.push(v);
346 }
347 }
348 out
349 }
350}
351
352pub(crate) trait Matches<T> {
356 fn matches(self, compare_val: Value) -> T;
363}
364
365impl Matches<Array> for Array {
366 fn matches(self, compare_val: Value) -> Array {
367 self.iter().map(|arr_val| (arr_val == &compare_val).into()).collect::<Vec<Value>>().into()
368 }
369}
370
371pub(crate) trait Union<T> {
374 fn union(self, other: T) -> T;
375}
376
377impl Union<Self> for Array {
378 fn union(mut self, mut other: Self) -> Array {
379 self.append(&mut other);
380 self.uniq()
381 }
382}
383
384pub(crate) trait Uniq<T> {
387 fn uniq(self) -> T;
388}
389
390impl Uniq<Array> for Array {
391 fn uniq(self) -> Array {
392 #[expect(clippy::mutable_key_type)]
393 let mut set = HashSet::with_capacity(self.len());
394 let mut to_return = Array::with_capacity(self.len());
395 for i in self.iter() {
396 if set.insert(i) {
397 to_return.push(i.clone());
398 }
399 }
400 to_return
401 }
402}
403
404pub(crate) trait Windows<T> {
407 fn windows(self, window_size: usize) -> Result<T>;
408}
409
410impl Windows<Array> for Array {
411 fn windows(self, window_size: usize) -> Result<Array> {
412 ensure!(
413 window_size >= 1,
414 Error::InvalidFunctionArguments {
415 name: "array::windows".to_string(),
416 message: "The second argument must be an integer greater than 0".to_string(),
417 }
418 );
419
420 Ok(self
421 .0
422 .windows(window_size)
423 .map::<Value, _>(|chunk| chunk.to_vec().into())
424 .collect::<Vec<_>>()
425 .into())
426 }
427}