1use std::cmp::Ordering;
2use std::collections::BTreeMap;
3use std::sync::{Arc, Mutex};
4
5use rust_decimal::Decimal;
6use rust_decimal::prelude::ToPrimitive;
7use teaql_core::{
8 Aggregate, AggregateFunction, BinaryOp, DeleteCommand, Entity, Expr, ExprFunction,
9 InsertCommand, Record, RecoverCommand, RelationAggregate, SelectQuery, SmartList,
10 SortDirection, UpdateCommand, Value,
11};
12
13use crate::{DataServiceError, InMemoryMetadataStore, MetadataStore, RuntimeError};
14
15#[derive(Debug)]
16pub enum MemoryDataServiceError {
17 Poisoned,
18 UnsupportedExpression(String),
19 UnsupportedAggregate(String),
20}
21
22impl std::fmt::Display for MemoryDataServiceError {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 match self {
25 Self::Poisoned => write!(f, "memory data service lock poisoned"),
26 Self::UnsupportedExpression(message) => {
27 write!(f, "unsupported memory expression: {message}")
28 }
29 Self::UnsupportedAggregate(message) => {
30 write!(f, "unsupported memory aggregate: {message}")
31 }
32 }
33 }
34}
35
36impl std::error::Error for MemoryDataServiceError {}
37
38#[derive(Debug, Clone)]
39pub struct MemoryDataService<M = InMemoryMetadataStore> {
40 metadata: M,
41 data: Arc<Mutex<BTreeMap<String, Vec<Record>>>>,
42}
43
44impl<M> MemoryDataService<M>
45where
46 M: MetadataStore,
47{
48 pub fn new(metadata: M) -> Self {
49 Self {
50 metadata,
51 data: Arc::new(Mutex::new(BTreeMap::new())),
52 }
53 }
54
55 pub fn with_rows(mut self, entity: impl Into<String>, rows: Vec<Record>) -> Self {
56 self.seed(entity, rows);
57 self
58 }
59
60 pub fn seed(&mut self, entity: impl Into<String>, rows: Vec<Record>) {
61 if let Ok(mut data) = self.data.lock() {
62 data.insert(entity.into(), rows);
63 }
64 }
65
66 pub fn fetch_all(
67 &self,
68 query: &SelectQuery,
69 ) -> Result<Vec<Record>, DataServiceError<MemoryDataServiceError>> {
70 self.require_entity(&query.entity)?;
71 let data = self
72 .data
73 .lock()
74 .map_err(|_| DataServiceError::Executor(MemoryDataServiceError::Poisoned))?;
75 let mut rows = data.get(&query.entity).cloned().unwrap_or_default();
76 drop(data);
77
78 if let Some(filter) = &query.filter {
79 rows = rows
80 .into_iter()
81 .filter_map(|row| match eval_filter(filter, &row) {
82 Ok(true) => Some(Ok(row)),
83 Ok(false) => None,
84 Err(err) => Some(Err(err)),
85 })
86 .collect::<Result<Vec<_>, _>>()
87 .map_err(DataServiceError::Executor)?;
88 }
89
90 if !query.aggregates.is_empty() {
91 return aggregate_rows(query, &rows).map_err(DataServiceError::Executor);
92 }
93
94 apply_ordering(&mut rows, query);
95 rows = apply_slice(rows, query);
96 if !query.projection.is_empty() || !query.expr_projection.is_empty() {
97 rows = rows
98 .into_iter()
99 .map(|row| project_row(row, query))
100 .collect::<Result<Vec<_>, _>>()
101 .map_err(DataServiceError::Executor)?;
102 }
103 Ok(rows)
104 }
105
106 pub fn fetch_smart_list(
107 &self,
108 query: &SelectQuery,
109 ) -> Result<SmartList<Record>, DataServiceError<MemoryDataServiceError>> {
110 self.fetch_all(query).map(SmartList::from)
111 }
112
113 pub fn fetch_entities<T>(
114 &self,
115 query: &SelectQuery,
116 ) -> Result<SmartList<T>, DataServiceError<MemoryDataServiceError>>
117 where
118 T: Entity,
119 {
120 self.fetch_all(query)?
121 .into_iter()
122 .map(T::from_record)
123 .collect::<Result<Vec<_>, _>>()
124 .map(SmartList::from)
125 .map_err(DataServiceError::Entity)
126 }
127
128 pub fn fetch_all_with_relation_aggregates(
129 &self,
130 query: &SelectQuery,
131 relation_aggregates: &[RelationAggregate],
132 ) -> Result<Vec<Record>, DataServiceError<MemoryDataServiceError>> {
133 let mut rows = self.fetch_all(query)?;
134 self.enhance_relation_aggregates(&query.entity, &mut rows, relation_aggregates)?;
135 Ok(rows)
136 }
137
138 pub fn fetch_smart_list_with_relation_aggregates(
139 &self,
140 query: &SelectQuery,
141 relation_aggregates: &[RelationAggregate],
142 ) -> Result<SmartList<Record>, DataServiceError<MemoryDataServiceError>> {
143 self.fetch_all_with_relation_aggregates(query, relation_aggregates)
144 .map(SmartList::from)
145 }
146
147 pub fn fetch_entities_with_relation_aggregates<T>(
148 &self,
149 query: &SelectQuery,
150 relation_aggregates: &[RelationAggregate],
151 ) -> Result<SmartList<T>, DataServiceError<MemoryDataServiceError>>
152 where
153 T: Entity,
154 {
155 self.fetch_all_with_relation_aggregates(query, relation_aggregates)?
156 .into_iter()
157 .map(T::from_record)
158 .collect::<Result<Vec<_>, _>>()
159 .map(SmartList::from)
160 .map_err(DataServiceError::Entity)
161 }
162
163 pub fn enhance_relation_aggregates(
164 &self,
165 parent_entity: &str,
166 parent_rows: &mut [Record],
167 relation_aggregates: &[RelationAggregate],
168 ) -> Result<(), DataServiceError<MemoryDataServiceError>> {
169 for aggregate in relation_aggregates {
170 self.enhance_relation_aggregate(parent_entity, parent_rows, aggregate)?;
171 }
172 Ok(())
173 }
174
175 fn enhance_relation_aggregate(
176 &self,
177 parent_entity: &str,
178 parent_rows: &mut [Record],
179 aggregate: &RelationAggregate,
180 ) -> Result<(), DataServiceError<MemoryDataServiceError>> {
181 let descriptor = self.metadata.entity(parent_entity).ok_or_else(|| {
182 DataServiceError::Runtime(RuntimeError::MissingEntity(parent_entity.to_owned()))
183 })?;
184
185 let relation = descriptor
186 .relation_by_name(&aggregate.relation_name)
187 .ok_or_else(|| {
188 DataServiceError::Runtime(RuntimeError::MissingRelation {
189 entity: parent_entity.to_owned(),
190 relation: aggregate.relation_name.clone(),
191 })
192 })?;
193
194 let ids = parent_rows
195 .iter()
196 .filter_map(|row| row.get(&relation.local_key).cloned())
197 .collect::<Vec<_>>();
198
199 if ids.is_empty() {
200 let value = default_aggregate_value(aggregate.single_result);
201 for parent in parent_rows.iter_mut() {
202 parent.insert(aggregate.alias.clone(), value.clone());
203 }
204 return Ok(());
205 }
206
207 let mut query = aggregate.query.clone();
208 query.entity = relation.target_entity.clone();
209 query.projection.clear();
210 query.expr_projection.clear();
211 query.order_by.clear();
212 query.slice = None;
213 query.relations.clear();
214 if query.aggregates.is_empty() {
215 let alias = aggregate_alias(aggregate.single_result, &aggregate.alias);
216 query = query.aggregate(Aggregate::count(alias));
217 }
218 if !query
219 .group_by
220 .iter()
221 .any(|field| field == &relation.foreign_key)
222 {
223 query = query.group_by(relation.foreign_key.clone());
224 }
225 query = query.and_filter(Expr::in_list(relation.foreign_key.clone(), ids));
226
227 let aggregate_rows = self.fetch_all(&query)?;
228
229 let mut buckets: BTreeMap<String, Vec<Record>> = BTreeMap::new();
230 for mut row in aggregate_rows {
231 if let Some(key) = row.remove(&relation.foreign_key) {
232 let bucket_key = local_graph_identity_key(&key);
233 buckets.entry(bucket_key).or_default().push(row);
234 }
235 }
236
237 for parent in parent_rows {
238 let value = parent
239 .get(&relation.local_key)
240 .and_then(|local_value| buckets.get(&local_graph_identity_key(local_value)))
241 .map(|rows| local_relation_aggregate_value(rows, aggregate.single_result))
242 .unwrap_or_else(|| default_aggregate_value(aggregate.single_result));
243 parent.insert(aggregate.alias.clone(), value);
244 }
245
246 Ok(())
247 }
248
249 pub fn insert(
250 &self,
251 command: &InsertCommand,
252 ) -> Result<u64, DataServiceError<MemoryDataServiceError>> {
253 self.require_entity(&command.entity)?;
254 let mut data = self
255 .data
256 .lock()
257 .map_err(|_| DataServiceError::Executor(MemoryDataServiceError::Poisoned))?;
258 data.entry(command.entity.clone())
259 .or_default()
260 .push(command.values.clone());
261 Ok(1)
262 }
263
264 pub fn update(
265 &self,
266 command: &UpdateCommand,
267 ) -> Result<u64, DataServiceError<MemoryDataServiceError>> {
268 let (id_property, version_property) = self.id_and_version_properties(&command.entity)?;
269 let mut data = self
270 .data
271 .lock()
272 .map_err(|_| DataServiceError::Executor(MemoryDataServiceError::Poisoned))?;
273 let rows = data.entry(command.entity.clone()).or_default();
274 let Some(row) = rows
275 .iter_mut()
276 .find(|row| row.get(id_property) == Some(&command.id))
277 else {
278 return self.maybe_optimistic_conflict(
279 command.expected_version,
280 &command.entity,
281 &command.id,
282 );
283 };
284
285 if let Some(expected) = command.expected_version {
286 if row.get(version_property) != Some(&Value::I64(expected)) {
287 println!(
288 "OptimisticLockConflict in memory.rs update! entity={}, id={:?}, expected={}, existing={:?}",
289 command.entity,
290 command.id,
291 expected,
292 row.get(version_property)
293 );
294 return Err(DataServiceError::Runtime(
295 RuntimeError::OptimisticLockConflict {
296 entity: command.entity.clone(),
297 id: format!("{:?}", command.id),
298 },
299 ));
300 }
301 row.insert(version_property.to_owned(), Value::I64(expected + 1));
302 }
303
304 for (key, value) in &command.values {
305 row.insert(key.clone(), value.clone());
306 }
307 Ok(1)
308 }
309
310 pub fn delete(
311 &self,
312 command: &DeleteCommand,
313 ) -> Result<u64, DataServiceError<MemoryDataServiceError>> {
314 let (id_property, version_property) = self.id_and_version_properties(&command.entity)?;
315 let mut data = self
316 .data
317 .lock()
318 .map_err(|_| DataServiceError::Executor(MemoryDataServiceError::Poisoned))?;
319 let rows = data.entry(command.entity.clone()).or_default();
320 let Some(index) = rows
321 .iter()
322 .position(|row| row.get(id_property) == Some(&command.id))
323 else {
324 return self.maybe_optimistic_conflict(
325 command.expected_version,
326 &command.entity,
327 &command.id,
328 );
329 };
330
331 if let Some(expected_version) = command.expected_version {
332 if rows[index].get(version_property) != Some(&Value::I64(expected_version)) {
333 return Err(DataServiceError::Runtime(
334 RuntimeError::OptimisticLockConflict {
335 entity: command.entity.clone(),
336 id: format!("{:?}", command.id),
337 },
338 ));
339 }
340 }
341
342 match command.soft_delete {
343 true => {
344 let next_version = command
345 .expected_version
346 .or_else(|| read_i64(rows[index].get(version_property)))
347 .map(|version| -(version.abs() + 1))
348 .unwrap_or(-1);
349 rows[index].insert(version_property.to_owned(), Value::I64(next_version));
350 }
351 false => { rows.remove(index); }
352 }
353 Ok(1)
354 }
355
356 pub fn recover(
357 &self,
358 command: &RecoverCommand,
359 ) -> Result<u64, DataServiceError<MemoryDataServiceError>> {
360 let (id_property, version_property) = self.id_and_version_properties(&command.entity)?;
361 let mut data = self
362 .data
363 .lock()
364 .map_err(|_| DataServiceError::Executor(MemoryDataServiceError::Poisoned))?;
365 let rows = data.entry(command.entity.clone()).or_default();
366 let Some(row) = rows
367 .iter_mut()
368 .find(|row| row.get(id_property) == Some(&command.id))
369 else {
370 return Err(DataServiceError::Runtime(
371 RuntimeError::OptimisticLockConflict {
372 entity: command.entity.clone(),
373 id: format!("{:?}", command.id),
374 },
375 ));
376 };
377
378 if row.get(version_property) != Some(&Value::I64(command.expected_version)) {
379 return Err(DataServiceError::Runtime(
380 RuntimeError::OptimisticLockConflict {
381 entity: command.entity.clone(),
382 id: format!("{:?}", command.id),
383 },
384 ));
385 }
386
387 row.insert(
388 version_property.to_owned(),
389 Value::I64(command.expected_version.abs() + 1),
390 );
391 Ok(1)
392 }
393
394 fn require_entity(&self, entity: &str) -> Result<(), DataServiceError<MemoryDataServiceError>> {
395 self.metadata.entity(entity).map(|_| ()).ok_or_else(|| {
396 DataServiceError::Runtime(RuntimeError::MissingEntity(entity.to_owned()))
397 })
398 }
399
400 fn id_and_version_properties(
401 &self,
402 entity: &str,
403 ) -> Result<(&str, &str), DataServiceError<MemoryDataServiceError>> {
404 let descriptor = self.metadata.entity(entity).ok_or_else(|| {
405 DataServiceError::Runtime(RuntimeError::MissingEntity(entity.to_owned()))
406 })?;
407 let id = descriptor
408 .id_property()
409 .map(|property| property.name.as_str())
410 .unwrap_or("id");
411 let version = descriptor
412 .version_property()
413 .map(|property| property.name.as_str())
414 .unwrap_or("version");
415 Ok((id, version))
416 }
417
418 fn maybe_optimistic_conflict(
419 &self,
420 expected_version: Option<i64>,
421 entity: &str,
422 id: &Value,
423 ) -> Result<u64, DataServiceError<MemoryDataServiceError>> {
424 let Some(_) = expected_version else {
425 return Ok(0);
426 };
427 Err(DataServiceError::Runtime(
428 RuntimeError::OptimisticLockConflict {
429 entity: entity.to_owned(),
430 id: format!("{id:?}"),
431 },
432 ))
433 }
434}
435
436fn default_aggregate_value(single_result: bool) -> Value {
437 match single_result {
438 true => Value::U64(0),
439 false => Value::List(Vec::new()),
440 }
441}
442
443fn aggregate_alias(single_result: bool, alias: &str) -> String {
444 match single_result {
445 true => alias.to_owned(),
446 false => "count".to_owned(),
447 }
448}
449
450fn local_relation_aggregate_value(rows: &[Record], single_result: bool) -> Value {
451 match single_result {
452 true => rows
453 .first()
454 .map(local_single_relation_aggregate_value)
455 .unwrap_or(Value::U64(0)),
456 false => Value::List(rows.iter().cloned().map(Value::object).collect()),
457 }
458}
459
460fn local_single_relation_aggregate_value(row: &Record) -> Value {
461 match row.len() {
462 1 => row.values().next().cloned().unwrap_or(Value::Null),
463 _ => Value::object(row.clone()),
464 }
465}
466
467fn eval_filter(expr: &Expr, row: &Record) -> Result<bool, MemoryDataServiceError> {
468 match expr {
469 Expr::Column(_) | Expr::Value(_) | Expr::Function { .. } => {
470 value_truthy(&eval_value(expr, row)?)
471 }
472 Expr::Binary { left, op, right } => {
473 let left = eval_value(left, row)?;
474 let right = eval_value(right, row)?;
475 eval_binary(&left, *op, &right)
476 }
477 Expr::SubQuery { .. } => Err(MemoryDataServiceError::UnsupportedExpression(
478 "subquery filters require a SQL executor".to_owned(),
479 )),
480 Expr::Between { expr, lower, upper } => {
481 let value = eval_value(expr, row)?;
482 let lower = eval_value(lower, row)?;
483 let upper = eval_value(upper, row)?;
484 Ok(compare_values(&value, &lower) != Some(Ordering::Less)
485 && compare_values(&value, &upper) != Some(Ordering::Greater))
486 }
487 Expr::IsNull(expr) => Ok(matches!(eval_value(expr, row)?, Value::Null)),
488 Expr::IsNotNull(expr) => Ok(!matches!(eval_value(expr, row)?, Value::Null)),
489 Expr::And(parts) => {
490 for part in parts {
491 if !eval_filter(part, row)? {
492 return Ok(false);
493 }
494 }
495 Ok(true)
496 }
497 Expr::Or(parts) => {
498 for part in parts {
499 if eval_filter(part, row)? {
500 return Ok(true);
501 }
502 }
503 Ok(false)
504 }
505 Expr::Not(expr) => Ok(!eval_filter(expr, row)?),
506 }
507}
508
509fn eval_value(expr: &Expr, row: &Record) -> Result<Value, MemoryDataServiceError> {
510 match expr {
511 Expr::Column(column) => Ok(row.get(column).cloned().unwrap_or(Value::Null)),
512 Expr::Value(value) => Ok(value.clone()),
513 Expr::Function { function, args } => eval_function(*function, args, row),
514 other => Err(MemoryDataServiceError::UnsupportedExpression(format!(
515 "cannot evaluate {other:?} as a scalar value"
516 ))),
517 }
518}
519
520fn eval_function(
521 function: ExprFunction,
522 args: &[Expr],
523 row: &Record,
524) -> Result<Value, MemoryDataServiceError> {
525 match function {
526 ExprFunction::Soundex => {
527 let [arg] = args else {
528 return Err(MemoryDataServiceError::UnsupportedExpression(
529 "SOUNDEX expects exactly one argument".to_owned(),
530 ));
531 };
532 match eval_value(arg, row)? {
533 Value::Text(value) => Ok(Value::Text(soundex(&value))),
534 Value::Null => Ok(Value::Null),
535 other => Err(MemoryDataServiceError::UnsupportedExpression(format!(
536 "SOUNDEX expects text, got {other:?}"
537 ))),
538 }
539 }
540 ExprFunction::Gbk => {
541 let [arg] = args else {
542 return Err(MemoryDataServiceError::UnsupportedExpression(
543 "GBK expects exactly one argument".to_owned(),
544 ));
545 };
546 eval_value(arg, row)
547 }
548 other => Err(MemoryDataServiceError::UnsupportedExpression(format!(
549 "function {other:?} is only supported by SQL execution"
550 ))),
551 }
552}
553
554fn eval_binary(left: &Value, op: BinaryOp, right: &Value) -> Result<bool, MemoryDataServiceError> {
555 match op {
556 BinaryOp::Eq => Ok(values_equal(left, right)),
557 BinaryOp::Ne => Ok(!values_equal(left, right)),
558 BinaryOp::Gt => Ok(compare_values(left, right) == Some(Ordering::Greater)),
559 BinaryOp::Gte => Ok(matches!(
560 compare_values(left, right),
561 Some(Ordering::Greater | Ordering::Equal)
562 )),
563 BinaryOp::Lt => Ok(compare_values(left, right) == Some(Ordering::Less)),
564 BinaryOp::Lte => Ok(matches!(
565 compare_values(left, right),
566 Some(Ordering::Less | Ordering::Equal)
567 )),
568 BinaryOp::Like => match (left, right) {
569 (Value::Text(value), Value::Text(pattern)) => Ok(like_matches(value, pattern)),
570 _ => Ok(false),
571 },
572 BinaryOp::NotLike => match (left, right) {
573 (Value::Text(value), Value::Text(pattern)) => Ok(!like_matches(value, pattern)),
574 _ => Ok(true),
575 },
576 BinaryOp::In | BinaryOp::InLarge => match right {
577 Value::List(values) => Ok(values.iter().any(|value| values_equal(left, value))),
578 _ => Err(MemoryDataServiceError::UnsupportedExpression(
579 "IN expects a list value".to_owned(),
580 )),
581 },
582 BinaryOp::NotIn | BinaryOp::NotInLarge => match right {
583 Value::List(values) => Ok(!values.iter().any(|value| values_equal(left, value))),
584 _ => Err(MemoryDataServiceError::UnsupportedExpression(
585 "NOT IN expects a list value".to_owned(),
586 )),
587 },
588 }
589}
590
591fn value_truthy(value: &Value) -> Result<bool, MemoryDataServiceError> {
592 match value {
593 Value::Bool(value) => Ok(*value),
594 Value::Null => Ok(false),
595 other => Err(MemoryDataServiceError::UnsupportedExpression(format!(
596 "non-boolean expression result: {other:?}"
597 ))),
598 }
599}
600
601fn values_equal(left: &Value, right: &Value) -> bool {
602 match (left, right) {
603 (Value::I64(left), Value::U64(right)) if *left >= 0 => *left as u64 == *right,
604 (Value::U64(left), Value::I64(right)) if *right >= 0 => *left == *right as u64,
605 _ => left == right,
606 }
607}
608
609fn compare_values(left: &Value, right: &Value) -> Option<Ordering> {
610 match (left, right) {
611 (Value::I64(left), Value::I64(right)) => Some(left.cmp(right)),
612 (Value::U64(left), Value::U64(right)) => Some(left.cmp(right)),
613 (Value::I64(left), Value::U64(right)) if *left >= 0 => Some((*left as u64).cmp(right)),
614 (Value::U64(left), Value::I64(right)) if *right >= 0 => Some(left.cmp(&(*right as u64))),
615 (Value::F64(left), Value::F64(right)) => left.partial_cmp(right),
616 (Value::Decimal(left), Value::Decimal(right)) => Some(left.cmp(right)),
617 (Value::Text(left), Value::Text(right)) => Some(left.cmp(right)),
618 (Value::Date(left), Value::Date(right)) => Some(left.cmp(right)),
619 (Value::Timestamp(left), Value::Timestamp(right)) => Some(left.cmp(right)),
620 _ => None,
621 }
622}
623
624fn like_matches(value: &str, pattern: &str) -> bool {
625 if pattern == "%" {
626 return true;
627 }
628 match (pattern.strip_prefix('%'), pattern.strip_suffix('%')) {
629 (Some(inner), Some(_)) if pattern.len() >= 2 => value.contains(&inner[..inner.len() - 1]),
630 (Some(suffix), None) => value.ends_with(suffix),
631 (None, Some(prefix)) => value.starts_with(prefix),
632 _ => value == pattern,
633 }
634}
635
636fn soundex(value: &str) -> String {
637 let mut letters = value
638 .chars()
639 .filter(|ch| ch.is_ascii_alphabetic())
640 .map(|ch| ch.to_ascii_uppercase());
641 let Some(first) = letters.next() else {
642 return "0000".to_owned();
643 };
644
645 let mut output = String::with_capacity(4);
646 output.push(first);
647 let mut previous_code = soundex_code(first);
648
649 for ch in letters {
650 let code = soundex_code(ch);
651 if code != '0' && code != previous_code {
652 output.push(code);
653 if output.len() == 4 {
654 return output;
655 }
656 }
657 previous_code = code;
658 }
659
660 while output.len() < 4 {
661 output.push('0');
662 }
663 output
664}
665
666fn soundex_code(ch: char) -> char {
667 match ch {
668 'B' | 'F' | 'P' | 'V' => '1',
669 'C' | 'G' | 'J' | 'K' | 'Q' | 'S' | 'X' | 'Z' => '2',
670 'D' | 'T' => '3',
671 'L' => '4',
672 'M' | 'N' => '5',
673 'R' => '6',
674 _ => '0',
675 }
676}
677
678fn apply_ordering(rows: &mut [Record], query: &SelectQuery) {
679 for order in query.order_by.iter().rev() {
680 rows.sort_by(|left, right| {
681 let resolve = |row: &Record| -> Option<Value> {
682 match &order.expr {
683 Some(expr) => eval_value(expr, row).ok(),
684 None => row.get(&order.field).cloned(),
685 }
686 };
687 let left_value = resolve(left);
688 let right_value = resolve(right);
689 let ordering = match (left_value.as_ref(), right_value.as_ref()) {
690 (Some(left), Some(right)) => compare_values(left, right).unwrap_or(Ordering::Equal),
691 (None, Some(_)) => Ordering::Less,
692 (Some(_), None) => Ordering::Greater,
693 (None, None) => Ordering::Equal,
694 };
695 match order.direction {
696 SortDirection::Asc => ordering,
697 SortDirection::Desc => ordering.reverse(),
698 }
699 });
700 }
701}
702
703fn apply_slice(rows: Vec<Record>, query: &SelectQuery) -> Vec<Record> {
704 let Some(slice) = query.slice else {
705 return rows;
706 };
707 let offset = usize::try_from(slice.offset).unwrap_or(usize::MAX);
708 let limit = slice
709 .limit
710 .and_then(|limit| usize::try_from(limit).ok())
711 .unwrap_or(usize::MAX);
712 rows.into_iter().skip(offset).take(limit).collect()
713}
714
715fn project_row(row: Record, query: &SelectQuery) -> Result<Record, MemoryDataServiceError> {
716 let mut output: Record = query
717 .projection
718 .iter()
719 .filter_map(|field| row.get(field).cloned().map(|value| (field.clone(), value)))
720 .collect();
721 for projection in &query.expr_projection {
722 output.insert(
723 projection.alias.clone(),
724 eval_value(&projection.expr, &row)?,
725 );
726 }
727 Ok(output)
728}
729
730fn aggregate_rows(
731 query: &SelectQuery,
732 rows: &[Record],
733) -> Result<Vec<Record>, MemoryDataServiceError> {
734 let mut groups: BTreeMap<Vec<String>, Vec<&Record>> = BTreeMap::new();
735 match query.group_by.is_empty() {
736 true => { groups.insert(Vec::new(), rows.iter().collect()); }
737 false => {
738 for row in rows {
739 let key = query
740 .group_by
741 .iter()
742 .map(|field| row.get(field).map(value_key).unwrap_or_default())
743 .collect::<Vec<_>>();
744 groups.entry(key).or_default().push(row);
745 }
746 }
747 }
748
749 let rows = groups
750 .into_values()
751 .map(|rows| {
752 let mut output = Record::new();
753 if let Some(first) = rows.first() {
754 for field in &query.group_by {
755 if let Some(value) = first.get(field) {
756 output.insert(field.clone(), value.clone());
757 }
758 }
759 }
760 for aggregate in &query.aggregates {
761 let value = match aggregate.function {
762 AggregateFunction::Count => count_rows(&rows, &aggregate.field),
763 AggregateFunction::Sum => numeric_sum(&rows, &aggregate.field)?,
764 AggregateFunction::Avg => numeric_avg(&rows, &aggregate.field)?,
765 AggregateFunction::Min => min_max(&rows, &aggregate.field, false)?,
766 AggregateFunction::Max => min_max(&rows, &aggregate.field, true)?,
767 AggregateFunction::Stddev => numeric_stddev(&rows, &aggregate.field, true)?,
768 AggregateFunction::StddevPop => numeric_stddev(&rows, &aggregate.field, false)?,
769 AggregateFunction::VarSamp => numeric_variance(&rows, &aggregate.field, true)?,
770 AggregateFunction::VarPop => numeric_variance(&rows, &aggregate.field, false)?,
771 AggregateFunction::BitAnd => {
772 bit_aggregate(&rows, &aggregate.field, BitOp::And)?
773 }
774 AggregateFunction::BitOr => bit_aggregate(&rows, &aggregate.field, BitOp::Or)?,
775 AggregateFunction::BitXor => {
776 bit_aggregate(&rows, &aggregate.field, BitOp::Xor)?
777 }
778 };
779 output.insert(aggregate.alias.clone(), value);
780 }
781 for projection in &query.expr_projection {
782 output.insert(
783 projection.alias.clone(),
784 eval_value(&projection.expr, &output)?,
785 );
786 }
787 Ok(output)
788 })
789 .collect::<Result<Vec<_>, _>>()?;
790 let Some(having) = &query.having else {
791 return Ok(rows);
792 };
793 rows.into_iter()
794 .filter_map(|row| match eval_filter(having, &row) {
795 Ok(true) => Some(Ok(row)),
796 Ok(false) => None,
797 Err(err) => Some(Err(err)),
798 })
799 .collect()
800}
801
802fn count_rows(rows: &[&Record], field: &str) -> Value {
804 let count = match field {
805 "*" => rows.len(),
806 _ => rows
807 .iter()
808 .filter(|row| !matches!(row.get(field), None | Some(Value::Null)))
809 .count(),
810 };
811 Value::U64(count as u64)
812}
813
814fn numeric_sum(rows: &[&Record], field: &str) -> Result<Value, MemoryDataServiceError> {
815 let mut decimal_sum = Decimal::ZERO;
816 let mut integer_sum: i128 = 0;
817 let mut saw_decimal = false;
818 for value in rows.iter().filter_map(|row| row.get(field)) {
819 match value {
820 Value::I64(value) => {
821 integer_sum += i128::from(*value);
822 decimal_sum += Decimal::from(*value);
823 }
824 Value::U64(value) => {
825 integer_sum += i128::from(*value);
826 decimal_sum += Decimal::from(*value);
827 }
828 Value::F64(value) => {
829 saw_decimal = true;
830 decimal_sum += decimal_from_f64(*value);
831 }
832 Value::Decimal(value) => {
833 saw_decimal = true;
834 decimal_sum += *value;
835 }
836 Value::Null => {}
837 other => {
838 return Err(MemoryDataServiceError::UnsupportedAggregate(format!(
839 "SUM does not support {other:?}"
840 )));
841 }
842 }
843 }
844 match (saw_decimal, integer_sum >= 0) {
845 (true, _) => Ok(Value::Decimal(decimal_sum)),
846 (_, true) => Ok(Value::U64(integer_sum as u64)),
847 _ => Ok(Value::I64(integer_sum as i64)),
848 }
849}
850
851fn numeric_avg(rows: &[&Record], field: &str) -> Result<Value, MemoryDataServiceError> {
852 let mut sum = Decimal::ZERO;
853 let mut count: u64 = 0;
854 for value in rows.iter().filter_map(|row| row.get(field)) {
855 match value {
856 Value::I64(value) => {
857 sum += Decimal::from(*value);
858 count += 1;
859 }
860 Value::U64(value) => {
861 sum += Decimal::from(*value);
862 count += 1;
863 }
864 Value::F64(value) => {
865 sum += decimal_from_f64(*value);
866 count += 1;
867 }
868 Value::Decimal(value) => {
869 sum += *value;
870 count += 1;
871 }
872 Value::Null => {}
873 other => {
874 return Err(MemoryDataServiceError::UnsupportedAggregate(format!(
875 "AVG does not support {other:?}"
876 )));
877 }
878 }
879 }
880 Ok((count > 0)
881 .then(|| Value::Decimal(sum / Decimal::from(count)))
882 .unwrap_or(Value::Null))
883}
884
885fn decimal_from_f64(value: f64) -> Decimal {
886 Decimal::from_f64_retain(value).unwrap_or(Decimal::ZERO)
887}
888
889fn numeric_values(rows: &[&Record], field: &str) -> Result<Vec<f64>, MemoryDataServiceError> {
890 rows.iter()
891 .filter_map(|row| row.get(field))
892 .filter(|value| !matches!(value, Value::Null))
893 .map(|value| match value {
894 Value::I64(value) => Ok(*value as f64),
895 Value::U64(value) => Ok(*value as f64),
896 Value::F64(value) => Ok(*value),
897 Value::Decimal(value) => value.to_f64().ok_or_else(|| {
898 MemoryDataServiceError::UnsupportedAggregate(format!(
899 "cannot convert decimal {value} to f64 for statistical aggregate"
900 ))
901 }),
902 other => Err(MemoryDataServiceError::UnsupportedAggregate(format!(
903 "numeric aggregate does not support {other:?}"
904 ))),
905 })
906 .collect()
907}
908
909fn numeric_variance(
910 rows: &[&Record],
911 field: &str,
912 sample: bool,
913) -> Result<Value, MemoryDataServiceError> {
914 let values = numeric_values(rows, field)?;
915 let count = values.len();
916 if count == 0 || (sample && count < 2) {
917 return Ok(Value::Null);
918 }
919 let mean = values.iter().sum::<f64>() / count as f64;
920 let sum = values
921 .iter()
922 .map(|value| {
923 let diff = value - mean;
924 diff * diff
925 })
926 .sum::<f64>();
927 let denominator = match sample { true => count - 1, false => count } as f64;
928 Ok(Value::Decimal(decimal_from_f64(sum / denominator)))
929}
930
931fn numeric_stddev(
932 rows: &[&Record],
933 field: &str,
934 sample: bool,
935) -> Result<Value, MemoryDataServiceError> {
936 Ok(match numeric_variance(rows, field, sample)? {
937 Value::Decimal(value) => {
938 Value::Decimal(decimal_from_f64(value.to_f64().unwrap_or(0.0).sqrt()))
939 }
940 Value::Null => Value::Null,
941 other => other,
942 })
943}
944
945#[derive(Debug, Clone, Copy)]
946enum BitOp {
947 And,
948 Or,
949 Xor,
950}
951
952fn bit_aggregate(
953 rows: &[&Record],
954 field: &str,
955 op: BitOp,
956) -> Result<Value, MemoryDataServiceError> {
957 let mut selected: Option<i64> = None;
958 for value in rows.iter().filter_map(|row| row.get(field)) {
959 let value = match value {
960 Value::I64(value) => *value,
961 Value::U64(value) => i64::try_from(*value).map_err(|_| {
962 MemoryDataServiceError::UnsupportedAggregate(format!(
963 "BIT aggregate u64 {value} exceeds i64 range"
964 ))
965 })?,
966 Value::Null => continue,
967 other => {
968 return Err(MemoryDataServiceError::UnsupportedAggregate(format!(
969 "BIT aggregate does not support {other:?}"
970 )));
971 }
972 };
973 selected = Some(match (selected, op) {
974 (None, _) => value,
975 (Some(current), BitOp::And) => current & value,
976 (Some(current), BitOp::Or) => current | value,
977 (Some(current), BitOp::Xor) => current ^ value,
978 });
979 }
980 Ok(selected.map(Value::I64).unwrap_or(Value::Null))
981}
982
983fn min_max(rows: &[&Record], field: &str, max: bool) -> Result<Value, MemoryDataServiceError> {
984 let mut selected: Option<Value> = None;
985 for value in rows.iter().filter_map(|row| row.get(field)) {
986 if matches!(value, Value::Null) {
987 continue;
988 }
989 match &selected {
990 None => selected = Some(value.clone()),
991 Some(current) => {
992 let Some(ordering) = compare_values(value, current) else {
993 return Err(MemoryDataServiceError::UnsupportedAggregate(format!(
994 "MIN/MAX does not support {value:?}"
995 )));
996 };
997 if (max && ordering == Ordering::Greater) || (!max && ordering == Ordering::Less) {
998 selected = Some(value.clone());
999 }
1000 }
1001 }
1002 }
1003 Ok(selected.unwrap_or(Value::Null))
1004}
1005
1006fn value_key(value: &Value) -> String {
1007 match value {
1008 Value::Null => "null".to_owned(),
1009 Value::Bool(value) => format!("b:{value}"),
1010 Value::I64(value) => format!("i:{value}"),
1011 Value::U64(value) => format!("u:{value}"),
1012 Value::F64(value) => format!("f:{value}"),
1013 Value::Decimal(value) => format!("d:{value}"),
1014 Value::Text(value) => format!("t:{value}"),
1015 Value::Json(value) => format!("j:{value}"),
1016 Value::Date(value) => format!("d:{value}"),
1017 Value::Timestamp(value) => format!("ts:{}", value.to_rfc3339()),
1018 Value::Object(_) => "object".to_owned(),
1019 Value::List(_) => "list".to_owned(),
1020 }
1021}
1022
1023fn read_i64(value: Option<&Value>) -> Option<i64> {
1024 match value {
1025 Some(Value::I64(value)) => Some(*value),
1026 _ => None,
1027 }
1028}
1029
1030fn local_graph_identity_key(value: &Value) -> String {
1031 match value {
1032 Value::I64(val) if *val >= 0 => format!("u:{}", *val as u64),
1033 Value::U64(val) => format!("u:{val}"),
1034 Value::Null => "null".to_owned(),
1035 Value::Bool(v) => format!("b:{v}"),
1036 Value::I64(v) => format!("i:{v}"),
1037 Value::F64(v) => format!("f:{v}"),
1038 Value::Decimal(v) => format!("d:{v}"),
1039 Value::Text(v) => format!("t:{v}"),
1040 Value::Json(v) => format!("j:{v}"),
1041 Value::Date(v) => format!("d:{v}"),
1042 Value::Timestamp(v) => format!("ts:{}", v.to_rfc3339()),
1043 Value::Object(_) => "o".to_owned(),
1044 Value::List(_) => "l".to_owned(),
1045 }
1046}