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(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(&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 columns: merged_cells.into_iter().collect(),
396 deleted: false,
397 };
398 let kit_row = crate::schema::core_row_to_json(&core_row, t)?;
399 let temp_id = self.alloc_temp_id();
400 self.staged.push(StagedOp::Update {
401 table: table.to_string(),
402 old_pk: encoded_pk_for(t, pk_map),
403 row_id: 0,
404 values: kit_row.values.clone(),
405 });
406 Ok(Row {
407 row_id: temp_id,
408 values: kit_row.values,
409 })
410 }
411
412 fn delete_row(&mut self, table: &str, row: &Row) -> Result<u64> {
416 let t = self.require_table(table)?.clone();
417 let (plan, row_cache) = self.plan_delete(table, row)?;
418 if !plan.restricted.is_empty() {
419 let msg = format!(
420 "delete restricted by {}",
421 plan.restricted
422 .iter()
423 .map(|r| format!("{}.{}", r.table, r.constraint))
424 .collect::<Vec<_>>()
425 .join(", ")
426 );
427 return Err(KitError::Restrict(msg));
428 }
429
430 for set_null in &plan.set_null {
434 let key = format!("{}:{}", set_null.table, set_null.pk);
435 if let Some(child_row) = row_cache.get(&key).cloned() {
436 self.apply_set_null(set_null, &child_row)?;
437 }
438 }
439 for del in &plan.delete {
440 if del.table == table {
441 continue; }
443 let child_table = self.require_table(&del.table)?.clone();
444 let key = format!("{}:{}", del.table, del.pk);
445 if let Some(child_row) = row_cache.get(&key) {
446 let row_id = child_row.row_id;
447 let values = child_row.values.clone();
448 self.delete_guards_for(&child_table, &values)?;
449 self.core
450 .delete(&del.table, RowId(row_id))
451 .map_err(KitError::from)?;
452 self.staged.push(StagedOp::Delete {
453 table: del.table.clone(),
454 pk: del.pk.clone(),
455 });
456 }
457 }
458
459 self.delete_guards_for(&t, &row.values)?;
462 self.touch_row_guard(table, &pk_components(&t, &row.values))?;
463 self.staged.push(StagedOp::Delete {
464 table: table.to_string(),
465 pk: encoded_pk_for(&t, &row.values),
466 });
467 Ok(row.row_id)
468 }
469
470 pub fn delete(&mut self, table: &str, pk: &Value) -> Result<()> {
472 let t = self.require_table(table)?.clone();
473 let pk_map = pk_to_map(pk, &t)?;
474
475 let has_inbound_fk = self
481 .db
482 .schema()
483 .tables
484 .iter()
485 .filter(|o| o.name != table)
486 .any(|o| o.foreign_keys.iter().any(|fk| fk.references_table == table));
487 if t.unique_constraints.is_empty() && !has_inbound_fk && t.primary_key.len() == 1 {
488 let pk_name = &t.primary_key[0];
489 if let Some(pk_col) = t.column(pk_name) {
490 let pk_json = pk_map.get(pk_name).cloned().unwrap_or(Value::Null);
491 let pk_core = crate::schema::json_to_core(&pk_json, pk_col.storage_type)?;
492 if let Some(rid) = self.db.lookup_row_id(table, &pk_core.encode_key())? {
493 self.core.delete(table, rid).map_err(KitError::from)?;
494 self.staged.push(StagedOp::Delete {
495 table: table.to_string(),
496 pk: encoded_pk_for(&t, &pk_map),
497 });
498 return Ok(());
499 }
500 return Err(KitError::Integrity(format!("row not found in {table}")));
501 }
502 }
503
504 let row = self
506 .get_by_pk_internal(table, &pk_map)?
507 .ok_or_else(|| KitError::Integrity(format!("row not found in {table}")))?;
508 let row_id = self.delete_row(table, &row)?;
509 self.core
510 .delete(table, RowId(row_id))
511 .map_err(KitError::from)?;
512 Ok(())
513 }
514
515 pub fn truncate(&mut self, table: &str) -> Result<()> {
516 let t = self.require_table(table)?.clone();
517 let has_data_writes = self.staged.iter().any(|op| match op {
520 StagedOp::Insert { table: t, .. }
521 | StagedOp::Update { table: t, .. }
522 | StagedOp::Delete { table: t, .. } => t == table,
523 StagedOp::Truncate { .. } => false,
524 });
525 if has_data_writes {
526 return Err(KitError::Validation(format!(
527 "truncate cannot be combined with prior writes on {table}"
528 )));
529 }
530 if self.db.schema.tables.iter().any(|other| {
531 other.name != t.name
532 && other
533 .foreign_keys
534 .iter()
535 .any(|fk| fk.references_table == t.name)
536 }) {
537 return Err(KitError::Restrict(format!(
538 "table {} is referenced by a foreign key",
539 t.name
540 )));
541 }
542 self.delete_all_guards_for_table(&t)?;
543 self.core.truncate(table).map_err(KitError::from)?;
544 self.staged.push(StagedOp::Truncate { table: t.name });
545 Ok(())
546 }
547
548 pub fn upsert(
549 &mut self,
550 table: &str,
551 row: Map<String, Value>,
552 on_conflict: OnConflict,
553 returning: Vec<String>,
554 ) -> Result<Value> {
555 let t = self.require_table(table)?.clone();
556 let mut values = row;
557 self.apply_defaults(&mut values, &t)?;
558 for col in &t.columns {
559 values.entry(col.name.clone()).or_insert(Value::Null);
560 }
561 mongreldb_kit_core::validation::validate_row(&t, &values)?;
562 let pk_map = pk_values_map(&t, &values);
563 let existing = self.get_by_pk_internal(table, &pk_map)?;
564 match (existing, on_conflict) {
565 (Some(old), OnConflict::DoNothing) => project_returning(&old, &returning),
566 (Some(old), OnConflict::DoUpdate(patch)) => {
567 let mut merged = values.clone();
568 let mut patch_keys = HashSet::new();
569 for (k, v) in patch {
570 if t.column(&k).is_some() {
571 merged.insert(k.clone(), v);
572 patch_keys.insert(k);
573 }
574 }
575 self.apply_update_defaults(&mut merged, &patch_keys, &t);
576 mongreldb_kit_core::validation::validate_row(&t, &merged)?;
577 self.check_unique_constraints(&t, &merged, Some(&old.values), None)?;
578 self.check_foreign_keys(&t, &merged, None)?;
579 self.reserve_unique_guards(&t, &merged, Some(&old.values))?;
580 self.touch_foreign_key_guards(&t, &merged)?;
581
582 let insert_cells = row_to_core_cells(&merged, &t)?;
583 let mut patch_values = Map::new();
584 for k in &patch_keys {
585 patch_values.insert(k.clone(), merged.get(k).cloned().unwrap_or(Value::Null));
586 }
587 let update_cells = patch_to_core_cells(&patch_values, &t)?;
588
589 self.core
590 .upsert(table, insert_cells, UpsertAction::DoUpdate(update_cells))
591 .map_err(KitError::from)?;
592 self.staged.push(StagedOp::Update {
593 table: table.to_string(),
594 old_pk: encoded_pk_for(&t, &old.values),
595 row_id: old.row_id,
596 values: merged.clone(),
597 });
598 project_returning(
599 &Row {
600 row_id: old.row_id,
601 values: merged,
602 },
603 &returning,
604 )
605 }
606 (None, on_conflict) => {
607 self.check_unique_constraints(&t, &values, None, None)?;
608 self.check_foreign_keys(&t, &values, None)?;
609 self.reserve_unique_guards(&t, &values, None)?;
610 let pk_explicit = pk_is_explicit(&t, &values);
611 self.reserve_pk_guard(&t, &values, pk_explicit)?;
612 self.touch_foreign_key_guards(&t, &values)?;
613 let cells = row_to_core_cells(&values, &t)?;
614 let action = match on_conflict {
615 OnConflict::DoNothing => UpsertAction::DoNothing,
616 OnConflict::DoUpdate(patch) => {
617 UpsertAction::DoUpdate(patch_to_core_cells(&patch, &t)?)
618 }
619 };
620 self.core
621 .upsert(table, cells, action)
622 .map_err(KitError::from)?;
623 self.staged.push(StagedOp::Insert {
624 table: table.to_string(),
625 values: values.clone(),
626 });
627 project_returning(&Row { row_id: 0, values }, &returning)
628 }
629 }
630 }
631
632 pub fn update_where(
633 &mut self,
634 table: &str,
635 filter: Option<Expr>,
636 patch: Map<String, Value>,
637 returning: Vec<String>,
638 ) -> Result<Vec<Value>> {
639 let t = self.require_table(table)?.clone();
640 let rows = self.select(&Query::Select(select_all(table, filter)))?;
641 let mut updates = Vec::with_capacity(rows.len());
642 let mut out = Vec::with_capacity(rows.len());
643 let patch_keys: HashSet<String> = patch.keys().cloned().collect();
644 for row in rows {
645 let mut values = row.values.clone();
646 for (k, v) in &patch {
647 if t.column(k).is_some() {
648 values.insert(k.clone(), v.clone());
649 }
650 }
651 self.apply_update_defaults(&mut values, &patch_keys, &t);
652 mongreldb_kit_core::validation::validate_row(&t, &values)?;
653 self.check_unique_constraints(&t, &values, Some(&row.values), None)?;
654 self.check_foreign_keys(&t, &values, None)?;
655 self.reserve_unique_guards(&t, &values, Some(&row.values))?;
656 self.touch_foreign_key_guards(&t, &values)?;
657
658 let cells = row_to_core_cells(&values, &t)?;
659 updates.push((RowId(row.row_id), cells));
660 self.staged.push(StagedOp::Update {
661 table: table.to_string(),
662 old_pk: encoded_pk_for(&t, &row.values),
663 row_id: row.row_id,
664 values: values.clone(),
665 });
666 out.push(project_returning(
667 &Row {
668 row_id: row.row_id,
669 values,
670 },
671 &returning,
672 )?);
673 }
674 if !updates.is_empty() {
675 self.core
676 .update_many(table, updates)
677 .map_err(KitError::from)?;
678 }
679 Ok(out)
680 }
681
682 pub fn delete_where(
683 &mut self,
684 table: &str,
685 filter: Option<Expr>,
686 returning: Vec<String>,
687 ) -> Result<Vec<Value>> {
688 self.require_table(table)?;
689 let rows = self.select(&Query::Select(select_all(table, filter)))?;
690 let mut out = Vec::with_capacity(rows.len());
691 let mut ids = Vec::with_capacity(rows.len());
692 for row in rows {
693 out.push(project_returning(&row, &returning)?);
694 ids.push(self.delete_row(table, &row)?);
695 }
696 if !ids.is_empty() {
697 self.core
698 .delete_many(table, ids.into_iter().map(RowId).collect())
699 .map_err(KitError::from)?;
700 }
701 Ok(out)
702 }
703
704 pub fn get_by_pk(&self, table: &str, pk: &Value) -> Result<Option<Row>> {
706 let t = self.require_table(table)?;
707 let pk_map = pk_to_map(pk, t)?;
708 self.get_by_pk_internal(table, &pk_map)
709 }
710
711 pub fn select(&self, query: &Query) -> Result<Vec<Row>> {
715 let select = match query {
716 Query::Select(s) => s,
717 _ => return Err(KitError::Validation("only SELECT supported".into())),
718 };
719 let ctx = self.exec_ctx();
720 run_select(&ctx, select)
721 }
722
723 pub fn select_distinct(&self, query: &Query) -> Result<Vec<Row>> {
727 let select = match query {
728 Query::Select(s) => s,
729 _ => return Err(KitError::Validation("only SELECT supported".into())),
730 };
731 let ctx = self.exec_ctx();
732 let rows = run_select(&ctx, select)?;
733 Ok(project_distinct(select, rows))
734 }
735
736 pub fn select_with(&self, ctes: &[Cte], body: &Select) -> Result<Vec<Row>> {
739 let mut ctx = self.exec_ctx();
740 for cte in ctes {
741 let rows = run_select(&ctx, &cte.query)?;
742 ctx.add_cte(cte.name.clone(), rows);
743 }
744 run_select(&ctx, body)
745 }
746
747 pub fn aggregate(&self, query: &AggregateQuery) -> Result<Vec<Row>> {
751 if let Some(rows) = self.try_native_aggregate(query)? {
752 return Ok(rows);
753 }
754 let ctx = self.exec_ctx();
755 run_aggregate(&ctx, query)
756 }
757
758 fn try_native_aggregate(&self, query: &AggregateQuery) -> Result<Option<Vec<Row>>> {
768 if !query.group_by.is_empty() || query.having.is_some() || query.aggregates.len() != 1 {
769 return Ok(None);
770 }
771 let agg = &query.aggregates[0];
772 if self.has_staged_for(&query.table) {
773 return Ok(None); }
775
776 if agg.distinct {
781 if !matches!(agg.func, AggFunc::Count) || query.filter.is_some() {
782 return Ok(None);
783 }
784 let Some(col_name) = &agg.column else {
785 return Ok(None);
786 };
787 let t = self.require_table(&query.table)?;
788 let Some(col) = t.columns.iter().find(|c| &c.name == col_name) else {
789 return Ok(None);
790 };
791 let Some(n) = self.db.count_distinct_core_at(
792 &query.table,
793 col.id as u16,
794 self.core.read_snapshot(),
795 )?
796 else {
797 return Ok(None);
798 };
799 let mut values = Map::new();
800 values.insert(agg.alias.clone(), Value::Number((n as i64).into()));
801 return Ok(Some(vec![Row { row_id: 0, values }]));
802 }
803
804 let conditions: Vec<Condition> = match &query.filter {
805 None => Vec::new(),
806 Some(filter) => {
807 let t = self.require_table(&query.table)?;
808 match crate::pushdown::translate_predicate(t, filter) {
809 Some(plan) if plan.can_push() && plan.fully_translated => plan.conditions,
811 _ => return Ok(None),
812 }
813 }
814 };
815 let snapshot = self.core.read_snapshot();
816
817 let value: Value = match (agg.func, &agg.column) {
818 (AggFunc::Count, None) => {
820 let Some(n) = self
821 .db
822 .count_core_rows_at(&query.table, &conditions, snapshot)?
823 else {
824 return Ok(None);
825 };
826 Value::Number((n as i64).into())
827 }
828 (func, Some(col_name)) => {
831 let t = self.require_table(&query.table)?;
832 let Some(col) = t.columns.iter().find(|c| &c.name == col_name) else {
833 return Ok(None);
834 };
835 let native = match func {
836 AggFunc::Count => NativeAgg::Count,
837 AggFunc::Sum => NativeAgg::Sum,
838 AggFunc::Min => NativeAgg::Min,
839 AggFunc::Max => NativeAgg::Max,
840 AggFunc::Avg => NativeAgg::Avg,
841 };
842 let Some(result) = self.db.aggregate_core_at(
843 &query.table,
844 Some(col.id as u16),
845 &conditions,
846 native,
847 snapshot,
848 )?
849 else {
850 return Ok(None);
851 };
852 match result {
855 NativeAggResult::Count(n) => Value::Number((n as i64).into()),
856 NativeAggResult::Int(x) => Value::Number(x.into()),
857 NativeAggResult::Float(f) => serde_json::Number::from_f64(f)
858 .map(Value::Number)
859 .unwrap_or(Value::Null),
860 NativeAggResult::Null => Value::Null,
861 }
862 }
863 _ => return Ok(None),
865 };
866
867 let mut values = Map::new();
868 values.insert(agg.alias.clone(), value);
869 Ok(Some(vec![Row { row_id: 0, values }]))
870 }
871
872 pub fn join(&self, query: &JoinQuery) -> Result<Vec<JoinRow>> {
875 let ctx = self.exec_ctx();
876 run_join(&ctx, query)
877 }
878
879 pub fn ann_search(
884 &self,
885 table: &str,
886 column: &str,
887 query: Vec<f32>,
888 k: usize,
889 ) -> Result<Vec<Row>> {
890 let t = self.require_table(table)?;
891 let col = t
892 .column(column)
893 .ok_or_else(|| KitError::Validation(format!("unknown column \"{column}\"")))?;
894 let cond = Condition::Ann {
895 column_id: col.id as u16,
896 query,
897 k,
898 };
899 self.snapshot_rows_pushed(table, &[cond])
900 }
901
902 pub fn sparse_match(
907 &self,
908 table: &str,
909 column: &str,
910 query: Vec<(u32, f32)>,
911 k: usize,
912 ) -> Result<Vec<Row>> {
913 let t = self.require_table(table)?;
914 let col = t
915 .column(column)
916 .ok_or_else(|| KitError::Validation(format!("unknown column \"{column}\"")))?;
917 let cond = Condition::SparseMatch {
918 column_id: col.id as u16,
919 query,
920 k,
921 };
922 self.snapshot_rows_pushed(table, &[cond])
923 }
924
925 pub fn execute(&mut self, query: &Query) -> Result<Vec<Value>> {
926 match query {
927 Query::Select(_) => Err(KitError::Validation("use select() for SELECT".into())),
928 Query::Insert(insert) => Ok(vec![self.insert_returning(
929 &insert.table,
930 insert.values.clone(),
931 insert.returning.clone(),
932 )?]),
933 Query::Upsert(upsert) => Ok(vec![self.upsert(
934 &upsert.table,
935 upsert.values.clone(),
936 upsert.on_conflict.clone(),
937 upsert.returning.clone(),
938 )?]),
939 Query::Update(update) => {
940 if update.pk.is_some() && update.filter.is_some() {
941 return Err(KitError::Validation(
942 "update cannot specify both pk and filter".into(),
943 ));
944 }
945 if let Some(pk) = &update.pk {
946 let row = self.update(&update.table, pk, update.set.clone())?;
947 Ok(vec![project_returning(&row, &update.returning)?])
948 } else if let Some(filter) = &update.filter {
949 self.update_where(
950 &update.table,
951 Some(filter.clone()),
952 update.set.clone(),
953 update.returning.clone(),
954 )
955 } else {
956 Err(KitError::Validation(
957 "update requires either a pk or a filter".into(),
958 ))
959 }
960 }
961 Query::Delete(delete) => {
962 if delete.pk.is_some() && delete.filter.is_some() {
963 return Err(KitError::Validation(
964 "delete cannot specify both pk and filter".into(),
965 ));
966 }
967 if let Some(pk) = &delete.pk {
968 let t = self.require_table(&delete.table)?;
969 let pk_map = pk_to_map(pk, t)?;
970 let projected = match self.get_by_pk_internal(&delete.table, &pk_map)? {
971 Some(row) => project_returning(&row, &delete.returning)?,
972 None => {
973 self.delete(&delete.table, pk)?;
975 unreachable!("delete returned Ok for a missing row")
976 }
977 };
978 self.delete(&delete.table, pk)?;
979 Ok(vec![projected])
980 } else if let Some(filter) = &delete.filter {
981 self.delete_where(
982 &delete.table,
983 Some(filter.clone()),
984 delete.returning.clone(),
985 )
986 } else {
987 Err(KitError::Validation(
988 "delete requires either a pk or a filter".into(),
989 ))
990 }
991 }
992 Query::Aggregate(_) | Query::Join(_) => Err(KitError::Validation(
993 "aggregate/join are not mutating statements".into(),
994 )),
995 }
996 }
997
998 fn exec_ctx(&self) -> ExecCtx<'_> {
1002 ExecCtx::new(
1003 Some(&self.db.schema),
1004 |name: &str, conds: Option<&[Condition]>| match conds {
1005 Some(c) if !c.is_empty() => self.snapshot_rows_pushed(name, c),
1006 _ => self.snapshot_rows(name),
1007 },
1008 )
1009 }
1010
1011 pub fn commit(self) -> Result<()> {
1023 const FLUSH_AFTER_ROWS: usize = 1000;
1024 let mut counts: HashMap<&str, usize> = HashMap::new();
1025 for op in &self.staged {
1026 let table = match op {
1027 StagedOp::Insert { table, .. }
1028 | StagedOp::Update { table, .. }
1029 | StagedOp::Delete { table, .. }
1030 | StagedOp::Truncate { table } => table.as_str(),
1031 };
1032 *counts.entry(table).or_default() += 1;
1033 }
1034 let tables_to_flush: Vec<&str> = counts
1035 .into_iter()
1036 .filter(|&(_, n)| n >= FLUSH_AFTER_ROWS)
1037 .map(|(table, _)| table)
1038 .collect();
1039 let db = self.db;
1040 self.core.commit().map_err(KitError::from)?;
1041 for table in tables_to_flush {
1042 let _ = db.flush_table(table);
1043 }
1044 Ok(())
1045 }
1046
1047 pub fn rollback(self) {
1049 self.core.rollback();
1050 }
1051
1052 fn alloc_temp_id(&mut self) -> u64 {
1055 let id = self.next_temp_id;
1056 self.next_temp_id += 1;
1057 id
1058 }
1059
1060 fn require_table(&self, name: &str) -> Result<&KitTable> {
1061 self.db
1062 .table(name)
1063 .ok_or_else(|| KitError::Integrity(format!("table {name} not found")))
1064 }
1065
1066 pub fn all_rows(&self, table: &str) -> Result<Vec<Row>> {
1068 self.snapshot_rows(table)
1069 }
1070
1071 fn snapshot_rows(&self, table: &str) -> Result<Vec<Row>> {
1072 let t = self.require_table(table)?;
1073 let core_rows = self
1074 .db
1075 .visible_core_rows_at(table, self.core.read_snapshot())?;
1076 let mut rows = core_rows
1077 .into_iter()
1078 .map(|r| core_row_to_json(&r, t))
1079 .collect::<Result<Vec<_>>>()?;
1080 self.replay_staged_rows(t, &mut rows);
1081 Ok(rows)
1082 }
1083
1084 fn snapshot_rows_pushed(&self, table: &str, conditions: &[Condition]) -> Result<Vec<Row>> {
1088 let t = self.require_table(table)?;
1089 if self.has_staged_for(table) {
1090 return Ok(self
1091 .snapshot_rows(table)?
1092 .into_iter()
1093 .filter(|r| row_matches_conditions(t, r, conditions))
1094 .collect());
1095 }
1096 let core_rows = self
1097 .db
1098 .query_core_rows_at(table, conditions, self.core.read_snapshot())?;
1099 core_rows
1100 .into_iter()
1101 .map(|r| core_row_to_json(&r, t))
1102 .collect()
1103 }
1104
1105 fn get_by_pk_internal(&self, table: &str, pk_map: &Map<String, Value>) -> Result<Option<Row>> {
1106 let t = self.require_table(table)?;
1107 if self.has_staged_for(table) {
1108 let rows = self.snapshot_rows(table)?;
1109 return Ok(rows.into_iter().find(|r| pk_matches(&r.values, pk_map, t)));
1110 }
1111 if let Some(conditions) = crate::pushdown::pk_conditions(t, pk_map) {
1114 let core_rows =
1115 self.db
1116 .query_core_rows_at(table, &conditions, self.core.read_snapshot())?;
1117 return Ok(core_rows
1118 .into_iter()
1119 .filter_map(|r| core_row_to_json(&r, t).ok())
1120 .find(|r| pk_matches(&r.values, pk_map, t)));
1121 }
1122 let rows = self.snapshot_rows(table)?;
1123 Ok(rows.into_iter().find(|r| pk_matches(&r.values, pk_map, t)))
1124 }
1125
1126 fn internal_rows(&self, table: &str) -> Result<Vec<CoreRow>> {
1127 self.db
1128 .visible_core_rows_at(table, self.core.read_snapshot())
1129 }
1130
1131 fn check_unique_constraints(
1136 &self,
1137 table: &KitTable,
1138 values: &Map<String, Value>,
1139 old_values: Option<&Map<String, Value>>,
1140 preloaded_guards: Option<&[CoreRow]>,
1141 ) -> Result<()> {
1142 if table.unique_constraints.is_empty() {
1143 return Ok(());
1144 }
1145 let owner_pk = encoded_pk_for(table, values);
1146 let owned;
1149 let committed: &[CoreRow] = match preloaded_guards {
1150 Some(g) => g,
1151 None => {
1152 owned = self.internal_rows(UNIQUE_KEYS)?;
1153 &owned
1154 }
1155 };
1156 for uq in &table.unique_constraints {
1157 let Some(key) = unique_key(table, uq, values) else {
1158 continue;
1159 };
1160 if let Some(old) = old_values {
1162 if unique_key(table, uq, old).as_deref() == Some(key.as_str()) {
1163 continue;
1164 }
1165 }
1166 self.assert_key_free(committed, table, uq, &key, &owner_pk)?;
1167 }
1168 Ok(())
1169 }
1170
1171 fn assert_key_free(
1172 &self,
1173 committed: &[CoreRow],
1174 table: &KitTable,
1175 uq: &UniqueConstraint,
1176 key: &str,
1177 owner_pk: &str,
1178 ) -> Result<()> {
1179 for guard in committed {
1180 if internal_bytes(guard, cols::UQ_ENCODED).as_deref() == Some(key) {
1181 let g_table = internal_bytes(guard, cols::UQ_OWNER_TABLE).unwrap_or_default();
1182 let g_pk = internal_bytes(guard, cols::UQ_OWNER_PK).unwrap_or_default();
1183 if g_table != table.name || g_pk != owner_pk {
1184 return Err(KitError::Duplicate(format!(
1185 "unique constraint {} on {}",
1186 uq.name, table.name
1187 )));
1188 }
1189 }
1190 }
1191 for staged in &self.staged_unique {
1192 if staged.encoded_key == key
1193 && (staged.owner_table != table.name || staged.owner_pk != owner_pk)
1194 {
1195 return Err(KitError::Duplicate(format!(
1196 "unique constraint {} on {}",
1197 uq.name, table.name
1198 )));
1199 }
1200 }
1201 Ok(())
1202 }
1203
1204 fn reserve_unique_guards(
1207 &mut self,
1208 table: &KitTable,
1209 values: &Map<String, Value>,
1210 old_values: Option<&Map<String, Value>>,
1211 ) -> Result<()> {
1212 let owner_pk = encoded_pk_for(table, values);
1213 for uq in &table.unique_constraints {
1214 let new_key = unique_key(table, uq, values);
1215 let old_key = old_values.and_then(|old| unique_key(table, uq, old));
1216 if new_key == old_key {
1217 continue;
1218 }
1219 if let Some(key) = &new_key {
1220 self.put_unique_guard(&uq.name, key, &table.name, &owner_pk)?;
1221 }
1222 if let Some(key) = &old_key {
1223 self.delete_unique_guard(key)?;
1224 }
1225 }
1226 Ok(())
1227 }
1228
1229 fn put_unique_guard(
1230 &mut self,
1231 constraint: &str,
1232 encoded_key: &str,
1233 owner_table: &str,
1234 owner_pk: &str,
1235 ) -> Result<()> {
1236 let now = iso_now();
1237 self.core
1238 .put(
1239 UNIQUE_KEYS,
1240 vec![
1241 (cols::UQ_ENCODED, CoreValue::Bytes(encoded_key.into())),
1242 (cols::UQ_CONSTRAINT, CoreValue::Bytes(constraint.into())),
1243 (cols::UQ_OWNER_TABLE, CoreValue::Bytes(owner_table.into())),
1244 (cols::UQ_OWNER_PK, CoreValue::Bytes(owner_pk.into())),
1245 (cols::UQ_CREATED, CoreValue::Bytes(now.into_bytes())),
1246 ],
1247 )
1248 .map_err(KitError::from)?;
1249 self.staged_unique.push(StagedUnique {
1250 encoded_key: encoded_key.to_string(),
1251 owner_table: owner_table.to_string(),
1252 owner_pk: owner_pk.to_string(),
1253 });
1254 Ok(())
1255 }
1256
1257 fn delete_unique_guard(&mut self, encoded_key: &str) -> Result<()> {
1258 let committed = self.internal_rows(UNIQUE_KEYS)?;
1259 for guard in &committed {
1260 if internal_bytes(guard, cols::UQ_ENCODED).as_deref() == Some(encoded_key) {
1261 self.core
1262 .delete(UNIQUE_KEYS, guard.row_id)
1263 .map_err(KitError::from)?;
1264 }
1265 }
1266 self.staged_unique.retain(|s| s.encoded_key != encoded_key);
1267 Ok(())
1268 }
1269
1270 fn delete_unique_guards_for_owner(&mut self, table: &KitTable, owner_pk: &str) -> Result<()> {
1272 let constraint_names: HashSet<&str> = table
1273 .unique_constraints
1274 .iter()
1275 .map(|u| u.name.as_str())
1276 .collect();
1277 let committed = self.internal_rows(UNIQUE_KEYS)?;
1278 for guard in &committed {
1279 let g_table = internal_bytes(guard, cols::UQ_OWNER_TABLE).unwrap_or_default();
1280 let g_pk = internal_bytes(guard, cols::UQ_OWNER_PK).unwrap_or_default();
1281 let g_constraint = internal_bytes(guard, cols::UQ_CONSTRAINT).unwrap_or_default();
1282 if g_table == table.name
1283 && g_pk == owner_pk
1284 && (constraint_names.contains(g_constraint.as_str())
1285 || g_constraint == pk_guard_constraint(table))
1286 {
1287 self.core
1288 .delete(UNIQUE_KEYS, guard.row_id)
1289 .map_err(KitError::from)?;
1290 }
1291 }
1292 let owner_pk = owner_pk.to_string();
1293 let name = table.name.clone();
1294 self.staged_unique
1295 .retain(|s| !(s.owner_table == name && s.owner_pk == owner_pk));
1296 Ok(())
1297 }
1298
1299 fn check_pk(
1309 &self,
1310 table: &KitTable,
1311 values: &Map<String, Value>,
1312 pk_explicit: bool,
1313 pk_seen: Option<&mut HashSet<String>>,
1314 ) -> Result<()> {
1315 if table.primary_key.is_empty() || !pk_explicit {
1317 return Ok(());
1318 }
1319
1320 if table.primary_key.len() == 1 {
1321 let duplicate = match pk_seen {
1326 Some(seen) => {
1327 let key = encoded_pk_for(table, values);
1328 if seen.contains(&key) {
1329 true
1330 } else {
1331 seen.insert(key);
1332 false
1333 }
1334 }
1335 None => {
1336 self.parent_exists(&table.name, values)?
1337 || self.staged_row_exists(table, values)
1338 }
1339 };
1340 if duplicate {
1341 return Err(KitError::Duplicate(format!(
1342 "primary key {} on {}",
1343 encoded_pk_for(table, values),
1344 table.name
1345 )));
1346 }
1347 return Ok(());
1348 }
1349
1350 let key = pk_guard_key(table, values);
1353 let owner_pk = encoded_pk_for(table, values);
1354 let committed = self.internal_rows(UNIQUE_KEYS)?;
1355 for guard in &committed {
1356 if internal_bytes(guard, cols::UQ_ENCODED).as_deref() == Some(key.as_str()) {
1357 return Err(KitError::Duplicate(format!(
1358 "primary key {} on {}",
1359 owner_pk, table.name
1360 )));
1361 }
1362 }
1363 for staged in &self.staged_unique {
1364 if staged.encoded_key == key {
1365 return Err(KitError::Duplicate(format!(
1366 "primary key {} on {}",
1367 owner_pk, table.name
1368 )));
1369 }
1370 }
1371 Ok(())
1372 }
1373
1374 fn reserve_pk_guard(
1375 &mut self,
1376 table: &KitTable,
1377 values: &Map<String, Value>,
1378 pk_explicit: bool,
1379 ) -> Result<()> {
1380 if table.primary_key.len() < 2 || !pk_explicit {
1383 return Ok(());
1384 }
1385 let key = pk_guard_key(table, values);
1386 let owner_pk = encoded_pk_for(table, values);
1387 let constraint = pk_guard_constraint(table);
1388 self.put_unique_guard(&constraint, &key, &table.name, &owner_pk)
1389 }
1390
1391 fn check_foreign_keys(
1394 &self,
1395 table: &KitTable,
1396 values: &Map<String, Value>,
1397 mut fk_cache: Option<&mut HashMap<String, bool>>,
1398 ) -> Result<()> {
1399 for fk in &table.foreign_keys {
1400 if fk_values_null(fk, values) {
1401 continue;
1402 }
1403 let parent = self.require_table(&fk.references_table)?;
1404 let parent_pk = parent_pk_value(values, fk, parent)?;
1405 let parent_pk_map = pk_to_map(&parent_pk, parent)?;
1406 let cache_key = format!(
1409 "{}\x00{}",
1410 fk.references_table,
1411 encode_pk(&pk_components(parent, &parent_pk_map))
1412 );
1413 let exists = if let Some(cache) = fk_cache.as_mut() {
1414 if let Some(&hit) = cache.get(&cache_key) {
1415 hit
1416 } else {
1417 let hit = self.parent_exists(&fk.references_table, &parent_pk_map)?
1418 || self.staged_row_exists(parent, &parent_pk_map);
1419 cache.insert(cache_key, hit);
1420 hit
1421 }
1422 } else {
1423 self.parent_exists(&fk.references_table, &parent_pk_map)?
1424 || self.staged_row_exists(parent, &parent_pk_map)
1425 };
1426 if exists {
1427 continue;
1428 }
1429 return Err(KitError::ForeignKey(format!(
1430 "{} references {}({})",
1431 fk.name,
1432 fk.references_table,
1433 fk.references_columns.join(",")
1434 )));
1435 }
1436 Ok(())
1437 }
1438
1439 fn touch_foreign_key_guards(
1440 &mut self,
1441 table: &KitTable,
1442 values: &Map<String, Value>,
1443 ) -> Result<()> {
1444 for fk in table.foreign_keys.clone() {
1445 if fk_values_null(&fk, values) {
1446 continue;
1447 }
1448 let parent = self.require_table(&fk.references_table)?.clone();
1449 let components = parent_pk_components(values, &fk, &parent);
1450 self.touch_row_guard(&parent.name, &components)?;
1451 }
1452 Ok(())
1453 }
1454
1455 fn parent_exists(&self, table: &str, pk_map: &Map<String, Value>) -> Result<bool> {
1456 let t = self.require_table(table)?;
1457 if self.has_staged_for(table) {
1458 let rows = self.snapshot_rows(table)?;
1459 return Ok(rows.iter().any(|r| pk_matches(&r.values, pk_map, t)));
1460 }
1461 if let Some(conditions) = crate::pushdown::pk_conditions(t, pk_map) {
1464 let core_rows =
1465 self.db
1466 .query_core_rows_at(table, &conditions, self.core.read_snapshot())?;
1467 return Ok(!core_rows.is_empty());
1468 }
1469 let rows = self.snapshot_rows(table)?;
1470 Ok(rows.iter().any(|r| pk_matches(&r.values, pk_map, t)))
1471 }
1472
1473 fn staged_row_exists(&self, table: &KitTable, pk_map: &Map<String, Value>) -> bool {
1479 let target = encode_pk(&pk_components(table, pk_map));
1480 let mut exists = false;
1481 for staged in &self.staged {
1482 match staged {
1483 StagedOp::Insert { table: t, values }
1484 | StagedOp::Update {
1485 table: t, values, ..
1486 } => {
1487 if t == &table.name && pk_matches(values, pk_map, table) {
1488 exists = true;
1489 }
1490 }
1491 StagedOp::Delete { table: t, pk } => {
1492 if t == &table.name && *pk == target {
1493 exists = false;
1494 }
1495 }
1496 StagedOp::Truncate { table: t } => {
1497 if t == &table.name {
1498 exists = false;
1499 }
1500 }
1501 }
1502 }
1503 exists
1504 }
1505
1506 fn touch_row_guard(&mut self, table: &str, pk_components: &[KeyComponent]) -> Result<()> {
1509 let encoded_pk = encode_pk(pk_components);
1510 let guard_key = encode_row_guard_key(table, &encoded_pk);
1511 if !self.touched_guards.insert(guard_key.clone()) {
1512 return Ok(());
1513 }
1514 let mut version = 1i64;
1518 let committed = self.db.query_core_rows_at(
1519 ROW_GUARDS,
1520 &[Condition::Pk(guard_key.as_bytes().to_vec())],
1521 self.core.read_snapshot(),
1522 )?;
1523 for guard in &committed {
1524 if internal_bytes(guard, cols::RG_ENCODED).as_deref() == Some(guard_key.as_str()) {
1525 if let Some(CoreValue::Int64(v)) = guard.columns.get(&cols::RG_VERSION) {
1526 version = v + 1;
1527 }
1528 self.core
1529 .delete(ROW_GUARDS, guard.row_id)
1530 .map_err(KitError::from)?;
1531 }
1532 }
1533 let now = iso_now();
1534 self.core
1535 .put(
1536 ROW_GUARDS,
1537 vec![
1538 (cols::RG_ENCODED, CoreValue::Bytes(guard_key.into_bytes())),
1539 (cols::RG_TABLE, CoreValue::Bytes(table.into())),
1540 (cols::RG_PK, CoreValue::Bytes(encoded_pk.into_bytes())),
1541 (cols::RG_VERSION, CoreValue::Int64(version)),
1542 (cols::RG_UPDATED, CoreValue::Bytes(now.into_bytes())),
1543 ],
1544 )
1545 .map_err(KitError::from)?;
1546 Ok(())
1547 }
1548
1549 fn has_staged_for(&self, table: &str) -> bool {
1550 self.staged.iter().any(|op| match op {
1551 StagedOp::Insert { table: t, .. }
1552 | StagedOp::Update { table: t, .. }
1553 | StagedOp::Delete { table: t, .. }
1554 | StagedOp::Truncate { table: t } => t == table,
1555 })
1556 }
1557
1558 fn replay_staged_rows(&self, table: &KitTable, rows: &mut Vec<Row>) {
1559 for staged in &self.staged {
1560 match staged {
1561 StagedOp::Insert { table: t, values } if t == &table.name => {
1562 let pk = encoded_pk_for(table, values);
1563 rows.retain(|r| encoded_pk_for(table, &r.values) != pk);
1564 rows.push(Row {
1565 row_id: 0,
1566 values: values.clone(),
1567 });
1568 }
1569 StagedOp::Update {
1570 table: t,
1571 old_pk,
1572 row_id,
1573 values,
1574 } if t == &table.name => {
1575 let new_pk = encoded_pk_for(table, values);
1576 rows.retain(|r| {
1577 let pk = encoded_pk_for(table, &r.values);
1578 pk != *old_pk && pk != new_pk
1579 });
1580 rows.push(Row {
1581 row_id: *row_id,
1582 values: values.clone(),
1583 });
1584 }
1585 StagedOp::Delete { table: t, pk } if t == &table.name => {
1586 rows.retain(|r| encoded_pk_for(table, &r.values) != *pk);
1587 }
1588 StagedOp::Truncate { table: t } if t == &table.name => {
1589 rows.clear();
1590 }
1591 _ => {}
1592 }
1593 }
1594 }
1595
1596 fn delete_guards_for(&mut self, table: &KitTable, values: &Map<String, Value>) -> Result<()> {
1598 let owner_pk = encoded_pk_for(table, values);
1599 self.delete_unique_guards_for_owner(table, &owner_pk)
1600 }
1601
1602 fn delete_all_guards_for_table(&mut self, table: &KitTable) -> Result<()> {
1603 for guard in self.internal_rows(UNIQUE_KEYS)? {
1604 let owner_table = internal_bytes(&guard, cols::UQ_OWNER_TABLE).unwrap_or_default();
1605 if owner_table == table.name {
1606 self.core
1607 .delete(UNIQUE_KEYS, guard.row_id)
1608 .map_err(KitError::from)?;
1609 }
1610 }
1611 for guard in self.internal_rows(ROW_GUARDS)? {
1612 let owner_table = internal_bytes(&guard, cols::RG_TABLE).unwrap_or_default();
1613 if owner_table == table.name {
1614 self.core
1615 .delete(ROW_GUARDS, guard.row_id)
1616 .map_err(KitError::from)?;
1617 }
1618 }
1619 self.staged_unique.retain(|s| s.owner_table != table.name);
1620 self.touched_guards
1621 .retain(|key| !key.starts_with(&format!("{}:", table.name)));
1622 Ok(())
1623 }
1624
1625 fn plan_delete(&self, table: &str, row: &Row) -> Result<(DeletePlan, HashMap<String, Row>)> {
1628 let schema = &self.db.schema;
1629 let t = self.require_table(table)?;
1630 let pk_str = encoded_pk_for(t, &row.values);
1631 let row_cache: RefCell<HashMap<String, Row>> = RefCell::new(HashMap::new());
1636 let find_children =
1637 |child_table: &KitTable, fk: &ForeignKey, parent_pk: &str| -> Vec<(String, String)> {
1638 let parent_pk_value = match pk_string_to_value(parent_pk, t) {
1639 Ok(v) => v,
1640 Err(_) => return Vec::new(),
1641 };
1642 let parent_pk_map = match pk_to_map(&parent_pk_value, t) {
1643 Ok(m) => m,
1644 Err(_) => return Vec::new(),
1645 };
1646 let child_rows = match self.snapshot_rows(&child_table.name) {
1647 Ok(r) => r,
1648 Err(_) => return Vec::new(),
1649 };
1650 let mut out = Vec::new();
1651 for child_row in child_rows {
1652 if fk_matches(&child_row.values, fk, &parent_pk_map, t) {
1653 let child_pk = encoded_pk_for(child_table, &child_row.values);
1654 row_cache
1655 .borrow_mut()
1656 .insert(format!("{}:{}", child_table.name, child_pk), child_row);
1657 out.push((child_pk, parent_pk.to_string()));
1658 }
1659 }
1660 out
1661 };
1662 let plan = plan_delete(schema, table, &pk_str, find_children).map_err(KitError::from)?;
1663 Ok((plan, row_cache.into_inner()))
1664 }
1665
1666 fn apply_set_null(
1667 &mut self,
1668 set_null: &mongreldb_kit_core::planner::SetNullUpdate,
1669 child_row: &Row,
1670 ) -> Result<()> {
1671 let child_table = self.require_table(&set_null.table)?.clone();
1672 let mut values = child_row.values.clone();
1673 for col in &set_null.columns {
1674 let col_def = child_table
1675 .column(col)
1676 .ok_or_else(|| KitError::Integrity(format!("set-null column {col} not found")))?;
1677 if !col_def.nullable {
1678 return Err(KitError::Restrict(format!(
1679 "set-null on non-nullable column {col}"
1680 )));
1681 }
1682 values.insert(col.clone(), Value::Null);
1683 }
1684 mongreldb_kit_core::validation::validate_row(&child_table, &values)?;
1686 self.delete_guards_for(&child_table, &child_row.values)?;
1690 let cells = row_to_core_cells(&values, &child_table)?;
1691 self.core
1692 .delete(&set_null.table, RowId(child_row.row_id))
1693 .map_err(KitError::from)?;
1694 self.core
1695 .put(&set_null.table, cells)
1696 .map_err(KitError::from)?;
1697 self.reserve_unique_guards(&child_table, &values, None)?;
1698 self.reserve_pk_guard(&child_table, &values, true)?;
1702 self.staged.push(StagedOp::Update {
1703 table: set_null.table.clone(),
1704 old_pk: encoded_pk_for(&child_table, &child_row.values),
1705 row_id: child_row.row_id,
1706 values: values.clone(),
1707 });
1708 Ok(())
1709 }
1710
1711 fn apply_defaults(&self, row: &mut Map<String, Value>, table: &KitTable) -> Result<()> {
1714 for col in &table.columns {
1715 if row.contains_key(&col.name) && row.get(&col.name) != Some(&Value::Null) {
1716 continue;
1717 }
1718 let Some(default) = &col.default else {
1719 continue;
1720 };
1721 let value = match default {
1722 DefaultKind::Static(v) => v.clone(),
1723 DefaultKind::Now => {
1724 let now = iso_now();
1725 if col.storage_type == ColumnType::Date {
1726 Value::String(now[..10].to_string())
1727 } else {
1728 Value::String(now)
1729 }
1730 }
1731 DefaultKind::Uuid => Value::String(uuid::Uuid::new_v4().to_string()),
1732 DefaultKind::Sequence(name) => {
1733 let start = self.db.allocate_sequence(name, 1)?;
1734 Value::Number(start.into())
1735 }
1736 DefaultKind::CustomName(name) => {
1737 let provider = self.db.default_providers.get(name).ok_or_else(|| {
1738 KitError::Validation(format!("custom default \"{name}\" is not registered"))
1739 })?;
1740 provider()
1741 }
1742 };
1743 row.insert(col.name.clone(), value);
1744 }
1745 Ok(())
1746 }
1747
1748 fn apply_update_defaults(
1756 &self,
1757 merged: &mut Map<String, Value>,
1758 patch_keys: &HashSet<String>,
1759 table: &KitTable,
1760 ) {
1761 let mut now: Option<String> = None;
1762 for col in &table.columns {
1763 if patch_keys.contains(&col.name) {
1764 continue;
1765 }
1766 if col.generated && matches!(col.default, Some(DefaultKind::Now)) {
1767 let stamp = now.get_or_insert_with(iso_now);
1768 let value = if col.storage_type == ColumnType::Date {
1769 Value::String(stamp[..10].to_string())
1770 } else {
1771 Value::String(stamp.clone())
1772 };
1773 merged.insert(col.name.clone(), value);
1774 }
1775 }
1776 }
1777}
1778
1779fn project_returning(row: &Row, columns: &[String]) -> Result<Value> {
1782 let mut out = Map::new();
1783 for c in columns {
1784 out.insert(c.clone(), row.values.get(c).cloned().unwrap_or(Value::Null));
1785 }
1786 Ok(Value::Object(out))
1787}
1788
1789fn pk_values_map(table: &KitTable, values: &Map<String, Value>) -> Map<String, Value> {
1790 let mut out = Map::new();
1791 for name in &table.primary_key {
1792 out.insert(
1793 name.clone(),
1794 values.get(name).cloned().unwrap_or(Value::Null),
1795 );
1796 }
1797 out
1798}
1799
1800fn patch_to_core_cells(
1804 patch: &Map<String, Value>,
1805 table: &KitTable,
1806) -> Result<Vec<(u16, CoreValue)>> {
1807 let mut cells = Vec::new();
1808 for (name, value) in patch {
1809 let Some(col) = table.column(name) else {
1810 continue;
1811 };
1812 cells.push((col.id as u16, json_to_core(value, col.storage_type)?));
1813 }
1814 Ok(cells)
1815}
1816
1817fn select_all(table: &str, filter: Option<Expr>) -> Select {
1818 Select {
1819 table: table.to_string(),
1820 columns: vec![],
1821 filter,
1822 order_by: vec![],
1823 limit: None,
1824 offset: None,
1825 }
1826}
1827
1828fn pk_matches(values: &Map<String, Value>, pk_map: &Map<String, Value>, table: &KitTable) -> bool {
1829 for name in &table.primary_key {
1830 if values.get(name) != pk_map.get(name) {
1831 return false;
1832 }
1833 }
1834 true
1835}
1836
1837fn pk_is_explicit(table: &KitTable, row: &Map<String, Value>) -> bool {
1843 !table.primary_key.is_empty()
1844 && table
1845 .primary_key
1846 .iter()
1847 .all(|name| matches!(row.get(name), Some(v) if !v.is_null()))
1848}
1849
1850fn pk_guard_constraint(table: &KitTable) -> String {
1851 format!("__pk_{}", table.name)
1852}
1853
1854fn pk_guard_key(table: &KitTable, values: &Map<String, Value>) -> String {
1855 encode_unique_key(
1856 KIT_KEY_VERSION,
1857 &pk_guard_constraint(table),
1858 &pk_components(table, values),
1859 )
1860}
1861
1862pub(crate) fn key_component(col: &Column, value: Option<&Value>) -> KeyComponent {
1864 match value {
1865 None | Some(Value::Null) => KeyComponent::Null,
1866 Some(v) => match col.storage_type {
1867 ColumnType::Int8
1868 | ColumnType::Int16
1869 | ColumnType::Int32
1870 | ColumnType::Int64
1871 | ColumnType::TimestampNanos => KeyComponent::Int(v.as_i64().unwrap_or(0)),
1872 _ => KeyComponent::Text(value_to_text(v)),
1873 },
1874 }
1875}
1876
1877fn value_to_text(value: &Value) -> String {
1878 match value {
1879 Value::String(s) => s.clone(),
1880 other => other.to_string(),
1881 }
1882}
1883
1884fn pk_components(table: &KitTable, values: &Map<String, Value>) -> Vec<KeyComponent> {
1885 table
1886 .primary_key
1887 .iter()
1888 .map(|name| {
1889 let col = table.column(name);
1890 match col {
1891 Some(c) => key_component(c, values.get(name)),
1892 None => KeyComponent::Null,
1893 }
1894 })
1895 .collect()
1896}
1897
1898pub(crate) fn encoded_pk_for(table: &KitTable, values: &Map<String, Value>) -> String {
1899 encode_pk(&pk_components(table, values))
1900}
1901
1902pub(crate) fn unique_key(
1903 table: &KitTable,
1904 uq: &UniqueConstraint,
1905 values: &Map<String, Value>,
1906) -> Option<String> {
1907 let mut components = Vec::with_capacity(uq.columns.len());
1908 for name in &uq.columns {
1909 let col = table.column(name)?;
1910 let component = key_component(col, values.get(name));
1911 if component == KeyComponent::Null {
1912 return None; }
1914 components.push(component);
1915 }
1916 Some(encode_unique_key(KIT_KEY_VERSION, &uq.name, &components))
1917}
1918
1919pub(crate) fn fk_values_null(fk: &ForeignKey, values: &Map<String, Value>) -> bool {
1920 fk.columns
1921 .iter()
1922 .any(|c| values.get(c).map(|v| v.is_null()).unwrap_or(true))
1923}
1924
1925pub(crate) fn parent_pk_components(
1926 values: &Map<String, Value>,
1927 fk: &ForeignKey,
1928 parent: &KitTable,
1929) -> Vec<KeyComponent> {
1930 fk.columns
1931 .iter()
1932 .zip(&parent.primary_key)
1933 .map(|(child_col, parent_col)| {
1934 let col = parent.column(parent_col);
1935 match col {
1936 Some(c) => key_component(c, values.get(child_col)),
1937 None => KeyComponent::Null,
1938 }
1939 })
1940 .collect()
1941}
1942
1943fn parent_pk_value(
1944 values: &Map<String, Value>,
1945 fk: &ForeignKey,
1946 parent: &KitTable,
1947) -> Result<Value> {
1948 if parent.primary_key.len() == 1 {
1949 let child_col = fk
1950 .columns
1951 .first()
1952 .ok_or_else(|| KitError::Integrity("fk has no columns".into()))?;
1953 Ok(values.get(child_col).cloned().unwrap_or(Value::Null))
1954 } else {
1955 let mut obj = Map::new();
1956 for (child_col, parent_col) in fk.columns.iter().zip(&parent.primary_key) {
1957 obj.insert(
1958 parent_col.clone(),
1959 values.get(child_col).cloned().unwrap_or(Value::Null),
1960 );
1961 }
1962 Ok(Value::Object(obj))
1963 }
1964}
1965
1966fn fk_matches(
1967 child_values: &Map<String, Value>,
1968 fk: &ForeignKey,
1969 parent_pk_map: &Map<String, Value>,
1970 parent_table: &KitTable,
1971) -> bool {
1972 for (child_col, parent_col) in fk.columns.iter().zip(&parent_table.primary_key) {
1973 if child_values.get(child_col) != parent_pk_map.get(parent_col) {
1974 return false;
1975 }
1976 }
1977 true
1978}
1979
1980fn pk_string_to_value(encoded: &str, table: &KitTable) -> Result<Value> {
1985 let components = decode_pk(encoded);
1986 if components.len() != table.primary_key.len() {
1987 return Err(KitError::Validation(format!(
1988 "encoded pk \"{encoded}\" has {} components, expected {}",
1989 components.len(),
1990 table.primary_key.len()
1991 )));
1992 }
1993 if table.primary_key.len() == 1 {
1994 return Ok(component_to_value(&components[0]));
1995 }
1996 let mut obj = Map::new();
1997 for (name, component) in table.primary_key.iter().zip(&components) {
1998 obj.insert(name.clone(), component_to_value(component));
1999 }
2000 Ok(Value::Object(obj))
2001}
2002
2003fn component_to_value(component: &KeyComponent) -> Value {
2004 match component {
2005 KeyComponent::Null => Value::Null,
2006 KeyComponent::Int(i) => Value::Number((*i).into()),
2007 KeyComponent::Text(s) => Value::String(s.clone()),
2008 }
2009}
2010
2011fn row_matches_conditions(table: &KitTable, row: &Row, conditions: &[Condition]) -> bool {
2012 conditions
2013 .iter()
2014 .all(|condition| row_matches_condition(table, row, condition))
2015}
2016
2017fn row_matches_condition(table: &KitTable, row: &Row, condition: &Condition) -> bool {
2018 match condition {
2019 Condition::Pk(key) => {
2020 let Some(pk_name) = table.primary_key.first() else {
2021 return false;
2022 };
2023 let Some(col) = table.column(pk_name) else {
2024 return false;
2025 };
2026 value_index_key(col, &row.values).as_deref() == Some(key.as_slice())
2027 }
2028 Condition::BitmapEq { column_id, value } => {
2029 let Some(col) = column_by_id(table, *column_id) else {
2030 return false;
2031 };
2032 value_index_key(col, &row.values).as_deref() == Some(value.as_slice())
2033 }
2034 Condition::BitmapIn { column_id, values } => {
2035 let Some(col) = column_by_id(table, *column_id) else {
2036 return false;
2037 };
2038 let Some(key) = value_index_key(col, &row.values) else {
2039 return false;
2040 };
2041 values.iter().any(|value| value == &key)
2042 }
2043 Condition::Range { column_id, lo, hi } => {
2044 let Some(col) = column_by_id(table, *column_id) else {
2045 return false;
2046 };
2047 matches!(
2048 json_to_core(
2049 row.values.get(&col.name).unwrap_or(&Value::Null),
2050 col.storage_type
2051 ),
2052 Ok(CoreValue::Int64(v)) if v >= *lo && v <= *hi
2053 )
2054 }
2055 Condition::RangeF64 {
2056 column_id,
2057 lo,
2058 lo_inclusive,
2059 hi,
2060 hi_inclusive,
2061 } => {
2062 let Some(col) = column_by_id(table, *column_id) else {
2063 return false;
2064 };
2065 let Ok(CoreValue::Float64(v)) = json_to_core(
2066 row.values.get(&col.name).unwrap_or(&Value::Null),
2067 col.storage_type,
2068 ) else {
2069 return false;
2070 };
2071 let ge_lo = if *lo_inclusive { v >= *lo } else { v > *lo };
2072 let le_hi = if *hi_inclusive { v <= *hi } else { v < *hi };
2073 ge_lo && le_hi
2074 }
2075 Condition::FmContains { column_id, pattern } => {
2076 let Some(col) = column_by_id(table, *column_id) else {
2077 return false;
2078 };
2079 if pattern.is_empty() {
2080 return true;
2081 }
2082 match json_to_core(
2083 row.values.get(&col.name).unwrap_or(&Value::Null),
2084 col.storage_type,
2085 ) {
2086 Ok(CoreValue::Bytes(bytes)) => bytes
2087 .windows(pattern.len())
2088 .any(|window| window == pattern.as_slice()),
2089 _ => false,
2090 }
2091 }
2092 Condition::IsNull { column_id } => {
2093 let Some(col) = column_by_id(table, *column_id) else {
2094 return false;
2095 };
2096 matches!(row.values.get(&col.name), None | Some(Value::Null))
2097 }
2098 Condition::IsNotNull { column_id } => {
2099 let Some(col) = column_by_id(table, *column_id) else {
2100 return false;
2101 };
2102 !matches!(row.values.get(&col.name), None | Some(Value::Null))
2103 }
2104 _ => true,
2107 }
2108}
2109
2110fn column_by_id(table: &KitTable, column_id: u16) -> Option<&Column> {
2111 table.columns.iter().find(|col| col.id as u16 == column_id)
2112}
2113
2114fn value_index_key(col: &Column, values: &Map<String, Value>) -> Option<Vec<u8>> {
2115 let value = values.get(&col.name).unwrap_or(&Value::Null);
2116 if value.is_null() {
2117 return None;
2118 }
2119 json_to_core(value, col.storage_type)
2120 .ok()
2121 .map(|value| value.encode_key())
2122}