1use super::comparison::double_cmp;
2use super::get_string;
3use crate::registry::*;
4use akar_common::types::Value;
5
6#[derive(Clone, Copy)]
9pub(crate) struct ValueRef<'a>(pub(crate) &'a Value);
10
11impl<'a> PartialEq for ValueRef<'a> {
12 #[inline]
13 fn eq(&self, other: &Self) -> bool {
14 self.0 == other.0
15 }
16}
17
18impl<'a> Eq for ValueRef<'a> {}
19
20impl<'a> std::hash::Hash for ValueRef<'a> {
21 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
22 std::mem::discriminant(self.0).hash(state);
23 match self.0 {
24 Value::Null => {}
25 Value::Bool(b) => b.hash(state),
26 Value::Int64(i) => i.hash(state),
27 Value::Int32(i) => i.hash(state),
28 Value::Int16(i) => i.hash(state),
29 Value::Int8(i) => i.hash(state),
30 Value::UInt64(u) => u.hash(state),
31 Value::UInt32(u) => u.hash(state),
32 Value::UInt16(u) => u.hash(state),
33 Value::UInt8(u) => u.hash(state),
34 Value::Int128(i) => i.hash(state),
35 Value::UInt128(u) => u.hash(state),
36 Value::Double(f) => {
37 let bits = if f.is_nan() {
38 0x7ff8000000000000u64
39 } else if *f == 0.0 {
40 0u64
41 } else {
42 f.to_bits()
43 };
44 bits.hash(state);
45 }
46 Value::Float(f) => {
47 let bits = if f.is_nan() {
48 0x7fc00000u32
49 } else if *f == 0.0 {
50 0u32
51 } else {
52 f.to_bits()
53 };
54 bits.hash(state);
55 }
56 Value::String(s) => s.hash(state),
57 Value::Blob(b) => b.hash(state),
58 Value::Date(d) => d.0.hash(state),
59 Value::Timestamp(t) => t.0.hash(state),
60 Value::TimestampTz(t) => t.0.hash(state),
61 Value::TimestampNs(t) => t.0.hash(state),
62 Value::TimestampMs(t) => t.0.hash(state),
63 Value::TimestampSec(t) => t.0.hash(state),
64 Value::Interval(inv) => {
65 inv.months.hash(state);
66 inv.days.hash(state);
67 inv.micros.hash(state);
68 }
69 Value::InternalID(id) => {
70 id.table_id.hash(state);
71 id.offset.hash(state);
72 }
73 Value::DTime(t) => t.hash(state),
74 Value::Union(tag, val) => {
75 tag.hash(state);
76 ValueRef(val).hash(state);
77 }
78 Value::List(items) => {
79 for item in items {
80 ValueRef(item).hash(state);
81 }
82 }
83 Value::Map(entries) => {
84 for (k, v) in entries {
85 ValueRef(k).hash(state);
86 ValueRef(v).hash(state);
87 }
88 }
89 Value::Struct(fields) => {
90 for (k, v) in fields {
91 k.hash(state);
92 ValueRef(v).hash(state);
93 }
94 }
95 Value::Json(j) => {
96 j.to_string().hash(state);
97 }
98 }
99 }
100}
101
102pub(crate) fn evaluate_list(op: ListOp, args: &[Value]) -> Result<Value, String> {
105 match op {
106 ListOp::Creation => {
107 Ok(Value::List(args.to_vec()))
109 }
110 ListOp::Len => match &args[0] {
111 Value::List(items) => Ok(Value::Int64(items.len() as i64)),
112 _ => Err("Expected list".into()),
113 },
114 ListOp::Extract => {
115 let list = match &args[0] {
116 Value::List(items) => items,
117 _ => return Err("Expected list".into()),
118 };
119 let idx = match &args[1] {
120 Value::Int64(i) => {
121 if *i < 1 {
123 return Err("List index must be >= 1".into());
124 }
125 (*i - 1) as usize
126 }
127 _ => return Err("Index must be integer".into()),
128 };
129 list.get(idx)
130 .cloned()
131 .ok_or_else(|| format!("Index {idx} out of bounds"))
132 }
133 ListOp::Concat => {
134 let mut result = Vec::new();
135 for arg in args {
136 match arg {
137 Value::List(items) => result.extend(items.clone()),
138 _ => result.push(arg.clone()),
139 }
140 }
141 Ok(Value::List(result))
142 }
143 ListOp::Sort => {
144 let mut list = match args[0].clone() {
145 Value::List(items) => items,
146 _ => return Err("Expected list".into()),
147 };
148 list.sort_by(|a, b| {
150 match compare_values_for_sort(a, b) {
151 Ok(ord) => ord,
152 Err(_) => std::cmp::Ordering::Equal, }
154 });
155 Ok(Value::List(list))
156 }
157 ListOp::Contains => {
158 let list = match &args[0] {
159 Value::List(items) => items,
160 _ => return Err("Expected list".into()),
161 };
162 Ok(Value::Bool(list.contains(&args[1])))
163 }
164 ListOp::Append => {
165 let mut list = match args[0].clone() {
166 Value::List(items) => items,
167 _ => return Err("Expected list".into()),
168 };
169 list.push(args[1].clone());
170 Ok(Value::List(list))
171 }
172 ListOp::Prepend => {
173 let mut list = match args[0].clone() {
174 Value::List(items) => items,
175 _ => return Err("Expected list".into()),
176 };
177 list.insert(0, args[1].clone());
178 Ok(Value::List(list))
179 }
180 ListOp::Reverse => {
181 let mut list = match args[0].clone() {
182 Value::List(items) => items,
183 _ => return Err("Expected list".into()),
184 };
185 list.reverse();
186 Ok(Value::List(list))
187 }
188 ListOp::Slice => {
189 let list = match &args[0] {
190 Value::List(items) => items,
191 _ => return Err("Expected list".into()),
192 };
193 let start = match &args[1] {
194 Value::Int64(i) => {
195 if *i < 1 {
196 return Err("Slice start index must be >= 1".into());
197 }
198 (*i - 1) as usize
199 }
200 _ => return Err("Slice start must be integer".into()),
201 };
202 if start >= list.len() {
203 return Err("Slice start index out of bounds".into());
204 }
205 if args.len() >= 3 {
206 let end = match &args[2] {
208 Value::Int64(i) => {
209 if *i < 1 {
210 return Err("Slice end index must be >= 1".into());
211 }
212 (*i - 1) as usize
213 }
214 _ => return Err("Slice end must be integer".into()),
215 };
216 if end >= list.len() || end < start {
217 return Err("Slice end index out of bounds".into());
218 }
219 Ok(Value::List(list[start..=end].to_vec()))
220 } else {
221 Ok(Value::List(list[start..].to_vec()))
223 }
224 }
225 ListOp::Range => {
227 let step = if args.len() >= 3 {
228 match &args[2] {
229 Value::Int64(s) => *s,
230 _ => 1i64,
231 }
232 } else {
233 1i64
234 };
235 let (start, end) = if args.len() >= 2 {
236 match (&args[0], &args[1]) {
237 (Value::Int64(s), Value::Int64(e)) => (*s, *e),
238 _ => return Err("RANGE requires integer arguments".into()),
239 }
240 } else {
241 match &args[0] {
242 Value::Int64(e) => (0i64, *e),
243 _ => return Err("RANGE requires integer arguments".into()),
244 }
245 };
246 if step == 0 {
247 return Err("Step of range cannot be 0".into());
248 }
249 if (end - start).signum() != step.signum() && end != start {
250 Ok(Value::List(vec![]))
251 } else {
252 let size = ((end - start).unsigned_abs() / step.unsigned_abs()) + 1;
253 let items: Vec<Value> = (0..size).map(|i| Value::Int64(start + step * i as i64)).collect();
254 Ok(Value::List(items))
255 }
256 }
257 ListOp::Distinct => {
258 let list = match &args[0] {
259 Value::List(items) => items,
260 _ => return Err("Expected list".into()),
261 };
262 let mut seen = hashbrown::HashSet::with_capacity(list.len());
263 let mut result = Vec::new();
264 for item in list {
265 if !matches!(item, Value::Null) && seen.insert(ValueRef(item)) {
266 result.push(item.clone());
267 }
268 }
269 Ok(Value::List(result))
270 }
271 ListOp::Unique => {
272 let list = match &args[0] {
273 Value::List(items) => items,
274 _ => return Err("Expected list".into()),
275 };
276 let mut seen = hashbrown::HashSet::with_capacity(list.len());
277 for item in list {
278 if !matches!(item, Value::Null) {
279 seen.insert(ValueRef(item));
280 }
281 }
282 Ok(Value::Int64(seen.len() as i64))
283 }
284 ListOp::Count => {
285 let list = match &args[0] {
286 Value::List(items) => items,
287 _ => return Err("Expected list".into()),
288 };
289 let val = &args[1];
290 let mut count = 0;
291 for item in list {
292 if item == val {
293 count += 1;
294 }
295 }
296 Ok(Value::Int64(count as i64))
297 }
298 ListOp::Min => {
299 let list = match &args[0] {
300 Value::List(items) => items,
301 _ => return Err("Expected list".into()),
302 };
303 if list.is_empty() {
304 return Ok(Value::Null);
305 }
306 let mut min_val = list[0].clone();
307 for item in list.iter().skip(1) {
308 if let Ok(std::cmp::Ordering::Less) = compare_values_for_sort(item, &min_val) {
309 min_val = item.clone();
310 }
311 }
312 Ok(min_val)
313 }
314 ListOp::Max => {
315 let list = match &args[0] {
316 Value::List(items) => items,
317 _ => return Err("Expected list".into()),
318 };
319 if list.is_empty() {
320 return Ok(Value::Null);
321 }
322 let mut max_val = list[0].clone();
323 for item in list.iter().skip(1) {
324 if let Ok(std::cmp::Ordering::Greater) = compare_values_for_sort(item, &max_val) {
325 max_val = item.clone();
326 }
327 }
328 Ok(max_val)
329 }
330 ListOp::HasAny => {
331 let list = match &args[0] {
332 Value::List(items) => items,
333 _ => return Err("Expected list".into()),
334 };
335 let search_items = match &args[1] {
336 Value::List(items) => items,
337 _ => return Err("Expected list for second argument".into()),
338 };
339 if list.len() <= 8 && search_items.len() <= 8 {
340 for search_item in search_items {
341 if list.contains(search_item) {
342 return Ok(Value::Bool(true));
343 }
344 }
345 return Ok(Value::Bool(false));
346 }
347 if list.len() <= search_items.len() {
348 let mut set = hashbrown::HashSet::with_capacity(list.len());
349 for item in list {
350 set.insert(ValueRef(item));
351 }
352 for search_item in search_items {
353 if set.contains(&ValueRef(search_item)) {
354 return Ok(Value::Bool(true));
355 }
356 }
357 } else {
358 let mut set = hashbrown::HashSet::with_capacity(search_items.len());
359 for search_item in search_items {
360 set.insert(ValueRef(search_item));
361 }
362 for item in list {
363 if set.contains(&ValueRef(item)) {
364 return Ok(Value::Bool(true));
365 }
366 }
367 }
368 Ok(Value::Bool(false))
369 }
370 ListOp::Sum => {
371 let list = match &args[0] {
372 Value::List(items) => items,
373 _ => return Err("Expected list".into()),
374 };
375 let mut sum: f64 = 0.0;
376 let mut is_int = true;
377 for item in list {
378 match item {
379 Value::Null => continue,
380 Value::Int64(x) => sum += *x as f64,
381 Value::Double(x) => {
382 sum += x;
383 is_int = false;
384 }
385 _ => return Err("LIST_SUM requires numeric list".into()),
386 }
387 }
388 if is_int {
389 Ok(Value::Int64(sum as i64))
390 } else {
391 Ok(Value::Double(sum))
392 }
393 }
394 ListOp::Product => {
395 let list = match &args[0] {
396 Value::List(items) => items,
397 _ => return Err("Expected list".into()),
398 };
399 let mut prod: f64 = 1.0;
400 let mut is_int = true;
401 for item in list {
402 match item {
403 Value::Null => continue,
404 Value::Int64(x) => prod *= *x as f64,
405 Value::Double(x) => {
406 prod *= x;
407 is_int = false;
408 }
409 _ => return Err("LIST_PRODUCT requires numeric list".into()),
410 }
411 }
412 if is_int {
413 Ok(Value::Int64(prod as i64))
414 } else {
415 Ok(Value::Double(prod))
416 }
417 }
418 ListOp::AnyValue => {
419 let list = match &args[0] {
420 Value::List(items) => items,
421 _ => return Err("Expected list".into()),
422 };
423 match list.iter().find(|v| !matches!(v, Value::Null)) {
425 Some(v) => Ok(v.clone()),
426 None => Ok(Value::Null),
427 }
428 }
429 ListOp::ToString => {
430 if args.len() < 2 {
432 return Err("list_to_string requires delimiter and list arguments".into());
433 }
434 let delim = get_string(&args[0])?;
435 let list = match &args[1] {
436 Value::List(items) => items,
437 _ => return Err("Expected list".into()),
438 };
439 let mut result = String::new();
440 let mut first = true;
441 for item in list {
442 if matches!(item, Value::Null) {
443 continue;
444 }
445 if !first {
446 result.push_str(&delim);
447 }
448 match item {
449 Value::String(s) => result.push_str(s),
450 other => result.push_str(&format!("{:?}", other)),
451 }
452 first = false;
453 }
454 Ok(Value::String(result))
455 }
456 ListOp::Position => {
457 let list = match &args[0] {
458 Value::List(items) => items,
459 _ => return Err("Expected list".into()),
460 };
461 let target = &args[1];
462 for (i, item) in list.iter().enumerate() {
464 if item == target {
465 return Ok(Value::Int64((i + 1) as i64));
466 }
467 }
468 Ok(Value::Int64(0))
469 }
470 ListOp::HasAll => {
471 let left = match &args[0] {
472 Value::List(items) => items,
473 _ => return Err("Expected list".into()),
474 };
475 let right = match &args[1] {
476 Value::List(items) => items,
477 _ => return Err("Expected list".into()),
478 };
479 if left.len() <= 8 {
480 for target in right {
481 if matches!(target, Value::Null) {
482 continue;
483 }
484 if !left.contains(target) {
485 return Ok(Value::Bool(false));
486 }
487 }
488 return Ok(Value::Bool(true));
489 }
490 let mut set = hashbrown::HashSet::with_capacity(left.len());
491 for item in left {
492 set.insert(ValueRef(item));
493 }
494 for target in right {
495 if matches!(target, Value::Null) {
496 continue;
497 }
498 if !set.contains(&ValueRef(target)) {
499 return Ok(Value::Bool(false));
500 }
501 }
502 Ok(Value::Bool(true))
503 }
504 ListOp::ReverseSort => {
505 let mut list = match args[0].clone() {
506 Value::List(items) => items,
507 _ => return Err("Expected list".into()),
508 };
509 list.sort_by(|a, b| match compare_values_for_sort(a, b) {
510 Ok(ord) => ord.reverse(),
511 Err(_) => std::cmp::Ordering::Equal,
512 });
513 Ok(Value::List(list))
514 }
515 ListOp::Any => {
517 let list = match &args[0] {
518 Value::List(items) => items,
519 _ => return Err("Expected list".into()),
520 };
521 Ok(Value::Bool(list.iter().any(is_truthy)))
522 }
523 ListOp::All => {
524 let list = match &args[0] {
525 Value::List(items) => items,
526 _ => return Err("Expected list".into()),
527 };
528 Ok(Value::Bool(!list.is_empty() && list.iter().all(is_truthy)))
529 }
530 ListOp::None => {
531 let list = match &args[0] {
532 Value::List(items) => items,
533 _ => return Err("Expected list".into()),
534 };
535 Ok(Value::Bool(list.iter().all(|v| !is_truthy(v))))
536 }
537 ListOp::Single => {
538 let list = match &args[0] {
539 Value::List(items) => items,
540 _ => return Err("Expected list".into()),
541 };
542 let count = list.iter().filter(|v| is_truthy(v)).count();
543 Ok(Value::Bool(count == 1))
544 }
545 ListOp::Transform => Err("list_transform requires a lambda expression — use in a query context".into()),
547 ListOp::Filter => Err("list_filter requires a lambda expression — use in a query context".into()),
548 ListOp::Reduce => Err("list_reduce requires a lambda expression — use in a query context".into()),
549 }
550}
551
552fn is_truthy(v: &Value) -> bool {
554 match v {
555 Value::Bool(b) => *b,
556 Value::Int64(x) => *x != 0,
557 Value::Double(x) => *x != 0.0,
558 _ => false,
559 }
560}
561
562pub(crate) fn compare_values_for_sort(a: &Value, b: &Value) -> Result<std::cmp::Ordering, String> {
564 match (a, b) {
565 (Value::Null, Value::Null) => Ok(std::cmp::Ordering::Equal),
566 (Value::Null, _) => Ok(std::cmp::Ordering::Less),
567 (_, Value::Null) => Ok(std::cmp::Ordering::Greater),
568 (Value::Int64(x), Value::Int64(y)) => Ok(x.cmp(y)),
569 (Value::Int32(x), Value::Int32(y)) => Ok(x.cmp(y)),
570 (Value::Int16(x), Value::Int16(y)) => Ok(x.cmp(y)),
571 (Value::Int8(x), Value::Int8(y)) => Ok(x.cmp(y)),
572 (Value::UInt64(x), Value::UInt64(y)) => Ok(x.cmp(y)),
573 (Value::UInt32(x), Value::UInt32(y)) => Ok(x.cmp(y)),
574 (Value::UInt16(x), Value::UInt16(y)) => Ok(x.cmp(y)),
575 (Value::UInt8(x), Value::UInt8(y)) => Ok(x.cmp(y)),
576 (Value::Double(x), Value::Double(y)) => Ok(double_cmp(*x, *y)),
577 (Value::Float(x), Value::Float(y)) => Ok(double_cmp(*x as f64, *y as f64)),
578 (Value::String(x), Value::String(y)) => Ok(x.cmp(y)),
579 (Value::Bool(x), Value::Bool(y)) => Ok(x.cmp(y)),
580 (Value::Date(x), Value::Date(y)) => Ok(x.cmp(y)),
581 (Value::Timestamp(x), Value::Timestamp(y)) => Ok(x.cmp(y)),
582 (Value::Int64(x), Value::Double(y)) => Ok(double_cmp(*x as f64, *y)),
584 (Value::Double(x), Value::Int64(y)) => Ok(double_cmp(*x, *y as f64)),
585 _ => Err("Cannot compare types for sort".into()),
586 }
587}