1use crate::db::internal_bytes;
26use crate::error::{KitError, Result};
27use crate::internal::{cols, iso_now, ROW_GUARDS, UNIQUE_KEYS};
28use crate::query::{project_distinct, run_aggregate, run_join, run_select, ExecCtx, JoinRow};
29use crate::schema::{core_row_to_json, json_to_core, pk_to_map, row_to_core_cells, Row};
30use mongreldb_core::epoch::Epoch;
31use mongreldb_core::memtable::{Row as CoreRow, Value as CoreValue};
32use mongreldb_core::query::Condition;
33use mongreldb_core::RowId;
34use mongreldb_core::UpsertAction;
35use mongreldb_core::{NativeAgg, NativeAggResult};
36use mongreldb_kit_core::keys::{
37 decode_pk, encode_pk, encode_row_guard_key, encode_unique_key, KeyComponent, KIT_KEY_VERSION,
38};
39use mongreldb_kit_core::planner::{plan_delete, DeletePlan};
40use mongreldb_kit_core::query::{
41 AggFunc, AggregateQuery, Cte, Expr, JoinQuery, OnConflict, Query, Select,
42};
43use mongreldb_kit_core::schema::{
44 Column, ColumnType, DefaultKind, ForeignKey, Table as KitTable, UniqueConstraint,
45};
46use serde_json::{Map, Value};
47use std::cell::RefCell;
48use std::collections::{HashMap, HashSet};
49
50pub struct Transaction<'a> {
52 db: &'a crate::db::Database,
53 core: mongreldb_core::txn::Transaction<'a>,
54 staged: Vec<StagedOp>,
55 staged_unique: Vec<StagedUnique>,
57 touched_guards: HashSet<String>,
59 next_temp_id: u64,
60}
61
62#[derive(Debug, Clone)]
63enum StagedOp {
64 Insert {
65 table: String,
66 values: Map<String, Value>,
67 },
68 Update {
69 table: String,
70 old_pk: String,
71 row_id: u64,
72 values: Map<String, Value>,
73 },
74 Delete {
77 table: String,
78 pk: String,
79 },
80 Truncate {
81 table: String,
82 },
83}
84
85#[derive(Debug, Clone)]
86struct StagedUnique {
87 encoded_key: String,
88 owner_table: String,
89 owner_pk: String,
90}
91
92struct BatchGuardCache {
99 unique_guards: Vec<CoreRow>,
101 fk_parents: HashMap<String, bool>,
103}
104
105impl<'a> Transaction<'a> {
106 pub(crate) fn new(
107 db: &'a crate::db::Database,
108 core: mongreldb_core::txn::Transaction<'a>,
109 ) -> Self {
110 Self {
111 db,
112 core,
113 staged: Vec::new(),
114 staged_unique: Vec::new(),
115 touched_guards: HashSet::new(),
116 next_temp_id: 1,
117 }
118 }
119
120 pub fn insert(&mut self, table: &str, row: Map<String, Value>) -> Result<Row> {
122 let t = self.require_table(table)?.clone();
123 self.do_insert(table, &t, row, None, None)
124 }
125
126 pub fn insert_returning(
127 &mut self,
128 table: &str,
129 row: Map<String, Value>,
130 returning: Vec<String>,
131 ) -> Result<Value> {
132 let inserted = self.insert(table, row)?;
133 project_returning(&inserted, &returning)
134 }
135
136 pub fn insert_many(&mut self, table: &str, rows: Vec<Map<String, Value>>) -> Result<Vec<Row>> {
145 let t = self.require_table(table)?.clone();
146 let mut pk_seen: Option<HashSet<String>> = if t.primary_key.len() == 1 {
149 let mut set = HashSet::new();
150 for r in self.snapshot_rows(table)? {
151 set.insert(encoded_pk_for(&t, &r.values));
152 }
153 Some(set)
154 } else {
155 None
156 };
157 let mut batch = if t.unique_constraints.is_empty() && t.foreign_keys.is_empty() {
162 None
163 } else {
164 let unique_guards = if t.unique_constraints.is_empty() {
165 Vec::new()
166 } else {
167 self.internal_rows(UNIQUE_KEYS)?
168 };
169 Some(BatchGuardCache {
170 unique_guards,
171 fk_parents: HashMap::new(),
172 })
173 };
174 let mut out = Vec::with_capacity(rows.len());
175 for row in rows {
176 out.push(self.do_insert(table, &t, row, pk_seen.as_mut(), batch.as_mut())?);
177 }
178 Ok(out)
179 }
180
181 fn do_insert(
186 &mut self,
187 table: &str,
188 t: &KitTable,
189 mut row: Map<String, Value>,
190 pk_seen: Option<&mut HashSet<String>>,
191 batch: Option<&mut BatchGuardCache>,
192 ) -> Result<Row> {
193 let pk_explicit = pk_is_explicit(t, &row);
197
198 self.apply_defaults(&mut row, t)?;
199 for col in &t.columns {
202 row.entry(col.name.clone()).or_insert(Value::Null);
203 }
204 mongreldb_kit_core::validation::validate_row_kit_only(t, &row)?;
205
206 let (ug_slice, fk_cache): (Option<&[CoreRow]>, Option<&mut HashMap<String, bool>>) =
210 match batch {
211 Some(b) => (Some(&b.unique_guards[..]), Some(&mut b.fk_parents)),
212 None => (None, None),
213 };
214
215 self.check_unique_constraints(t, &row, None, ug_slice)?;
217 self.check_pk(t, &row, pk_explicit, pk_seen)?;
218 self.check_foreign_keys(t, &row, fk_cache)?;
219
220 self.reserve_unique_guards(t, &row, None)?;
222 self.reserve_pk_guard(t, &row, pk_explicit)?;
223 self.touch_foreign_key_guards(t, &row)?;
224
225 let cells = row_to_core_cells(&row, t)?;
226 self.core.put(table, cells).map_err(KitError::from)?;
227 let temp_id = self.alloc_temp_id();
228 self.staged.push(StagedOp::Insert {
229 table: table.to_string(),
230 values: row.clone(),
231 });
232 Ok(Row {
233 row_id: temp_id,
234 values: row,
235 })
236 }
237
238 pub fn update(&mut self, table: &str, pk: &Value, patch: Map<String, Value>) -> Result<Row> {
240 let t = self.require_table(table)?.clone();
241 let pk_map = pk_to_map(pk, &t)?;
242
243 let has_inbound_fk = self
250 .db
251 .schema()
252 .tables
253 .iter()
254 .filter(|o| o.name != table)
255 .any(|o| o.foreign_keys.iter().any(|fk| fk.references_table == table));
256 if t.unique_constraints.is_empty()
257 && t.check_constraints.is_empty()
258 && !has_inbound_fk
259 && t.primary_key.len() == 1
260 {
261 return self.update_fast(table, &t, &pk_map, patch);
262 }
263
264 let old_row = self
266 .get_by_pk_internal(table, &pk_map)?
267 .ok_or_else(|| KitError::Integrity(format!("row not found in {table}")))?;
268
269 let patch_keys: HashSet<String> = patch.keys().cloned().collect();
270 let mut values = old_row.values.clone();
271 for (k, v) in patch {
272 if t.column(&k).is_some() {
273 values.insert(k, v);
274 }
275 }
276 self.apply_update_defaults(&mut values, &patch_keys, &t);
277 mongreldb_kit_core::validation::validate_row_kit_only(&t, &values)?;
278 self.check_unique_constraints(&t, &values, Some(&old_row.values), None)?;
279 self.check_foreign_keys(&t, &values, None)?;
280
281 self.reserve_unique_guards(&t, &values, Some(&old_row.values))?;
283 self.touch_foreign_key_guards(&t, &values)?;
284
285 let cells = row_to_core_cells(&values, &t)?;
286 self.core
287 .delete(table, RowId(old_row.row_id))
288 .map_err(KitError::from)?;
289 self.core.put(table, cells).map_err(KitError::from)?;
290 let temp_id = self.alloc_temp_id();
291 self.staged.push(StagedOp::Update {
292 table: table.to_string(),
293 old_pk: encoded_pk_for(&t, &old_row.values),
294 row_id: old_row.row_id,
295 values: values.clone(),
296 });
297 Ok(Row {
298 row_id: temp_id,
299 values,
300 })
301 }
302
303 fn update_fast(
307 &mut self,
308 table: &str,
309 t: &KitTable,
310 pk_map: &Map<String, Value>,
311 patch: Map<String, Value>,
312 ) -> Result<Row> {
313 let pk_name = &t.primary_key[0];
314 let mut update_cells: Vec<(u16, CoreValue)> = Vec::new();
315 let patch_keys: HashSet<String> = patch.keys().cloned().collect();
316
317 let pk_col = t.column(pk_name).ok_or_else(|| {
319 KitError::Validation(format!("primary key column {pk_name} not found"))
320 })?;
321 let pk_json = pk_map.get(pk_name).cloned().unwrap_or(Value::Null);
322 let pk_core = crate::schema::json_to_core(&pk_json, pk_col.storage_type)?;
323
324 for (name, val) in &patch {
326 if let Some(col) = t.column(name) {
327 let cv = crate::schema::json_to_core(val, col.storage_type)?;
328 update_cells.push((col.id as u16, cv));
329 }
330 }
331
332 let mut now_stamp: Option<String> = None;
334 for col in &t.columns {
335 if patch_keys.contains(&col.name) {
336 continue;
337 }
338 if col.generated && matches!(col.default, Some(DefaultKind::Now)) {
339 let stamp = now_stamp.get_or_insert_with(iso_now);
340 let val = if col.storage_type == ColumnType::Date {
341 Value::String(stamp[..10].to_string())
342 } else {
343 Value::String(stamp.clone())
344 };
345 let cv = crate::schema::json_to_core(&val, col.storage_type)?;
346 update_cells.push((col.id as u16, cv));
347 }
348 }
349
350 let core_db = self.db.core_db();
356 let handle = core_db.table(table).map_err(KitError::from)?;
357 let snap = self.core.read_snapshot();
358 let row_id = {
359 let mut guard = handle.lock();
360 guard.ensure_indexes_complete().map_err(KitError::from)?;
361 guard
362 .lookup_pk(&pk_core.encode_key())
363 .ok_or_else(|| KitError::Integrity(format!("row not found in {table}")))?
364 };
365 let old_row = handle
366 .lock()
367 .get(row_id, snap)
368 .ok_or_else(|| KitError::Integrity(format!("row not found in {table}")))?;
369
370 let mut merged: std::collections::HashMap<u16, CoreValue> = old_row.columns;
372 for (id, val) in &update_cells {
373 merged.insert(*id, val.clone());
374 }
375 let merged_cells: Vec<(u16, CoreValue)> = t
376 .columns
377 .iter()
378 .map(|col| {
379 (
380 col.id as u16,
381 merged.remove(&(col.id as u16)).unwrap_or(CoreValue::Null),
382 )
383 })
384 .collect();
385
386 self.core
388 .put(table, merged_cells.clone())
389 .map_err(KitError::from)?;
390
391 let core_row = CoreRow {
393 row_id,
394 committed_epoch: Epoch(0),
395 commit_ts: None,
396 columns: merged_cells.into_iter().collect(),
397 deleted: false,
398 };
399 let kit_row = crate::schema::core_row_to_json(&core_row, t)?;
400 let temp_id = self.alloc_temp_id();
401 self.staged.push(StagedOp::Update {
402 table: table.to_string(),
403 old_pk: encoded_pk_for(t, pk_map),
404 row_id: 0,
405 values: kit_row.values.clone(),
406 });
407 Ok(Row {
408 row_id: temp_id,
409 values: kit_row.values,
410 })
411 }
412
413 fn delete_row(&mut self, table: &str, row: &Row) -> Result<u64> {
417 let t = self.require_table(table)?.clone();
418 let (plan, row_cache) = self.plan_delete(table, row)?;
419 if !plan.restricted.is_empty() {
420 let msg = format!(
421 "delete restricted by {}",
422 plan.restricted
423 .iter()
424 .map(|r| format!("{}.{}", r.table, r.constraint))
425 .collect::<Vec<_>>()
426 .join(", ")
427 );
428 return Err(KitError::Restrict(msg));
429 }
430
431 for set_null in &plan.set_null {
435 let key = format!("{}:{}", set_null.table, set_null.pk);
436 if let Some(child_row) = row_cache.get(&key).cloned() {
437 self.apply_set_null(set_null, &child_row)?;
438 }
439 }
440 for del in &plan.delete {
441 if del.table == table {
442 continue; }
444 let child_table = self.require_table(&del.table)?.clone();
445 let key = format!("{}:{}", del.table, del.pk);
446 if let Some(child_row) = row_cache.get(&key) {
447 let row_id = child_row.row_id;
448 let values = child_row.values.clone();
449 self.delete_guards_for(&child_table, &values)?;
450 self.core
451 .delete(&del.table, RowId(row_id))
452 .map_err(KitError::from)?;
453 self.staged.push(StagedOp::Delete {
454 table: del.table.clone(),
455 pk: del.pk.clone(),
456 });
457 }
458 }
459
460 self.delete_guards_for(&t, &row.values)?;
463 self.touch_row_guard(table, &pk_components(&t, &row.values))?;
464 self.staged.push(StagedOp::Delete {
465 table: table.to_string(),
466 pk: encoded_pk_for(&t, &row.values),
467 });
468 Ok(row.row_id)
469 }
470
471 pub fn delete(&mut self, table: &str, pk: &Value) -> Result<()> {
473 let t = self.require_table(table)?.clone();
474 let pk_map = pk_to_map(pk, &t)?;
475
476 let has_inbound_fk = self
482 .db
483 .schema()
484 .tables
485 .iter()
486 .filter(|o| o.name != table)
487 .any(|o| o.foreign_keys.iter().any(|fk| fk.references_table == table));
488 if t.unique_constraints.is_empty() && !has_inbound_fk && t.primary_key.len() == 1 {
489 let pk_name = &t.primary_key[0];
490 if let Some(pk_col) = t.column(pk_name) {
491 let pk_json = pk_map.get(pk_name).cloned().unwrap_or(Value::Null);
492 let pk_core = crate::schema::json_to_core(&pk_json, pk_col.storage_type)?;
493 if let Some(rid) = self.db.lookup_row_id(table, &pk_core.encode_key())? {
494 self.core.delete(table, rid).map_err(KitError::from)?;
495 self.staged.push(StagedOp::Delete {
496 table: table.to_string(),
497 pk: encoded_pk_for(&t, &pk_map),
498 });
499 return Ok(());
500 }
501 return Err(KitError::Integrity(format!("row not found in {table}")));
502 }
503 }
504
505 let row = self
507 .get_by_pk_internal(table, &pk_map)?
508 .ok_or_else(|| KitError::Integrity(format!("row not found in {table}")))?;
509 let row_id = self.delete_row(table, &row)?;
510 self.core
511 .delete(table, RowId(row_id))
512 .map_err(KitError::from)?;
513 Ok(())
514 }
515
516 pub fn truncate(&mut self, table: &str) -> Result<()> {
517 let t = self.require_table(table)?.clone();
518 let has_data_writes = self.staged.iter().any(|op| match op {
521 StagedOp::Insert { table: t, .. }
522 | StagedOp::Update { table: t, .. }
523 | StagedOp::Delete { table: t, .. } => t == table,
524 StagedOp::Truncate { .. } => false,
525 });
526 if has_data_writes {
527 return Err(KitError::Validation(format!(
528 "truncate cannot be combined with prior writes on {table}"
529 )));
530 }
531 if self.db.schema.tables.iter().any(|other| {
532 other.name != t.name
533 && other
534 .foreign_keys
535 .iter()
536 .any(|fk| fk.references_table == t.name)
537 }) {
538 return Err(KitError::Restrict(format!(
539 "table {} is referenced by a foreign key",
540 t.name
541 )));
542 }
543 self.delete_all_guards_for_table(&t)?;
544 self.core.truncate(table).map_err(KitError::from)?;
545 self.staged.push(StagedOp::Truncate { table: t.name });
546 Ok(())
547 }
548
549 pub fn upsert(
550 &mut self,
551 table: &str,
552 row: Map<String, Value>,
553 on_conflict: OnConflict,
554 returning: Vec<String>,
555 ) -> Result<Value> {
556 let t = self.require_table(table)?.clone();
557 let mut values = row;
558 self.apply_defaults(&mut values, &t)?;
559 for col in &t.columns {
560 values.entry(col.name.clone()).or_insert(Value::Null);
561 }
562 mongreldb_kit_core::validation::validate_row_kit_only(&t, &values)?;
563 let pk_map = pk_values_map(&t, &values);
564 let existing = self.get_by_pk_internal(table, &pk_map)?;
565 match (existing, on_conflict) {
566 (Some(old), OnConflict::DoNothing) => project_returning(&old, &returning),
567 (Some(old), OnConflict::DoUpdate(patch)) => {
568 let mut merged = values.clone();
569 let mut patch_keys = HashSet::new();
570 for (k, v) in patch {
571 if t.column(&k).is_some() {
572 merged.insert(k.clone(), v);
573 patch_keys.insert(k);
574 }
575 }
576 self.apply_update_defaults(&mut merged, &patch_keys, &t);
577 mongreldb_kit_core::validation::validate_row_kit_only(&t, &merged)?;
578 self.check_unique_constraints(&t, &merged, Some(&old.values), None)?;
579 self.check_foreign_keys(&t, &merged, None)?;
580 self.reserve_unique_guards(&t, &merged, Some(&old.values))?;
581 self.touch_foreign_key_guards(&t, &merged)?;
582
583 let insert_cells = row_to_core_cells(&merged, &t)?;
584 let mut patch_values = Map::new();
585 for k in &patch_keys {
586 patch_values.insert(k.clone(), merged.get(k).cloned().unwrap_or(Value::Null));
587 }
588 let update_cells = patch_to_core_cells(&patch_values, &t)?;
589
590 self.core
591 .upsert(table, insert_cells, UpsertAction::DoUpdate(update_cells))
592 .map_err(KitError::from)?;
593 self.staged.push(StagedOp::Update {
594 table: table.to_string(),
595 old_pk: encoded_pk_for(&t, &old.values),
596 row_id: old.row_id,
597 values: merged.clone(),
598 });
599 project_returning(
600 &Row {
601 row_id: old.row_id,
602 values: merged,
603 },
604 &returning,
605 )
606 }
607 (None, on_conflict) => {
608 self.check_unique_constraints(&t, &values, None, None)?;
609 self.check_foreign_keys(&t, &values, None)?;
610 self.reserve_unique_guards(&t, &values, None)?;
611 let pk_explicit = pk_is_explicit(&t, &values);
612 self.reserve_pk_guard(&t, &values, pk_explicit)?;
613 self.touch_foreign_key_guards(&t, &values)?;
614 let cells = row_to_core_cells(&values, &t)?;
615 let action = match on_conflict {
616 OnConflict::DoNothing => UpsertAction::DoNothing,
617 OnConflict::DoUpdate(patch) => {
618 UpsertAction::DoUpdate(patch_to_core_cells(&patch, &t)?)
619 }
620 };
621 self.core
622 .upsert(table, cells, action)
623 .map_err(KitError::from)?;
624 self.staged.push(StagedOp::Insert {
625 table: table.to_string(),
626 values: values.clone(),
627 });
628 project_returning(&Row { row_id: 0, values }, &returning)
629 }
630 }
631 }
632
633 pub fn update_where(
634 &mut self,
635 table: &str,
636 filter: Option<Expr>,
637 patch: Map<String, Value>,
638 returning: Vec<String>,
639 ) -> Result<Vec<Value>> {
640 let t = self.require_table(table)?.clone();
641 let rows = self.select(&Query::Select(select_all(table, filter)))?;
642 let mut updates = Vec::with_capacity(rows.len());
643 let mut out = Vec::with_capacity(rows.len());
644 let patch_keys: HashSet<String> = patch.keys().cloned().collect();
645 for row in rows {
646 let mut values = row.values.clone();
647 for (k, v) in &patch {
648 if t.column(k).is_some() {
649 values.insert(k.clone(), v.clone());
650 }
651 }
652 self.apply_update_defaults(&mut values, &patch_keys, &t);
653 mongreldb_kit_core::validation::validate_row_kit_only(&t, &values)?;
654 self.check_unique_constraints(&t, &values, Some(&row.values), None)?;
655 self.check_foreign_keys(&t, &values, None)?;
656 self.reserve_unique_guards(&t, &values, Some(&row.values))?;
657 self.touch_foreign_key_guards(&t, &values)?;
658
659 let cells = row_to_core_cells(&values, &t)?;
660 updates.push((RowId(row.row_id), cells));
661 self.staged.push(StagedOp::Update {
662 table: table.to_string(),
663 old_pk: encoded_pk_for(&t, &row.values),
664 row_id: row.row_id,
665 values: values.clone(),
666 });
667 out.push(project_returning(
668 &Row {
669 row_id: row.row_id,
670 values,
671 },
672 &returning,
673 )?);
674 }
675 if !updates.is_empty() {
676 self.core
677 .update_many(table, updates)
678 .map_err(KitError::from)?;
679 }
680 Ok(out)
681 }
682
683 pub fn delete_where(
684 &mut self,
685 table: &str,
686 filter: Option<Expr>,
687 returning: Vec<String>,
688 ) -> Result<Vec<Value>> {
689 self.require_table(table)?;
690 let rows = self.select(&Query::Select(select_all(table, filter)))?;
691 let mut out = Vec::with_capacity(rows.len());
692 let mut ids = Vec::with_capacity(rows.len());
693 for row in rows {
694 out.push(project_returning(&row, &returning)?);
695 ids.push(self.delete_row(table, &row)?);
696 }
697 if !ids.is_empty() {
698 self.core
699 .delete_many(table, ids.into_iter().map(RowId).collect())
700 .map_err(KitError::from)?;
701 }
702 Ok(out)
703 }
704
705 pub fn get_by_pk(&self, table: &str, pk: &Value) -> Result<Option<Row>> {
707 let t = self.require_table(table)?;
708 let pk_map = pk_to_map(pk, t)?;
709 self.get_by_pk_internal(table, &pk_map)
710 }
711
712 pub fn select(&self, query: &Query) -> Result<Vec<Row>> {
716 let select = match query {
717 Query::Select(s) => s,
718 _ => return Err(KitError::Validation("only SELECT supported".into())),
719 };
720 let ctx = self.exec_ctx();
721 run_select(&ctx, select)
722 }
723
724 pub fn select_distinct(&self, query: &Query) -> Result<Vec<Row>> {
728 let select = match query {
729 Query::Select(s) => s,
730 _ => return Err(KitError::Validation("only SELECT supported".into())),
731 };
732 let ctx = self.exec_ctx();
733 let rows = run_select(&ctx, select)?;
734 Ok(project_distinct(select, rows))
735 }
736
737 pub fn select_with(&self, ctes: &[Cte], body: &Select) -> Result<Vec<Row>> {
740 let mut ctx = self.exec_ctx();
741 for cte in ctes {
742 let rows = run_select(&ctx, &cte.query)?;
743 ctx.add_cte(cte.name.clone(), rows);
744 }
745 run_select(&ctx, body)
746 }
747
748 pub fn aggregate(&self, query: &AggregateQuery) -> Result<Vec<Row>> {
752 if let Some(rows) = self.try_native_aggregate(query)? {
753 return Ok(rows);
754 }
755 let ctx = self.exec_ctx();
756 run_aggregate(&ctx, query)
757 }
758
759 fn try_native_aggregate(&self, query: &AggregateQuery) -> Result<Option<Vec<Row>>> {
769 if !query.group_by.is_empty() || query.having.is_some() || query.aggregates.len() != 1 {
770 return Ok(None);
771 }
772 let agg = &query.aggregates[0];
773 if self.has_staged_for(&query.table) {
774 return Ok(None); }
776
777 if agg.distinct {
782 if !matches!(agg.func, AggFunc::Count) || query.filter.is_some() {
783 return Ok(None);
784 }
785 let Some(col_name) = &agg.column else {
786 return Ok(None);
787 };
788 let t = self.require_table(&query.table)?;
789 let Some(col) = t.columns.iter().find(|c| &c.name == col_name) else {
790 return Ok(None);
791 };
792 let Some(n) = self.db.count_distinct_core_at(
793 &query.table,
794 col.id as u16,
795 self.core.read_snapshot(),
796 )?
797 else {
798 return Ok(None);
799 };
800 let mut values = Map::new();
801 values.insert(agg.alias.clone(), Value::Number((n as i64).into()));
802 return Ok(Some(vec![Row { row_id: 0, values }]));
803 }
804
805 let conditions: Vec<Condition> = match &query.filter {
806 None => Vec::new(),
807 Some(filter) => {
808 let t = self.require_table(&query.table)?;
809 match crate::pushdown::translate_predicate(t, filter) {
810 Some(plan) if plan.can_push() && plan.fully_translated => plan.conditions,
812 _ => return Ok(None),
813 }
814 }
815 };
816 let snapshot = self.core.read_snapshot();
817
818 let value: Value = match (agg.func, &agg.column) {
819 (AggFunc::Count, None) => {
821 let Some(n) = self
822 .db
823 .count_core_rows_at(&query.table, &conditions, snapshot)?
824 else {
825 return Ok(None);
826 };
827 Value::Number((n as i64).into())
828 }
829 (func, Some(col_name)) => {
832 let t = self.require_table(&query.table)?;
833 let Some(col) = t.columns.iter().find(|c| &c.name == col_name) else {
834 return Ok(None);
835 };
836 let native = match func {
837 AggFunc::Count => NativeAgg::Count,
838 AggFunc::Sum => NativeAgg::Sum,
839 AggFunc::Min => NativeAgg::Min,
840 AggFunc::Max => NativeAgg::Max,
841 AggFunc::Avg => NativeAgg::Avg,
842 };
843 let Some(result) = self.db.aggregate_core_at(
844 &query.table,
845 Some(col.id as u16),
846 &conditions,
847 native,
848 snapshot,
849 )?
850 else {
851 return Ok(None);
852 };
853 match result {
856 NativeAggResult::Count(n) => Value::Number((n as i64).into()),
857 NativeAggResult::Int(x) => Value::Number(x.into()),
858 NativeAggResult::Float(f) => serde_json::Number::from_f64(f)
859 .map(Value::Number)
860 .unwrap_or(Value::Null),
861 NativeAggResult::Null => Value::Null,
862 }
863 }
864 _ => return Ok(None),
866 };
867
868 let mut values = Map::new();
869 values.insert(agg.alias.clone(), value);
870 Ok(Some(vec![Row { row_id: 0, values }]))
871 }
872
873 pub fn join(&self, query: &JoinQuery) -> Result<Vec<JoinRow>> {
876 let ctx = self.exec_ctx();
877 run_join(&ctx, query)
878 }
879
880 pub fn ann_search(
888 &self,
889 table: &str,
890 column: &str,
891 query: Vec<f32>,
892 k: usize,
893 ) -> Result<Vec<Row>> {
894 let t = self.require_table(table)?;
895 let col = t
896 .column(column)
897 .ok_or_else(|| KitError::Validation(format!("unknown column \"{column}\"")))?;
898 let cond = Condition::Ann {
899 column_id: col.id as u16,
900 query,
901 k,
902 };
903 self.snapshot_rows_pushed(table, &[cond])
904 }
905
906 pub fn search(
915 &self,
916 table: &str,
917 spec: crate::search::SearchSpec,
918 ) -> Result<Vec<crate::search::SearchHit>> {
919 if self.has_staged_for(table) {
920 return Err(KitError::Validation(
921 "search does not include uncommitted staged rows; commit first".into(),
922 ));
923 }
924 let t = self.require_table(table)?;
925 let request = crate::search::build_core_request(t, &spec)?;
926 let hits = self
927 .db
928 .core_db()
929 .search_for_current_principal(table, &request)
930 .map_err(KitError::from)?;
931 hits.into_iter()
932 .map(|hit| crate::search::core_hit_to_kit(hit, t))
933 .collect()
934 }
935
936 pub fn retrieve_text(
941 &self,
942 table: &str,
943 embedding_column: &str,
944 text: &str,
945 k: usize,
946 ) -> Result<crate::search::TextRetrieveResult> {
947 if self.has_staged_for(table) {
948 return Err(KitError::Validation(
949 "retrieve_text does not include uncommitted staged rows; commit first".into(),
950 ));
951 }
952 if k == 0 {
953 return Err(KitError::Validation(
954 "retrieve_text k must be greater than zero".into(),
955 ));
956 }
957 let t = self.require_table(table)?;
958 let column_id = crate::search::resolve_column_id(t, embedding_column)?;
959 let retrieved = self
960 .db
961 .core_db()
962 .retrieve_text(
963 table,
964 column_id,
965 text,
966 mongreldb_core::TextSearchOptions::new(k),
967 )
968 .map_err(KitError::from)?;
969 let hits = retrieved
970 .hits
971 .into_iter()
972 .map(|hit| {
973 let (score_kind, score_value) = match hit.score {
974 mongreldb_core::query::RetrieverScore::AnnHammingDistance(d) => {
975 ("ann_hamming_distance".into(), f64::from(d))
976 }
977 mongreldb_core::query::RetrieverScore::AnnCosineDistance(d) => {
978 ("ann_cosine_distance".into(), f64::from(d))
979 }
980 mongreldb_core::query::RetrieverScore::SparseDotProduct(v) => {
981 ("sparse_dot_product".into(), v)
982 }
983 mongreldb_core::query::RetrieverScore::MinHashEstimatedJaccard(v) => {
984 ("minhash_estimated_jaccard".into(), f64::from(v))
985 }
986 };
987 crate::search::TextRetrieveHit {
988 row_id: hit.row_id.0,
989 rank: hit.rank,
990 score_kind,
991 score_value,
992 }
993 })
994 .collect();
995 Ok(crate::search::TextRetrieveResult {
996 hits,
997 provenance: crate::search::TextRetrieveProvenance {
998 embedding_column: embedding_column.to_owned(),
999 provider_registry_generation: retrieved.provenance.provider_registry_generation,
1000 query_source_fingerprint: retrieved.provenance.query_source_fingerprint,
1001 semantic_identity: retrieved.provenance.semantic_identity,
1002 },
1003 })
1004 }
1005
1006 pub fn sparse_match(
1011 &self,
1012 table: &str,
1013 column: &str,
1014 query: Vec<(u32, f32)>,
1015 k: usize,
1016 ) -> Result<Vec<Row>> {
1017 let t = self.require_table(table)?;
1018 let col = t
1019 .column(column)
1020 .ok_or_else(|| KitError::Validation(format!("unknown column \"{column}\"")))?;
1021 let cond = Condition::SparseMatch {
1022 column_id: col.id as u16,
1023 query,
1024 k,
1025 };
1026 self.snapshot_rows_pushed(table, &[cond])
1027 }
1028
1029 pub fn execute(&mut self, query: &Query) -> Result<Vec<Value>> {
1030 match query {
1031 Query::Select(_) => Err(KitError::Validation("use select() for SELECT".into())),
1032 Query::Insert(insert) => Ok(vec![self.insert_returning(
1033 &insert.table,
1034 insert.values.clone(),
1035 insert.returning.clone(),
1036 )?]),
1037 Query::Upsert(upsert) => Ok(vec![self.upsert(
1038 &upsert.table,
1039 upsert.values.clone(),
1040 upsert.on_conflict.clone(),
1041 upsert.returning.clone(),
1042 )?]),
1043 Query::Update(update) => {
1044 if update.pk.is_some() && update.filter.is_some() {
1045 return Err(KitError::Validation(
1046 "update cannot specify both pk and filter".into(),
1047 ));
1048 }
1049 if let Some(pk) = &update.pk {
1050 let row = self.update(&update.table, pk, update.set.clone())?;
1051 Ok(vec![project_returning(&row, &update.returning)?])
1052 } else if let Some(filter) = &update.filter {
1053 self.update_where(
1054 &update.table,
1055 Some(filter.clone()),
1056 update.set.clone(),
1057 update.returning.clone(),
1058 )
1059 } else {
1060 Err(KitError::Validation(
1061 "update requires either a pk or a filter".into(),
1062 ))
1063 }
1064 }
1065 Query::Delete(delete) => {
1066 if delete.pk.is_some() && delete.filter.is_some() {
1067 return Err(KitError::Validation(
1068 "delete cannot specify both pk and filter".into(),
1069 ));
1070 }
1071 if let Some(pk) = &delete.pk {
1072 let t = self.require_table(&delete.table)?;
1073 let pk_map = pk_to_map(pk, t)?;
1074 let projected = match self.get_by_pk_internal(&delete.table, &pk_map)? {
1075 Some(row) => project_returning(&row, &delete.returning)?,
1076 None => {
1077 self.delete(&delete.table, pk)?;
1079 unreachable!("delete returned Ok for a missing row")
1080 }
1081 };
1082 self.delete(&delete.table, pk)?;
1083 Ok(vec![projected])
1084 } else if let Some(filter) = &delete.filter {
1085 self.delete_where(
1086 &delete.table,
1087 Some(filter.clone()),
1088 delete.returning.clone(),
1089 )
1090 } else {
1091 Err(KitError::Validation(
1092 "delete requires either a pk or a filter".into(),
1093 ))
1094 }
1095 }
1096 Query::Aggregate(_) | Query::Join(_) => Err(KitError::Validation(
1097 "aggregate/join are not mutating statements".into(),
1098 )),
1099 }
1100 }
1101
1102 fn exec_ctx(&self) -> ExecCtx<'_> {
1106 ExecCtx::new(
1107 Some(&self.db.schema),
1108 |name: &str, conds: Option<&[Condition]>| match conds {
1109 Some(c) if !c.is_empty() => self.snapshot_rows_pushed(name, c),
1110 _ => self.snapshot_rows(name),
1111 },
1112 )
1113 }
1114
1115 pub fn commit(self) -> Result<()> {
1127 const FLUSH_AFTER_ROWS: usize = 1000;
1128 let mut counts: HashMap<&str, usize> = HashMap::new();
1129 for op in &self.staged {
1130 let table = match op {
1131 StagedOp::Insert { table, .. }
1132 | StagedOp::Update { table, .. }
1133 | StagedOp::Delete { table, .. }
1134 | StagedOp::Truncate { table } => table.as_str(),
1135 };
1136 *counts.entry(table).or_default() += 1;
1137 }
1138 let tables_to_flush: Vec<&str> = counts
1139 .into_iter()
1140 .filter(|&(_, n)| n >= FLUSH_AFTER_ROWS)
1141 .map(|(table, _)| table)
1142 .collect();
1143 let db = self.db;
1144 self.core.commit().map_err(KitError::from)?;
1145 for table in tables_to_flush {
1146 let _ = db.flush_table(table);
1147 }
1148 Ok(())
1149 }
1150
1151 pub fn rollback(self) {
1153 self.core.rollback();
1154 }
1155
1156 fn alloc_temp_id(&mut self) -> u64 {
1159 let id = self.next_temp_id;
1160 self.next_temp_id += 1;
1161 id
1162 }
1163
1164 fn require_table(&self, name: &str) -> Result<&KitTable> {
1165 self.db
1166 .table(name)
1167 .ok_or_else(|| KitError::Integrity(format!("table {name} not found")))
1168 }
1169
1170 pub fn all_rows(&self, table: &str) -> Result<Vec<Row>> {
1172 self.snapshot_rows(table)
1173 }
1174
1175 fn snapshot_rows(&self, table: &str) -> Result<Vec<Row>> {
1176 let t = self.require_table(table)?;
1177 let core_rows = self
1178 .db
1179 .visible_core_rows_at(table, self.core.read_snapshot())?;
1180 let mut rows = core_rows
1181 .into_iter()
1182 .map(|r| core_row_to_json(&r, t))
1183 .collect::<Result<Vec<_>>>()?;
1184 self.replay_staged_rows(t, &mut rows);
1185 Ok(rows)
1186 }
1187
1188 fn snapshot_rows_pushed(&self, table: &str, conditions: &[Condition]) -> Result<Vec<Row>> {
1192 let t = self.require_table(table)?;
1193 if self.has_staged_for(table) {
1194 return Ok(self
1195 .snapshot_rows(table)?
1196 .into_iter()
1197 .filter(|r| row_matches_conditions(t, r, conditions))
1198 .collect());
1199 }
1200 let core_rows = self
1201 .db
1202 .query_core_rows_at(table, conditions, self.core.read_snapshot())?;
1203 core_rows
1204 .into_iter()
1205 .map(|r| core_row_to_json(&r, t))
1206 .collect()
1207 }
1208
1209 fn get_by_pk_internal(&self, table: &str, pk_map: &Map<String, Value>) -> Result<Option<Row>> {
1210 let t = self.require_table(table)?;
1211 if self.has_staged_for(table) {
1212 let rows = self.snapshot_rows(table)?;
1213 return Ok(rows.into_iter().find(|r| pk_matches(&r.values, pk_map, t)));
1214 }
1215 if let Some(conditions) = crate::pushdown::pk_conditions(t, pk_map) {
1218 let core_rows =
1219 self.db
1220 .query_core_rows_at(table, &conditions, self.core.read_snapshot())?;
1221 return Ok(core_rows
1222 .into_iter()
1223 .filter_map(|r| core_row_to_json(&r, t).ok())
1224 .find(|r| pk_matches(&r.values, pk_map, t)));
1225 }
1226 let rows = self.snapshot_rows(table)?;
1227 Ok(rows.into_iter().find(|r| pk_matches(&r.values, pk_map, t)))
1228 }
1229
1230 fn internal_rows(&self, table: &str) -> Result<Vec<CoreRow>> {
1231 self.db
1232 .visible_core_rows_at(table, self.core.read_snapshot())
1233 }
1234
1235 fn check_unique_constraints(
1240 &self,
1241 table: &KitTable,
1242 values: &Map<String, Value>,
1243 old_values: Option<&Map<String, Value>>,
1244 preloaded_guards: Option<&[CoreRow]>,
1245 ) -> Result<()> {
1246 if table.unique_constraints.is_empty() {
1247 return Ok(());
1248 }
1249 let owner_pk = encoded_pk_for(table, values);
1250 let owned;
1253 let committed: &[CoreRow] = match preloaded_guards {
1254 Some(g) => g,
1255 None => {
1256 owned = self.internal_rows(UNIQUE_KEYS)?;
1257 &owned
1258 }
1259 };
1260 for uq in &table.unique_constraints {
1261 let Some(key) = unique_key(table, uq, values) else {
1262 continue;
1263 };
1264 if let Some(old) = old_values {
1266 if unique_key(table, uq, old).as_deref() == Some(key.as_str()) {
1267 continue;
1268 }
1269 }
1270 self.assert_key_free(committed, table, uq, &key, &owner_pk)?;
1271 }
1272 Ok(())
1273 }
1274
1275 fn assert_key_free(
1276 &self,
1277 committed: &[CoreRow],
1278 table: &KitTable,
1279 uq: &UniqueConstraint,
1280 key: &str,
1281 owner_pk: &str,
1282 ) -> Result<()> {
1283 for guard in committed {
1284 if internal_bytes(guard, cols::UQ_ENCODED).as_deref() == Some(key) {
1285 let g_table = internal_bytes(guard, cols::UQ_OWNER_TABLE).unwrap_or_default();
1286 let g_pk = internal_bytes(guard, cols::UQ_OWNER_PK).unwrap_or_default();
1287 if g_table != table.name || g_pk != owner_pk {
1288 return Err(KitError::Duplicate(format!(
1289 "unique constraint {} on {}",
1290 uq.name, table.name
1291 )));
1292 }
1293 }
1294 }
1295 for staged in &self.staged_unique {
1296 if staged.encoded_key == key
1297 && (staged.owner_table != table.name || staged.owner_pk != owner_pk)
1298 {
1299 return Err(KitError::Duplicate(format!(
1300 "unique constraint {} on {}",
1301 uq.name, table.name
1302 )));
1303 }
1304 }
1305 Ok(())
1306 }
1307
1308 fn reserve_unique_guards(
1311 &mut self,
1312 table: &KitTable,
1313 values: &Map<String, Value>,
1314 old_values: Option<&Map<String, Value>>,
1315 ) -> Result<()> {
1316 let owner_pk = encoded_pk_for(table, values);
1317 for uq in &table.unique_constraints {
1318 let new_key = unique_key(table, uq, values);
1319 let old_key = old_values.and_then(|old| unique_key(table, uq, old));
1320 if new_key == old_key {
1321 continue;
1322 }
1323 if let Some(key) = &new_key {
1324 self.put_unique_guard(&uq.name, key, &table.name, &owner_pk)?;
1325 }
1326 if let Some(key) = &old_key {
1327 self.delete_unique_guard(key)?;
1328 }
1329 }
1330 Ok(())
1331 }
1332
1333 fn put_unique_guard(
1334 &mut self,
1335 constraint: &str,
1336 encoded_key: &str,
1337 owner_table: &str,
1338 owner_pk: &str,
1339 ) -> Result<()> {
1340 let now = iso_now();
1341 self.core
1342 .put(
1343 UNIQUE_KEYS,
1344 vec![
1345 (cols::UQ_ENCODED, CoreValue::Bytes(encoded_key.into())),
1346 (cols::UQ_CONSTRAINT, CoreValue::Bytes(constraint.into())),
1347 (cols::UQ_OWNER_TABLE, CoreValue::Bytes(owner_table.into())),
1348 (cols::UQ_OWNER_PK, CoreValue::Bytes(owner_pk.into())),
1349 (cols::UQ_CREATED, CoreValue::Bytes(now.into_bytes())),
1350 ],
1351 )
1352 .map_err(KitError::from)?;
1353 self.staged_unique.push(StagedUnique {
1354 encoded_key: encoded_key.to_string(),
1355 owner_table: owner_table.to_string(),
1356 owner_pk: owner_pk.to_string(),
1357 });
1358 Ok(())
1359 }
1360
1361 fn delete_unique_guard(&mut self, encoded_key: &str) -> Result<()> {
1362 let committed = self.internal_rows(UNIQUE_KEYS)?;
1363 for guard in &committed {
1364 if internal_bytes(guard, cols::UQ_ENCODED).as_deref() == Some(encoded_key) {
1365 self.core
1366 .delete(UNIQUE_KEYS, guard.row_id)
1367 .map_err(KitError::from)?;
1368 }
1369 }
1370 self.staged_unique.retain(|s| s.encoded_key != encoded_key);
1371 Ok(())
1372 }
1373
1374 fn delete_unique_guards_for_owner(&mut self, table: &KitTable, owner_pk: &str) -> Result<()> {
1376 let constraint_names: HashSet<&str> = table
1377 .unique_constraints
1378 .iter()
1379 .map(|u| u.name.as_str())
1380 .collect();
1381 let committed = self.internal_rows(UNIQUE_KEYS)?;
1382 for guard in &committed {
1383 let g_table = internal_bytes(guard, cols::UQ_OWNER_TABLE).unwrap_or_default();
1384 let g_pk = internal_bytes(guard, cols::UQ_OWNER_PK).unwrap_or_default();
1385 let g_constraint = internal_bytes(guard, cols::UQ_CONSTRAINT).unwrap_or_default();
1386 if g_table == table.name
1387 && g_pk == owner_pk
1388 && (constraint_names.contains(g_constraint.as_str())
1389 || g_constraint == pk_guard_constraint(table))
1390 {
1391 self.core
1392 .delete(UNIQUE_KEYS, guard.row_id)
1393 .map_err(KitError::from)?;
1394 }
1395 }
1396 let owner_pk = owner_pk.to_string();
1397 let name = table.name.clone();
1398 self.staged_unique
1399 .retain(|s| !(s.owner_table == name && s.owner_pk == owner_pk));
1400 Ok(())
1401 }
1402
1403 fn check_pk(
1413 &self,
1414 table: &KitTable,
1415 values: &Map<String, Value>,
1416 pk_explicit: bool,
1417 pk_seen: Option<&mut HashSet<String>>,
1418 ) -> Result<()> {
1419 if table.primary_key.is_empty() || !pk_explicit {
1421 return Ok(());
1422 }
1423
1424 if table.primary_key.len() == 1 {
1425 let duplicate = match pk_seen {
1430 Some(seen) => {
1431 let key = encoded_pk_for(table, values);
1432 if seen.contains(&key) {
1433 true
1434 } else {
1435 seen.insert(key);
1436 false
1437 }
1438 }
1439 None => {
1440 self.parent_exists(&table.name, values)?
1441 || self.staged_row_exists(table, values)
1442 }
1443 };
1444 if duplicate {
1445 return Err(KitError::Duplicate(format!(
1446 "primary key {} on {}",
1447 encoded_pk_for(table, values),
1448 table.name
1449 )));
1450 }
1451 return Ok(());
1452 }
1453
1454 let key = pk_guard_key(table, values);
1457 let owner_pk = encoded_pk_for(table, values);
1458 let committed = self.internal_rows(UNIQUE_KEYS)?;
1459 for guard in &committed {
1460 if internal_bytes(guard, cols::UQ_ENCODED).as_deref() == Some(key.as_str()) {
1461 return Err(KitError::Duplicate(format!(
1462 "primary key {} on {}",
1463 owner_pk, table.name
1464 )));
1465 }
1466 }
1467 for staged in &self.staged_unique {
1468 if staged.encoded_key == key {
1469 return Err(KitError::Duplicate(format!(
1470 "primary key {} on {}",
1471 owner_pk, table.name
1472 )));
1473 }
1474 }
1475 Ok(())
1476 }
1477
1478 fn reserve_pk_guard(
1479 &mut self,
1480 table: &KitTable,
1481 values: &Map<String, Value>,
1482 pk_explicit: bool,
1483 ) -> Result<()> {
1484 if table.primary_key.len() < 2 || !pk_explicit {
1487 return Ok(());
1488 }
1489 let key = pk_guard_key(table, values);
1490 let owner_pk = encoded_pk_for(table, values);
1491 let constraint = pk_guard_constraint(table);
1492 self.put_unique_guard(&constraint, &key, &table.name, &owner_pk)
1493 }
1494
1495 fn check_foreign_keys(
1498 &self,
1499 table: &KitTable,
1500 values: &Map<String, Value>,
1501 mut fk_cache: Option<&mut HashMap<String, bool>>,
1502 ) -> Result<()> {
1503 for fk in &table.foreign_keys {
1504 if fk_values_null(fk, values) {
1505 continue;
1506 }
1507 let parent = self.require_table(&fk.references_table)?;
1508 let parent_pk = parent_pk_value(values, fk, parent)?;
1509 let parent_pk_map = pk_to_map(&parent_pk, parent)?;
1510 let cache_key = format!(
1513 "{}\x00{}",
1514 fk.references_table,
1515 encode_pk(&pk_components(parent, &parent_pk_map))
1516 );
1517 let exists = if let Some(cache) = fk_cache.as_mut() {
1518 if let Some(&hit) = cache.get(&cache_key) {
1519 hit
1520 } else {
1521 let hit = self.parent_exists(&fk.references_table, &parent_pk_map)?
1522 || self.staged_row_exists(parent, &parent_pk_map);
1523 cache.insert(cache_key, hit);
1524 hit
1525 }
1526 } else {
1527 self.parent_exists(&fk.references_table, &parent_pk_map)?
1528 || self.staged_row_exists(parent, &parent_pk_map)
1529 };
1530 if exists {
1531 continue;
1532 }
1533 return Err(KitError::ForeignKey(format!(
1534 "{} references {}({})",
1535 fk.name,
1536 fk.references_table,
1537 fk.references_columns.join(",")
1538 )));
1539 }
1540 Ok(())
1541 }
1542
1543 fn touch_foreign_key_guards(
1544 &mut self,
1545 table: &KitTable,
1546 values: &Map<String, Value>,
1547 ) -> Result<()> {
1548 for fk in table.foreign_keys.clone() {
1549 if fk_values_null(&fk, values) {
1550 continue;
1551 }
1552 let parent = self.require_table(&fk.references_table)?.clone();
1553 let components = parent_pk_components(values, &fk, &parent);
1554 self.touch_row_guard(&parent.name, &components)?;
1555 }
1556 Ok(())
1557 }
1558
1559 fn parent_exists(&self, table: &str, pk_map: &Map<String, Value>) -> Result<bool> {
1560 let t = self.require_table(table)?;
1561 if self.has_staged_for(table) {
1562 let rows = self.snapshot_rows(table)?;
1563 return Ok(rows.iter().any(|r| pk_matches(&r.values, pk_map, t)));
1564 }
1565 if let Some(conditions) = crate::pushdown::pk_conditions(t, pk_map) {
1568 let core_rows =
1569 self.db
1570 .query_core_rows_at(table, &conditions, self.core.read_snapshot())?;
1571 return Ok(!core_rows.is_empty());
1572 }
1573 let rows = self.snapshot_rows(table)?;
1574 Ok(rows.iter().any(|r| pk_matches(&r.values, pk_map, t)))
1575 }
1576
1577 fn staged_row_exists(&self, table: &KitTable, pk_map: &Map<String, Value>) -> bool {
1583 let target = encode_pk(&pk_components(table, pk_map));
1584 let mut exists = false;
1585 for staged in &self.staged {
1586 match staged {
1587 StagedOp::Insert { table: t, values }
1588 | StagedOp::Update {
1589 table: t, values, ..
1590 } => {
1591 if t == &table.name && pk_matches(values, pk_map, table) {
1592 exists = true;
1593 }
1594 }
1595 StagedOp::Delete { table: t, pk } => {
1596 if t == &table.name && *pk == target {
1597 exists = false;
1598 }
1599 }
1600 StagedOp::Truncate { table: t } => {
1601 if t == &table.name {
1602 exists = false;
1603 }
1604 }
1605 }
1606 }
1607 exists
1608 }
1609
1610 fn touch_row_guard(&mut self, table: &str, pk_components: &[KeyComponent]) -> Result<()> {
1613 let encoded_pk = encode_pk(pk_components);
1614 let guard_key = encode_row_guard_key(table, &encoded_pk);
1615 if !self.touched_guards.insert(guard_key.clone()) {
1616 return Ok(());
1617 }
1618 let mut version = 1i64;
1622 let committed = self.db.query_core_rows_at(
1623 ROW_GUARDS,
1624 &[Condition::Pk(guard_key.as_bytes().to_vec())],
1625 self.core.read_snapshot(),
1626 )?;
1627 for guard in &committed {
1628 if internal_bytes(guard, cols::RG_ENCODED).as_deref() == Some(guard_key.as_str()) {
1629 if let Some(CoreValue::Int64(v)) = guard.columns.get(&cols::RG_VERSION) {
1630 version = v + 1;
1631 }
1632 self.core
1633 .delete(ROW_GUARDS, guard.row_id)
1634 .map_err(KitError::from)?;
1635 }
1636 }
1637 let now = iso_now();
1638 self.core
1639 .put(
1640 ROW_GUARDS,
1641 vec![
1642 (cols::RG_ENCODED, CoreValue::Bytes(guard_key.into_bytes())),
1643 (cols::RG_TABLE, CoreValue::Bytes(table.into())),
1644 (cols::RG_PK, CoreValue::Bytes(encoded_pk.into_bytes())),
1645 (cols::RG_VERSION, CoreValue::Int64(version)),
1646 (cols::RG_UPDATED, CoreValue::Bytes(now.into_bytes())),
1647 ],
1648 )
1649 .map_err(KitError::from)?;
1650 Ok(())
1651 }
1652
1653 fn has_staged_for(&self, table: &str) -> bool {
1654 self.staged.iter().any(|op| match op {
1655 StagedOp::Insert { table: t, .. }
1656 | StagedOp::Update { table: t, .. }
1657 | StagedOp::Delete { table: t, .. }
1658 | StagedOp::Truncate { table: t } => t == table,
1659 })
1660 }
1661
1662 fn replay_staged_rows(&self, table: &KitTable, rows: &mut Vec<Row>) {
1663 for staged in &self.staged {
1664 match staged {
1665 StagedOp::Insert { table: t, values } if t == &table.name => {
1666 let pk = encoded_pk_for(table, values);
1667 rows.retain(|r| encoded_pk_for(table, &r.values) != pk);
1668 rows.push(Row {
1669 row_id: 0,
1670 values: values.clone(),
1671 });
1672 }
1673 StagedOp::Update {
1674 table: t,
1675 old_pk,
1676 row_id,
1677 values,
1678 } if t == &table.name => {
1679 let new_pk = encoded_pk_for(table, values);
1680 rows.retain(|r| {
1681 let pk = encoded_pk_for(table, &r.values);
1682 pk != *old_pk && pk != new_pk
1683 });
1684 rows.push(Row {
1685 row_id: *row_id,
1686 values: values.clone(),
1687 });
1688 }
1689 StagedOp::Delete { table: t, pk } if t == &table.name => {
1690 rows.retain(|r| encoded_pk_for(table, &r.values) != *pk);
1691 }
1692 StagedOp::Truncate { table: t } if t == &table.name => {
1693 rows.clear();
1694 }
1695 _ => {}
1696 }
1697 }
1698 }
1699
1700 fn delete_guards_for(&mut self, table: &KitTable, values: &Map<String, Value>) -> Result<()> {
1702 let owner_pk = encoded_pk_for(table, values);
1703 self.delete_unique_guards_for_owner(table, &owner_pk)
1704 }
1705
1706 fn delete_all_guards_for_table(&mut self, table: &KitTable) -> Result<()> {
1707 for guard in self.internal_rows(UNIQUE_KEYS)? {
1708 let owner_table = internal_bytes(&guard, cols::UQ_OWNER_TABLE).unwrap_or_default();
1709 if owner_table == table.name {
1710 self.core
1711 .delete(UNIQUE_KEYS, guard.row_id)
1712 .map_err(KitError::from)?;
1713 }
1714 }
1715 for guard in self.internal_rows(ROW_GUARDS)? {
1716 let owner_table = internal_bytes(&guard, cols::RG_TABLE).unwrap_or_default();
1717 if owner_table == table.name {
1718 self.core
1719 .delete(ROW_GUARDS, guard.row_id)
1720 .map_err(KitError::from)?;
1721 }
1722 }
1723 self.staged_unique.retain(|s| s.owner_table != table.name);
1724 self.touched_guards
1725 .retain(|key| !key.starts_with(&format!("{}:", table.name)));
1726 Ok(())
1727 }
1728
1729 fn plan_delete(&self, table: &str, row: &Row) -> Result<(DeletePlan, HashMap<String, Row>)> {
1732 let schema = &self.db.schema;
1733 let t = self.require_table(table)?;
1734 let pk_str = encoded_pk_for(t, &row.values);
1735 let row_cache: RefCell<HashMap<String, Row>> = RefCell::new(HashMap::new());
1740 let find_children =
1741 |child_table: &KitTable, fk: &ForeignKey, parent_pk: &str| -> Vec<(String, String)> {
1742 let parent_pk_value = match pk_string_to_value(parent_pk, t) {
1743 Ok(v) => v,
1744 Err(_) => return Vec::new(),
1745 };
1746 let parent_pk_map = match pk_to_map(&parent_pk_value, t) {
1747 Ok(m) => m,
1748 Err(_) => return Vec::new(),
1749 };
1750 let child_rows = match self.snapshot_rows(&child_table.name) {
1751 Ok(r) => r,
1752 Err(_) => return Vec::new(),
1753 };
1754 let mut out = Vec::new();
1755 for child_row in child_rows {
1756 if fk_matches(&child_row.values, fk, &parent_pk_map, t) {
1757 let child_pk = encoded_pk_for(child_table, &child_row.values);
1758 row_cache
1759 .borrow_mut()
1760 .insert(format!("{}:{}", child_table.name, child_pk), child_row);
1761 out.push((child_pk, parent_pk.to_string()));
1762 }
1763 }
1764 out
1765 };
1766 let plan = plan_delete(schema, table, &pk_str, find_children).map_err(KitError::from)?;
1767 Ok((plan, row_cache.into_inner()))
1768 }
1769
1770 fn apply_set_null(
1771 &mut self,
1772 set_null: &mongreldb_kit_core::planner::SetNullUpdate,
1773 child_row: &Row,
1774 ) -> Result<()> {
1775 let child_table = self.require_table(&set_null.table)?.clone();
1776 let mut values = child_row.values.clone();
1777 for col in &set_null.columns {
1778 let col_def = child_table
1779 .column(col)
1780 .ok_or_else(|| KitError::Integrity(format!("set-null column {col} not found")))?;
1781 if !col_def.nullable {
1782 return Err(KitError::Restrict(format!(
1783 "set-null on non-nullable column {col}"
1784 )));
1785 }
1786 values.insert(col.clone(), Value::Null);
1787 }
1788 mongreldb_kit_core::validation::validate_row_kit_only(&child_table, &values)?;
1790 self.delete_guards_for(&child_table, &child_row.values)?;
1794 let cells = row_to_core_cells(&values, &child_table)?;
1795 self.core
1796 .delete(&set_null.table, RowId(child_row.row_id))
1797 .map_err(KitError::from)?;
1798 self.core
1799 .put(&set_null.table, cells)
1800 .map_err(KitError::from)?;
1801 self.reserve_unique_guards(&child_table, &values, None)?;
1802 self.reserve_pk_guard(&child_table, &values, true)?;
1806 self.staged.push(StagedOp::Update {
1807 table: set_null.table.clone(),
1808 old_pk: encoded_pk_for(&child_table, &child_row.values),
1809 row_id: child_row.row_id,
1810 values: values.clone(),
1811 });
1812 Ok(())
1813 }
1814
1815 fn apply_defaults(&self, row: &mut Map<String, Value>, table: &KitTable) -> Result<()> {
1818 for col in &table.columns {
1819 if row.contains_key(&col.name) && row.get(&col.name) != Some(&Value::Null) {
1820 continue;
1821 }
1822 let Some(default) = &col.default else {
1823 continue;
1824 };
1825 let value = match default {
1826 DefaultKind::Static(v) => v.clone(),
1827 DefaultKind::Now => {
1828 let now = iso_now();
1829 if col.storage_type == ColumnType::Date {
1830 Value::String(now[..10].to_string())
1831 } else {
1832 Value::String(now)
1833 }
1834 }
1835 DefaultKind::Uuid => Value::String(uuid::Uuid::new_v4().to_string()),
1836 DefaultKind::Sequence(name) => {
1837 let start = self.db.allocate_sequence(name, 1)?;
1838 Value::Number(start.into())
1839 }
1840 DefaultKind::CustomName(name) => {
1841 let provider = self.db.default_providers.get(name).ok_or_else(|| {
1842 KitError::Validation(format!("custom default \"{name}\" is not registered"))
1843 })?;
1844 provider()
1845 }
1846 };
1847 row.insert(col.name.clone(), value);
1848 }
1849 Ok(())
1850 }
1851
1852 fn apply_update_defaults(
1860 &self,
1861 merged: &mut Map<String, Value>,
1862 patch_keys: &HashSet<String>,
1863 table: &KitTable,
1864 ) {
1865 let mut now: Option<String> = None;
1866 for col in &table.columns {
1867 if patch_keys.contains(&col.name) {
1868 continue;
1869 }
1870 if col.generated && matches!(col.default, Some(DefaultKind::Now)) {
1871 let stamp = now.get_or_insert_with(iso_now);
1872 let value = if col.storage_type == ColumnType::Date {
1873 Value::String(stamp[..10].to_string())
1874 } else {
1875 Value::String(stamp.clone())
1876 };
1877 merged.insert(col.name.clone(), value);
1878 }
1879 }
1880 }
1881}
1882
1883fn project_returning(row: &Row, columns: &[String]) -> Result<Value> {
1886 let mut out = Map::new();
1887 for c in columns {
1888 out.insert(c.clone(), row.values.get(c).cloned().unwrap_or(Value::Null));
1889 }
1890 Ok(Value::Object(out))
1891}
1892
1893fn pk_values_map(table: &KitTable, values: &Map<String, Value>) -> Map<String, Value> {
1894 let mut out = Map::new();
1895 for name in &table.primary_key {
1896 out.insert(
1897 name.clone(),
1898 values.get(name).cloned().unwrap_or(Value::Null),
1899 );
1900 }
1901 out
1902}
1903
1904fn patch_to_core_cells(
1908 patch: &Map<String, Value>,
1909 table: &KitTable,
1910) -> Result<Vec<(u16, CoreValue)>> {
1911 let mut cells = Vec::new();
1912 for (name, value) in patch {
1913 let Some(col) = table.column(name) else {
1914 continue;
1915 };
1916 cells.push((col.id as u16, json_to_core(value, col.storage_type)?));
1917 }
1918 Ok(cells)
1919}
1920
1921fn select_all(table: &str, filter: Option<Expr>) -> Select {
1922 Select {
1923 table: table.to_string(),
1924 columns: vec![],
1925 filter,
1926 order_by: vec![],
1927 limit: None,
1928 offset: None,
1929 }
1930}
1931
1932fn pk_matches(values: &Map<String, Value>, pk_map: &Map<String, Value>, table: &KitTable) -> bool {
1933 for name in &table.primary_key {
1934 if values.get(name) != pk_map.get(name) {
1935 return false;
1936 }
1937 }
1938 true
1939}
1940
1941fn pk_is_explicit(table: &KitTable, row: &Map<String, Value>) -> bool {
1947 !table.primary_key.is_empty()
1948 && table
1949 .primary_key
1950 .iter()
1951 .all(|name| matches!(row.get(name), Some(v) if !v.is_null()))
1952}
1953
1954fn pk_guard_constraint(table: &KitTable) -> String {
1955 format!("__pk_{}", table.name)
1956}
1957
1958fn pk_guard_key(table: &KitTable, values: &Map<String, Value>) -> String {
1959 encode_unique_key(
1960 KIT_KEY_VERSION,
1961 &pk_guard_constraint(table),
1962 &pk_components(table, values),
1963 )
1964}
1965
1966pub(crate) fn key_component(col: &Column, value: Option<&Value>) -> KeyComponent {
1968 match value {
1969 None | Some(Value::Null) => KeyComponent::Null,
1970 Some(v) => match col.storage_type {
1971 ColumnType::Int8
1972 | ColumnType::Int16
1973 | ColumnType::Int32
1974 | ColumnType::Int64
1975 | ColumnType::TimestampNanos => KeyComponent::Int(v.as_i64().unwrap_or(0)),
1976 _ => KeyComponent::Text(value_to_text(v)),
1977 },
1978 }
1979}
1980
1981fn value_to_text(value: &Value) -> String {
1982 match value {
1983 Value::String(s) => s.clone(),
1984 other => other.to_string(),
1985 }
1986}
1987
1988fn pk_components(table: &KitTable, values: &Map<String, Value>) -> Vec<KeyComponent> {
1989 table
1990 .primary_key
1991 .iter()
1992 .map(|name| {
1993 let col = table.column(name);
1994 match col {
1995 Some(c) => key_component(c, values.get(name)),
1996 None => KeyComponent::Null,
1997 }
1998 })
1999 .collect()
2000}
2001
2002pub(crate) fn encoded_pk_for(table: &KitTable, values: &Map<String, Value>) -> String {
2003 encode_pk(&pk_components(table, values))
2004}
2005
2006pub(crate) fn unique_key(
2007 table: &KitTable,
2008 uq: &UniqueConstraint,
2009 values: &Map<String, Value>,
2010) -> Option<String> {
2011 let mut components = Vec::with_capacity(uq.columns.len());
2012 for name in &uq.columns {
2013 let col = table.column(name)?;
2014 let component = key_component(col, values.get(name));
2015 if component == KeyComponent::Null {
2016 return None; }
2018 components.push(component);
2019 }
2020 Some(encode_unique_key(KIT_KEY_VERSION, &uq.name, &components))
2021}
2022
2023pub(crate) fn fk_values_null(fk: &ForeignKey, values: &Map<String, Value>) -> bool {
2024 fk.columns
2025 .iter()
2026 .any(|c| values.get(c).map(|v| v.is_null()).unwrap_or(true))
2027}
2028
2029pub(crate) fn parent_pk_components(
2030 values: &Map<String, Value>,
2031 fk: &ForeignKey,
2032 parent: &KitTable,
2033) -> Vec<KeyComponent> {
2034 fk.columns
2035 .iter()
2036 .zip(&parent.primary_key)
2037 .map(|(child_col, parent_col)| {
2038 let col = parent.column(parent_col);
2039 match col {
2040 Some(c) => key_component(c, values.get(child_col)),
2041 None => KeyComponent::Null,
2042 }
2043 })
2044 .collect()
2045}
2046
2047fn parent_pk_value(
2048 values: &Map<String, Value>,
2049 fk: &ForeignKey,
2050 parent: &KitTable,
2051) -> Result<Value> {
2052 if parent.primary_key.len() == 1 {
2053 let child_col = fk
2054 .columns
2055 .first()
2056 .ok_or_else(|| KitError::Integrity("fk has no columns".into()))?;
2057 Ok(values.get(child_col).cloned().unwrap_or(Value::Null))
2058 } else {
2059 let mut obj = Map::new();
2060 for (child_col, parent_col) in fk.columns.iter().zip(&parent.primary_key) {
2061 obj.insert(
2062 parent_col.clone(),
2063 values.get(child_col).cloned().unwrap_or(Value::Null),
2064 );
2065 }
2066 Ok(Value::Object(obj))
2067 }
2068}
2069
2070fn fk_matches(
2071 child_values: &Map<String, Value>,
2072 fk: &ForeignKey,
2073 parent_pk_map: &Map<String, Value>,
2074 parent_table: &KitTable,
2075) -> bool {
2076 for (child_col, parent_col) in fk.columns.iter().zip(&parent_table.primary_key) {
2077 if child_values.get(child_col) != parent_pk_map.get(parent_col) {
2078 return false;
2079 }
2080 }
2081 true
2082}
2083
2084fn pk_string_to_value(encoded: &str, table: &KitTable) -> Result<Value> {
2089 let components = decode_pk(encoded);
2090 if components.len() != table.primary_key.len() {
2091 return Err(KitError::Validation(format!(
2092 "encoded pk \"{encoded}\" has {} components, expected {}",
2093 components.len(),
2094 table.primary_key.len()
2095 )));
2096 }
2097 if table.primary_key.len() == 1 {
2098 return Ok(component_to_value(&components[0]));
2099 }
2100 let mut obj = Map::new();
2101 for (name, component) in table.primary_key.iter().zip(&components) {
2102 obj.insert(name.clone(), component_to_value(component));
2103 }
2104 Ok(Value::Object(obj))
2105}
2106
2107fn component_to_value(component: &KeyComponent) -> Value {
2108 match component {
2109 KeyComponent::Null => Value::Null,
2110 KeyComponent::Int(i) => Value::Number((*i).into()),
2111 KeyComponent::Text(s) => Value::String(s.clone()),
2112 }
2113}
2114
2115fn row_matches_conditions(table: &KitTable, row: &Row, conditions: &[Condition]) -> bool {
2116 conditions
2117 .iter()
2118 .all(|condition| row_matches_condition(table, row, condition))
2119}
2120
2121fn row_matches_condition(table: &KitTable, row: &Row, condition: &Condition) -> bool {
2122 match condition {
2123 Condition::Pk(key) => {
2124 let Some(pk_name) = table.primary_key.first() else {
2125 return false;
2126 };
2127 let Some(col) = table.column(pk_name) else {
2128 return false;
2129 };
2130 value_index_key(col, &row.values).as_deref() == Some(key.as_slice())
2131 }
2132 Condition::BitmapEq { column_id, value } => {
2133 let Some(col) = column_by_id(table, *column_id) else {
2134 return false;
2135 };
2136 value_index_key(col, &row.values).as_deref() == Some(value.as_slice())
2137 }
2138 Condition::BitmapIn { column_id, values } => {
2139 let Some(col) = column_by_id(table, *column_id) else {
2140 return false;
2141 };
2142 let Some(key) = value_index_key(col, &row.values) else {
2143 return false;
2144 };
2145 values.iter().any(|value| value == &key)
2146 }
2147 Condition::Range { column_id, lo, hi } => {
2148 let Some(col) = column_by_id(table, *column_id) else {
2149 return false;
2150 };
2151 matches!(
2152 json_to_core(
2153 row.values.get(&col.name).unwrap_or(&Value::Null),
2154 col.storage_type
2155 ),
2156 Ok(CoreValue::Int64(v)) if v >= *lo && v <= *hi
2157 )
2158 }
2159 Condition::RangeF64 {
2160 column_id,
2161 lo,
2162 lo_inclusive,
2163 hi,
2164 hi_inclusive,
2165 } => {
2166 let Some(col) = column_by_id(table, *column_id) else {
2167 return false;
2168 };
2169 let Ok(CoreValue::Float64(v)) = json_to_core(
2170 row.values.get(&col.name).unwrap_or(&Value::Null),
2171 col.storage_type,
2172 ) else {
2173 return false;
2174 };
2175 let ge_lo = if *lo_inclusive { v >= *lo } else { v > *lo };
2176 let le_hi = if *hi_inclusive { v <= *hi } else { v < *hi };
2177 ge_lo && le_hi
2178 }
2179 Condition::FmContains { column_id, pattern } => {
2180 let Some(col) = column_by_id(table, *column_id) else {
2181 return false;
2182 };
2183 if pattern.is_empty() {
2184 return true;
2185 }
2186 match json_to_core(
2187 row.values.get(&col.name).unwrap_or(&Value::Null),
2188 col.storage_type,
2189 ) {
2190 Ok(CoreValue::Bytes(bytes)) => bytes
2191 .windows(pattern.len())
2192 .any(|window| window == pattern.as_slice()),
2193 _ => false,
2194 }
2195 }
2196 Condition::IsNull { column_id } => {
2197 let Some(col) = column_by_id(table, *column_id) else {
2198 return false;
2199 };
2200 matches!(row.values.get(&col.name), None | Some(Value::Null))
2201 }
2202 Condition::IsNotNull { column_id } => {
2203 let Some(col) = column_by_id(table, *column_id) else {
2204 return false;
2205 };
2206 !matches!(row.values.get(&col.name), None | Some(Value::Null))
2207 }
2208 _ => true,
2211 }
2212}
2213
2214fn column_by_id(table: &KitTable, column_id: u16) -> Option<&Column> {
2215 table.columns.iter().find(|col| col.id as u16 == column_id)
2216}
2217
2218fn value_index_key(col: &Column, values: &Map<String, Value>) -> Option<Vec<u8>> {
2219 let value = values.get(&col.name).unwrap_or(&Value::Null);
2220 if value.is_null() {
2221 return None;
2222 }
2223 json_to_core(value, col.storage_type)
2224 .ok()
2225 .map(|value| value.encode_key())
2226}