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 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_kit_only(&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_kit_only(&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_kit_only(&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(
887 &self,
888 table: &str,
889 column: &str,
890 query: Vec<f32>,
891 k: usize,
892 ) -> Result<Vec<Row>> {
893 let t = self.require_table(table)?;
894 let col = t
895 .column(column)
896 .ok_or_else(|| KitError::Validation(format!("unknown column \"{column}\"")))?;
897 let cond = Condition::Ann {
898 column_id: col.id as u16,
899 query,
900 k,
901 };
902 self.snapshot_rows_pushed(table, &[cond])
903 }
904
905 pub fn search(
914 &self,
915 table: &str,
916 spec: crate::search::SearchSpec,
917 ) -> Result<Vec<crate::search::SearchHit>> {
918 if self.has_staged_for(table) {
919 return Err(KitError::Validation(
920 "search does not include uncommitted staged rows; commit first".into(),
921 ));
922 }
923 let t = self.require_table(table)?;
924 let request = crate::search::build_core_request(t, &spec)?;
925 let hits = self
926 .db
927 .core_db()
928 .search_for_current_principal(table, &request)
929 .map_err(KitError::from)?;
930 hits.into_iter()
931 .map(|hit| crate::search::core_hit_to_kit(hit, t))
932 .collect()
933 }
934
935 pub fn sparse_match(
940 &self,
941 table: &str,
942 column: &str,
943 query: Vec<(u32, f32)>,
944 k: usize,
945 ) -> Result<Vec<Row>> {
946 let t = self.require_table(table)?;
947 let col = t
948 .column(column)
949 .ok_or_else(|| KitError::Validation(format!("unknown column \"{column}\"")))?;
950 let cond = Condition::SparseMatch {
951 column_id: col.id as u16,
952 query,
953 k,
954 };
955 self.snapshot_rows_pushed(table, &[cond])
956 }
957
958 pub fn execute(&mut self, query: &Query) -> Result<Vec<Value>> {
959 match query {
960 Query::Select(_) => Err(KitError::Validation("use select() for SELECT".into())),
961 Query::Insert(insert) => Ok(vec![self.insert_returning(
962 &insert.table,
963 insert.values.clone(),
964 insert.returning.clone(),
965 )?]),
966 Query::Upsert(upsert) => Ok(vec![self.upsert(
967 &upsert.table,
968 upsert.values.clone(),
969 upsert.on_conflict.clone(),
970 upsert.returning.clone(),
971 )?]),
972 Query::Update(update) => {
973 if update.pk.is_some() && update.filter.is_some() {
974 return Err(KitError::Validation(
975 "update cannot specify both pk and filter".into(),
976 ));
977 }
978 if let Some(pk) = &update.pk {
979 let row = self.update(&update.table, pk, update.set.clone())?;
980 Ok(vec![project_returning(&row, &update.returning)?])
981 } else if let Some(filter) = &update.filter {
982 self.update_where(
983 &update.table,
984 Some(filter.clone()),
985 update.set.clone(),
986 update.returning.clone(),
987 )
988 } else {
989 Err(KitError::Validation(
990 "update requires either a pk or a filter".into(),
991 ))
992 }
993 }
994 Query::Delete(delete) => {
995 if delete.pk.is_some() && delete.filter.is_some() {
996 return Err(KitError::Validation(
997 "delete cannot specify both pk and filter".into(),
998 ));
999 }
1000 if let Some(pk) = &delete.pk {
1001 let t = self.require_table(&delete.table)?;
1002 let pk_map = pk_to_map(pk, t)?;
1003 let projected = match self.get_by_pk_internal(&delete.table, &pk_map)? {
1004 Some(row) => project_returning(&row, &delete.returning)?,
1005 None => {
1006 self.delete(&delete.table, pk)?;
1008 unreachable!("delete returned Ok for a missing row")
1009 }
1010 };
1011 self.delete(&delete.table, pk)?;
1012 Ok(vec![projected])
1013 } else if let Some(filter) = &delete.filter {
1014 self.delete_where(
1015 &delete.table,
1016 Some(filter.clone()),
1017 delete.returning.clone(),
1018 )
1019 } else {
1020 Err(KitError::Validation(
1021 "delete requires either a pk or a filter".into(),
1022 ))
1023 }
1024 }
1025 Query::Aggregate(_) | Query::Join(_) => Err(KitError::Validation(
1026 "aggregate/join are not mutating statements".into(),
1027 )),
1028 }
1029 }
1030
1031 fn exec_ctx(&self) -> ExecCtx<'_> {
1035 ExecCtx::new(
1036 Some(&self.db.schema),
1037 |name: &str, conds: Option<&[Condition]>| match conds {
1038 Some(c) if !c.is_empty() => self.snapshot_rows_pushed(name, c),
1039 _ => self.snapshot_rows(name),
1040 },
1041 )
1042 }
1043
1044 pub fn commit(self) -> Result<()> {
1056 const FLUSH_AFTER_ROWS: usize = 1000;
1057 let mut counts: HashMap<&str, usize> = HashMap::new();
1058 for op in &self.staged {
1059 let table = match op {
1060 StagedOp::Insert { table, .. }
1061 | StagedOp::Update { table, .. }
1062 | StagedOp::Delete { table, .. }
1063 | StagedOp::Truncate { table } => table.as_str(),
1064 };
1065 *counts.entry(table).or_default() += 1;
1066 }
1067 let tables_to_flush: Vec<&str> = counts
1068 .into_iter()
1069 .filter(|&(_, n)| n >= FLUSH_AFTER_ROWS)
1070 .map(|(table, _)| table)
1071 .collect();
1072 let db = self.db;
1073 self.core.commit().map_err(KitError::from)?;
1074 for table in tables_to_flush {
1075 let _ = db.flush_table(table);
1076 }
1077 Ok(())
1078 }
1079
1080 pub fn rollback(self) {
1082 self.core.rollback();
1083 }
1084
1085 fn alloc_temp_id(&mut self) -> u64 {
1088 let id = self.next_temp_id;
1089 self.next_temp_id += 1;
1090 id
1091 }
1092
1093 fn require_table(&self, name: &str) -> Result<&KitTable> {
1094 self.db
1095 .table(name)
1096 .ok_or_else(|| KitError::Integrity(format!("table {name} not found")))
1097 }
1098
1099 pub fn all_rows(&self, table: &str) -> Result<Vec<Row>> {
1101 self.snapshot_rows(table)
1102 }
1103
1104 fn snapshot_rows(&self, table: &str) -> Result<Vec<Row>> {
1105 let t = self.require_table(table)?;
1106 let core_rows = self
1107 .db
1108 .visible_core_rows_at(table, self.core.read_snapshot())?;
1109 let mut rows = core_rows
1110 .into_iter()
1111 .map(|r| core_row_to_json(&r, t))
1112 .collect::<Result<Vec<_>>>()?;
1113 self.replay_staged_rows(t, &mut rows);
1114 Ok(rows)
1115 }
1116
1117 fn snapshot_rows_pushed(&self, table: &str, conditions: &[Condition]) -> Result<Vec<Row>> {
1121 let t = self.require_table(table)?;
1122 if self.has_staged_for(table) {
1123 return Ok(self
1124 .snapshot_rows(table)?
1125 .into_iter()
1126 .filter(|r| row_matches_conditions(t, r, conditions))
1127 .collect());
1128 }
1129 let core_rows = self
1130 .db
1131 .query_core_rows_at(table, conditions, self.core.read_snapshot())?;
1132 core_rows
1133 .into_iter()
1134 .map(|r| core_row_to_json(&r, t))
1135 .collect()
1136 }
1137
1138 fn get_by_pk_internal(&self, table: &str, pk_map: &Map<String, Value>) -> Result<Option<Row>> {
1139 let t = self.require_table(table)?;
1140 if self.has_staged_for(table) {
1141 let rows = self.snapshot_rows(table)?;
1142 return Ok(rows.into_iter().find(|r| pk_matches(&r.values, pk_map, t)));
1143 }
1144 if let Some(conditions) = crate::pushdown::pk_conditions(t, pk_map) {
1147 let core_rows =
1148 self.db
1149 .query_core_rows_at(table, &conditions, self.core.read_snapshot())?;
1150 return Ok(core_rows
1151 .into_iter()
1152 .filter_map(|r| core_row_to_json(&r, t).ok())
1153 .find(|r| pk_matches(&r.values, pk_map, t)));
1154 }
1155 let rows = self.snapshot_rows(table)?;
1156 Ok(rows.into_iter().find(|r| pk_matches(&r.values, pk_map, t)))
1157 }
1158
1159 fn internal_rows(&self, table: &str) -> Result<Vec<CoreRow>> {
1160 self.db
1161 .visible_core_rows_at(table, self.core.read_snapshot())
1162 }
1163
1164 fn check_unique_constraints(
1169 &self,
1170 table: &KitTable,
1171 values: &Map<String, Value>,
1172 old_values: Option<&Map<String, Value>>,
1173 preloaded_guards: Option<&[CoreRow]>,
1174 ) -> Result<()> {
1175 if table.unique_constraints.is_empty() {
1176 return Ok(());
1177 }
1178 let owner_pk = encoded_pk_for(table, values);
1179 let owned;
1182 let committed: &[CoreRow] = match preloaded_guards {
1183 Some(g) => g,
1184 None => {
1185 owned = self.internal_rows(UNIQUE_KEYS)?;
1186 &owned
1187 }
1188 };
1189 for uq in &table.unique_constraints {
1190 let Some(key) = unique_key(table, uq, values) else {
1191 continue;
1192 };
1193 if let Some(old) = old_values {
1195 if unique_key(table, uq, old).as_deref() == Some(key.as_str()) {
1196 continue;
1197 }
1198 }
1199 self.assert_key_free(committed, table, uq, &key, &owner_pk)?;
1200 }
1201 Ok(())
1202 }
1203
1204 fn assert_key_free(
1205 &self,
1206 committed: &[CoreRow],
1207 table: &KitTable,
1208 uq: &UniqueConstraint,
1209 key: &str,
1210 owner_pk: &str,
1211 ) -> Result<()> {
1212 for guard in committed {
1213 if internal_bytes(guard, cols::UQ_ENCODED).as_deref() == Some(key) {
1214 let g_table = internal_bytes(guard, cols::UQ_OWNER_TABLE).unwrap_or_default();
1215 let g_pk = internal_bytes(guard, cols::UQ_OWNER_PK).unwrap_or_default();
1216 if g_table != table.name || g_pk != owner_pk {
1217 return Err(KitError::Duplicate(format!(
1218 "unique constraint {} on {}",
1219 uq.name, table.name
1220 )));
1221 }
1222 }
1223 }
1224 for staged in &self.staged_unique {
1225 if staged.encoded_key == key
1226 && (staged.owner_table != table.name || staged.owner_pk != owner_pk)
1227 {
1228 return Err(KitError::Duplicate(format!(
1229 "unique constraint {} on {}",
1230 uq.name, table.name
1231 )));
1232 }
1233 }
1234 Ok(())
1235 }
1236
1237 fn reserve_unique_guards(
1240 &mut self,
1241 table: &KitTable,
1242 values: &Map<String, Value>,
1243 old_values: Option<&Map<String, Value>>,
1244 ) -> Result<()> {
1245 let owner_pk = encoded_pk_for(table, values);
1246 for uq in &table.unique_constraints {
1247 let new_key = unique_key(table, uq, values);
1248 let old_key = old_values.and_then(|old| unique_key(table, uq, old));
1249 if new_key == old_key {
1250 continue;
1251 }
1252 if let Some(key) = &new_key {
1253 self.put_unique_guard(&uq.name, key, &table.name, &owner_pk)?;
1254 }
1255 if let Some(key) = &old_key {
1256 self.delete_unique_guard(key)?;
1257 }
1258 }
1259 Ok(())
1260 }
1261
1262 fn put_unique_guard(
1263 &mut self,
1264 constraint: &str,
1265 encoded_key: &str,
1266 owner_table: &str,
1267 owner_pk: &str,
1268 ) -> Result<()> {
1269 let now = iso_now();
1270 self.core
1271 .put(
1272 UNIQUE_KEYS,
1273 vec![
1274 (cols::UQ_ENCODED, CoreValue::Bytes(encoded_key.into())),
1275 (cols::UQ_CONSTRAINT, CoreValue::Bytes(constraint.into())),
1276 (cols::UQ_OWNER_TABLE, CoreValue::Bytes(owner_table.into())),
1277 (cols::UQ_OWNER_PK, CoreValue::Bytes(owner_pk.into())),
1278 (cols::UQ_CREATED, CoreValue::Bytes(now.into_bytes())),
1279 ],
1280 )
1281 .map_err(KitError::from)?;
1282 self.staged_unique.push(StagedUnique {
1283 encoded_key: encoded_key.to_string(),
1284 owner_table: owner_table.to_string(),
1285 owner_pk: owner_pk.to_string(),
1286 });
1287 Ok(())
1288 }
1289
1290 fn delete_unique_guard(&mut self, encoded_key: &str) -> Result<()> {
1291 let committed = self.internal_rows(UNIQUE_KEYS)?;
1292 for guard in &committed {
1293 if internal_bytes(guard, cols::UQ_ENCODED).as_deref() == Some(encoded_key) {
1294 self.core
1295 .delete(UNIQUE_KEYS, guard.row_id)
1296 .map_err(KitError::from)?;
1297 }
1298 }
1299 self.staged_unique.retain(|s| s.encoded_key != encoded_key);
1300 Ok(())
1301 }
1302
1303 fn delete_unique_guards_for_owner(&mut self, table: &KitTable, owner_pk: &str) -> Result<()> {
1305 let constraint_names: HashSet<&str> = table
1306 .unique_constraints
1307 .iter()
1308 .map(|u| u.name.as_str())
1309 .collect();
1310 let committed = self.internal_rows(UNIQUE_KEYS)?;
1311 for guard in &committed {
1312 let g_table = internal_bytes(guard, cols::UQ_OWNER_TABLE).unwrap_or_default();
1313 let g_pk = internal_bytes(guard, cols::UQ_OWNER_PK).unwrap_or_default();
1314 let g_constraint = internal_bytes(guard, cols::UQ_CONSTRAINT).unwrap_or_default();
1315 if g_table == table.name
1316 && g_pk == owner_pk
1317 && (constraint_names.contains(g_constraint.as_str())
1318 || g_constraint == pk_guard_constraint(table))
1319 {
1320 self.core
1321 .delete(UNIQUE_KEYS, guard.row_id)
1322 .map_err(KitError::from)?;
1323 }
1324 }
1325 let owner_pk = owner_pk.to_string();
1326 let name = table.name.clone();
1327 self.staged_unique
1328 .retain(|s| !(s.owner_table == name && s.owner_pk == owner_pk));
1329 Ok(())
1330 }
1331
1332 fn check_pk(
1342 &self,
1343 table: &KitTable,
1344 values: &Map<String, Value>,
1345 pk_explicit: bool,
1346 pk_seen: Option<&mut HashSet<String>>,
1347 ) -> Result<()> {
1348 if table.primary_key.is_empty() || !pk_explicit {
1350 return Ok(());
1351 }
1352
1353 if table.primary_key.len() == 1 {
1354 let duplicate = match pk_seen {
1359 Some(seen) => {
1360 let key = encoded_pk_for(table, values);
1361 if seen.contains(&key) {
1362 true
1363 } else {
1364 seen.insert(key);
1365 false
1366 }
1367 }
1368 None => {
1369 self.parent_exists(&table.name, values)?
1370 || self.staged_row_exists(table, values)
1371 }
1372 };
1373 if duplicate {
1374 return Err(KitError::Duplicate(format!(
1375 "primary key {} on {}",
1376 encoded_pk_for(table, values),
1377 table.name
1378 )));
1379 }
1380 return Ok(());
1381 }
1382
1383 let key = pk_guard_key(table, values);
1386 let owner_pk = encoded_pk_for(table, values);
1387 let committed = self.internal_rows(UNIQUE_KEYS)?;
1388 for guard in &committed {
1389 if internal_bytes(guard, cols::UQ_ENCODED).as_deref() == Some(key.as_str()) {
1390 return Err(KitError::Duplicate(format!(
1391 "primary key {} on {}",
1392 owner_pk, table.name
1393 )));
1394 }
1395 }
1396 for staged in &self.staged_unique {
1397 if staged.encoded_key == key {
1398 return Err(KitError::Duplicate(format!(
1399 "primary key {} on {}",
1400 owner_pk, table.name
1401 )));
1402 }
1403 }
1404 Ok(())
1405 }
1406
1407 fn reserve_pk_guard(
1408 &mut self,
1409 table: &KitTable,
1410 values: &Map<String, Value>,
1411 pk_explicit: bool,
1412 ) -> Result<()> {
1413 if table.primary_key.len() < 2 || !pk_explicit {
1416 return Ok(());
1417 }
1418 let key = pk_guard_key(table, values);
1419 let owner_pk = encoded_pk_for(table, values);
1420 let constraint = pk_guard_constraint(table);
1421 self.put_unique_guard(&constraint, &key, &table.name, &owner_pk)
1422 }
1423
1424 fn check_foreign_keys(
1427 &self,
1428 table: &KitTable,
1429 values: &Map<String, Value>,
1430 mut fk_cache: Option<&mut HashMap<String, bool>>,
1431 ) -> Result<()> {
1432 for fk in &table.foreign_keys {
1433 if fk_values_null(fk, values) {
1434 continue;
1435 }
1436 let parent = self.require_table(&fk.references_table)?;
1437 let parent_pk = parent_pk_value(values, fk, parent)?;
1438 let parent_pk_map = pk_to_map(&parent_pk, parent)?;
1439 let cache_key = format!(
1442 "{}\x00{}",
1443 fk.references_table,
1444 encode_pk(&pk_components(parent, &parent_pk_map))
1445 );
1446 let exists = if let Some(cache) = fk_cache.as_mut() {
1447 if let Some(&hit) = cache.get(&cache_key) {
1448 hit
1449 } else {
1450 let hit = self.parent_exists(&fk.references_table, &parent_pk_map)?
1451 || self.staged_row_exists(parent, &parent_pk_map);
1452 cache.insert(cache_key, hit);
1453 hit
1454 }
1455 } else {
1456 self.parent_exists(&fk.references_table, &parent_pk_map)?
1457 || self.staged_row_exists(parent, &parent_pk_map)
1458 };
1459 if exists {
1460 continue;
1461 }
1462 return Err(KitError::ForeignKey(format!(
1463 "{} references {}({})",
1464 fk.name,
1465 fk.references_table,
1466 fk.references_columns.join(",")
1467 )));
1468 }
1469 Ok(())
1470 }
1471
1472 fn touch_foreign_key_guards(
1473 &mut self,
1474 table: &KitTable,
1475 values: &Map<String, Value>,
1476 ) -> Result<()> {
1477 for fk in table.foreign_keys.clone() {
1478 if fk_values_null(&fk, values) {
1479 continue;
1480 }
1481 let parent = self.require_table(&fk.references_table)?.clone();
1482 let components = parent_pk_components(values, &fk, &parent);
1483 self.touch_row_guard(&parent.name, &components)?;
1484 }
1485 Ok(())
1486 }
1487
1488 fn parent_exists(&self, table: &str, pk_map: &Map<String, Value>) -> Result<bool> {
1489 let t = self.require_table(table)?;
1490 if self.has_staged_for(table) {
1491 let rows = self.snapshot_rows(table)?;
1492 return Ok(rows.iter().any(|r| pk_matches(&r.values, pk_map, t)));
1493 }
1494 if let Some(conditions) = crate::pushdown::pk_conditions(t, pk_map) {
1497 let core_rows =
1498 self.db
1499 .query_core_rows_at(table, &conditions, self.core.read_snapshot())?;
1500 return Ok(!core_rows.is_empty());
1501 }
1502 let rows = self.snapshot_rows(table)?;
1503 Ok(rows.iter().any(|r| pk_matches(&r.values, pk_map, t)))
1504 }
1505
1506 fn staged_row_exists(&self, table: &KitTable, pk_map: &Map<String, Value>) -> bool {
1512 let target = encode_pk(&pk_components(table, pk_map));
1513 let mut exists = false;
1514 for staged in &self.staged {
1515 match staged {
1516 StagedOp::Insert { table: t, values }
1517 | StagedOp::Update {
1518 table: t, values, ..
1519 } => {
1520 if t == &table.name && pk_matches(values, pk_map, table) {
1521 exists = true;
1522 }
1523 }
1524 StagedOp::Delete { table: t, pk } => {
1525 if t == &table.name && *pk == target {
1526 exists = false;
1527 }
1528 }
1529 StagedOp::Truncate { table: t } => {
1530 if t == &table.name {
1531 exists = false;
1532 }
1533 }
1534 }
1535 }
1536 exists
1537 }
1538
1539 fn touch_row_guard(&mut self, table: &str, pk_components: &[KeyComponent]) -> Result<()> {
1542 let encoded_pk = encode_pk(pk_components);
1543 let guard_key = encode_row_guard_key(table, &encoded_pk);
1544 if !self.touched_guards.insert(guard_key.clone()) {
1545 return Ok(());
1546 }
1547 let mut version = 1i64;
1551 let committed = self.db.query_core_rows_at(
1552 ROW_GUARDS,
1553 &[Condition::Pk(guard_key.as_bytes().to_vec())],
1554 self.core.read_snapshot(),
1555 )?;
1556 for guard in &committed {
1557 if internal_bytes(guard, cols::RG_ENCODED).as_deref() == Some(guard_key.as_str()) {
1558 if let Some(CoreValue::Int64(v)) = guard.columns.get(&cols::RG_VERSION) {
1559 version = v + 1;
1560 }
1561 self.core
1562 .delete(ROW_GUARDS, guard.row_id)
1563 .map_err(KitError::from)?;
1564 }
1565 }
1566 let now = iso_now();
1567 self.core
1568 .put(
1569 ROW_GUARDS,
1570 vec![
1571 (cols::RG_ENCODED, CoreValue::Bytes(guard_key.into_bytes())),
1572 (cols::RG_TABLE, CoreValue::Bytes(table.into())),
1573 (cols::RG_PK, CoreValue::Bytes(encoded_pk.into_bytes())),
1574 (cols::RG_VERSION, CoreValue::Int64(version)),
1575 (cols::RG_UPDATED, CoreValue::Bytes(now.into_bytes())),
1576 ],
1577 )
1578 .map_err(KitError::from)?;
1579 Ok(())
1580 }
1581
1582 fn has_staged_for(&self, table: &str) -> bool {
1583 self.staged.iter().any(|op| match op {
1584 StagedOp::Insert { table: t, .. }
1585 | StagedOp::Update { table: t, .. }
1586 | StagedOp::Delete { table: t, .. }
1587 | StagedOp::Truncate { table: t } => t == table,
1588 })
1589 }
1590
1591 fn replay_staged_rows(&self, table: &KitTable, rows: &mut Vec<Row>) {
1592 for staged in &self.staged {
1593 match staged {
1594 StagedOp::Insert { table: t, values } if t == &table.name => {
1595 let pk = encoded_pk_for(table, values);
1596 rows.retain(|r| encoded_pk_for(table, &r.values) != pk);
1597 rows.push(Row {
1598 row_id: 0,
1599 values: values.clone(),
1600 });
1601 }
1602 StagedOp::Update {
1603 table: t,
1604 old_pk,
1605 row_id,
1606 values,
1607 } if t == &table.name => {
1608 let new_pk = encoded_pk_for(table, values);
1609 rows.retain(|r| {
1610 let pk = encoded_pk_for(table, &r.values);
1611 pk != *old_pk && pk != new_pk
1612 });
1613 rows.push(Row {
1614 row_id: *row_id,
1615 values: values.clone(),
1616 });
1617 }
1618 StagedOp::Delete { table: t, pk } if t == &table.name => {
1619 rows.retain(|r| encoded_pk_for(table, &r.values) != *pk);
1620 }
1621 StagedOp::Truncate { table: t } if t == &table.name => {
1622 rows.clear();
1623 }
1624 _ => {}
1625 }
1626 }
1627 }
1628
1629 fn delete_guards_for(&mut self, table: &KitTable, values: &Map<String, Value>) -> Result<()> {
1631 let owner_pk = encoded_pk_for(table, values);
1632 self.delete_unique_guards_for_owner(table, &owner_pk)
1633 }
1634
1635 fn delete_all_guards_for_table(&mut self, table: &KitTable) -> Result<()> {
1636 for guard in self.internal_rows(UNIQUE_KEYS)? {
1637 let owner_table = internal_bytes(&guard, cols::UQ_OWNER_TABLE).unwrap_or_default();
1638 if owner_table == table.name {
1639 self.core
1640 .delete(UNIQUE_KEYS, guard.row_id)
1641 .map_err(KitError::from)?;
1642 }
1643 }
1644 for guard in self.internal_rows(ROW_GUARDS)? {
1645 let owner_table = internal_bytes(&guard, cols::RG_TABLE).unwrap_or_default();
1646 if owner_table == table.name {
1647 self.core
1648 .delete(ROW_GUARDS, guard.row_id)
1649 .map_err(KitError::from)?;
1650 }
1651 }
1652 self.staged_unique.retain(|s| s.owner_table != table.name);
1653 self.touched_guards
1654 .retain(|key| !key.starts_with(&format!("{}:", table.name)));
1655 Ok(())
1656 }
1657
1658 fn plan_delete(&self, table: &str, row: &Row) -> Result<(DeletePlan, HashMap<String, Row>)> {
1661 let schema = &self.db.schema;
1662 let t = self.require_table(table)?;
1663 let pk_str = encoded_pk_for(t, &row.values);
1664 let row_cache: RefCell<HashMap<String, Row>> = RefCell::new(HashMap::new());
1669 let find_children =
1670 |child_table: &KitTable, fk: &ForeignKey, parent_pk: &str| -> Vec<(String, String)> {
1671 let parent_pk_value = match pk_string_to_value(parent_pk, t) {
1672 Ok(v) => v,
1673 Err(_) => return Vec::new(),
1674 };
1675 let parent_pk_map = match pk_to_map(&parent_pk_value, t) {
1676 Ok(m) => m,
1677 Err(_) => return Vec::new(),
1678 };
1679 let child_rows = match self.snapshot_rows(&child_table.name) {
1680 Ok(r) => r,
1681 Err(_) => return Vec::new(),
1682 };
1683 let mut out = Vec::new();
1684 for child_row in child_rows {
1685 if fk_matches(&child_row.values, fk, &parent_pk_map, t) {
1686 let child_pk = encoded_pk_for(child_table, &child_row.values);
1687 row_cache
1688 .borrow_mut()
1689 .insert(format!("{}:{}", child_table.name, child_pk), child_row);
1690 out.push((child_pk, parent_pk.to_string()));
1691 }
1692 }
1693 out
1694 };
1695 let plan = plan_delete(schema, table, &pk_str, find_children).map_err(KitError::from)?;
1696 Ok((plan, row_cache.into_inner()))
1697 }
1698
1699 fn apply_set_null(
1700 &mut self,
1701 set_null: &mongreldb_kit_core::planner::SetNullUpdate,
1702 child_row: &Row,
1703 ) -> Result<()> {
1704 let child_table = self.require_table(&set_null.table)?.clone();
1705 let mut values = child_row.values.clone();
1706 for col in &set_null.columns {
1707 let col_def = child_table
1708 .column(col)
1709 .ok_or_else(|| KitError::Integrity(format!("set-null column {col} not found")))?;
1710 if !col_def.nullable {
1711 return Err(KitError::Restrict(format!(
1712 "set-null on non-nullable column {col}"
1713 )));
1714 }
1715 values.insert(col.clone(), Value::Null);
1716 }
1717 mongreldb_kit_core::validation::validate_row_kit_only(&child_table, &values)?;
1719 self.delete_guards_for(&child_table, &child_row.values)?;
1723 let cells = row_to_core_cells(&values, &child_table)?;
1724 self.core
1725 .delete(&set_null.table, RowId(child_row.row_id))
1726 .map_err(KitError::from)?;
1727 self.core
1728 .put(&set_null.table, cells)
1729 .map_err(KitError::from)?;
1730 self.reserve_unique_guards(&child_table, &values, None)?;
1731 self.reserve_pk_guard(&child_table, &values, true)?;
1735 self.staged.push(StagedOp::Update {
1736 table: set_null.table.clone(),
1737 old_pk: encoded_pk_for(&child_table, &child_row.values),
1738 row_id: child_row.row_id,
1739 values: values.clone(),
1740 });
1741 Ok(())
1742 }
1743
1744 fn apply_defaults(&self, row: &mut Map<String, Value>, table: &KitTable) -> Result<()> {
1747 for col in &table.columns {
1748 if row.contains_key(&col.name) && row.get(&col.name) != Some(&Value::Null) {
1749 continue;
1750 }
1751 let Some(default) = &col.default else {
1752 continue;
1753 };
1754 let value = match default {
1755 DefaultKind::Static(v) => v.clone(),
1756 DefaultKind::Now => {
1757 let now = iso_now();
1758 if col.storage_type == ColumnType::Date {
1759 Value::String(now[..10].to_string())
1760 } else {
1761 Value::String(now)
1762 }
1763 }
1764 DefaultKind::Uuid => Value::String(uuid::Uuid::new_v4().to_string()),
1765 DefaultKind::Sequence(name) => {
1766 let start = self.db.allocate_sequence(name, 1)?;
1767 Value::Number(start.into())
1768 }
1769 DefaultKind::CustomName(name) => {
1770 let provider = self.db.default_providers.get(name).ok_or_else(|| {
1771 KitError::Validation(format!("custom default \"{name}\" is not registered"))
1772 })?;
1773 provider()
1774 }
1775 };
1776 row.insert(col.name.clone(), value);
1777 }
1778 Ok(())
1779 }
1780
1781 fn apply_update_defaults(
1789 &self,
1790 merged: &mut Map<String, Value>,
1791 patch_keys: &HashSet<String>,
1792 table: &KitTable,
1793 ) {
1794 let mut now: Option<String> = None;
1795 for col in &table.columns {
1796 if patch_keys.contains(&col.name) {
1797 continue;
1798 }
1799 if col.generated && matches!(col.default, Some(DefaultKind::Now)) {
1800 let stamp = now.get_or_insert_with(iso_now);
1801 let value = if col.storage_type == ColumnType::Date {
1802 Value::String(stamp[..10].to_string())
1803 } else {
1804 Value::String(stamp.clone())
1805 };
1806 merged.insert(col.name.clone(), value);
1807 }
1808 }
1809 }
1810}
1811
1812fn project_returning(row: &Row, columns: &[String]) -> Result<Value> {
1815 let mut out = Map::new();
1816 for c in columns {
1817 out.insert(c.clone(), row.values.get(c).cloned().unwrap_or(Value::Null));
1818 }
1819 Ok(Value::Object(out))
1820}
1821
1822fn pk_values_map(table: &KitTable, values: &Map<String, Value>) -> Map<String, Value> {
1823 let mut out = Map::new();
1824 for name in &table.primary_key {
1825 out.insert(
1826 name.clone(),
1827 values.get(name).cloned().unwrap_or(Value::Null),
1828 );
1829 }
1830 out
1831}
1832
1833fn patch_to_core_cells(
1837 patch: &Map<String, Value>,
1838 table: &KitTable,
1839) -> Result<Vec<(u16, CoreValue)>> {
1840 let mut cells = Vec::new();
1841 for (name, value) in patch {
1842 let Some(col) = table.column(name) else {
1843 continue;
1844 };
1845 cells.push((col.id as u16, json_to_core(value, col.storage_type)?));
1846 }
1847 Ok(cells)
1848}
1849
1850fn select_all(table: &str, filter: Option<Expr>) -> Select {
1851 Select {
1852 table: table.to_string(),
1853 columns: vec![],
1854 filter,
1855 order_by: vec![],
1856 limit: None,
1857 offset: None,
1858 }
1859}
1860
1861fn pk_matches(values: &Map<String, Value>, pk_map: &Map<String, Value>, table: &KitTable) -> bool {
1862 for name in &table.primary_key {
1863 if values.get(name) != pk_map.get(name) {
1864 return false;
1865 }
1866 }
1867 true
1868}
1869
1870fn pk_is_explicit(table: &KitTable, row: &Map<String, Value>) -> bool {
1876 !table.primary_key.is_empty()
1877 && table
1878 .primary_key
1879 .iter()
1880 .all(|name| matches!(row.get(name), Some(v) if !v.is_null()))
1881}
1882
1883fn pk_guard_constraint(table: &KitTable) -> String {
1884 format!("__pk_{}", table.name)
1885}
1886
1887fn pk_guard_key(table: &KitTable, values: &Map<String, Value>) -> String {
1888 encode_unique_key(
1889 KIT_KEY_VERSION,
1890 &pk_guard_constraint(table),
1891 &pk_components(table, values),
1892 )
1893}
1894
1895pub(crate) fn key_component(col: &Column, value: Option<&Value>) -> KeyComponent {
1897 match value {
1898 None | Some(Value::Null) => KeyComponent::Null,
1899 Some(v) => match col.storage_type {
1900 ColumnType::Int8
1901 | ColumnType::Int16
1902 | ColumnType::Int32
1903 | ColumnType::Int64
1904 | ColumnType::TimestampNanos => KeyComponent::Int(v.as_i64().unwrap_or(0)),
1905 _ => KeyComponent::Text(value_to_text(v)),
1906 },
1907 }
1908}
1909
1910fn value_to_text(value: &Value) -> String {
1911 match value {
1912 Value::String(s) => s.clone(),
1913 other => other.to_string(),
1914 }
1915}
1916
1917fn pk_components(table: &KitTable, values: &Map<String, Value>) -> Vec<KeyComponent> {
1918 table
1919 .primary_key
1920 .iter()
1921 .map(|name| {
1922 let col = table.column(name);
1923 match col {
1924 Some(c) => key_component(c, values.get(name)),
1925 None => KeyComponent::Null,
1926 }
1927 })
1928 .collect()
1929}
1930
1931pub(crate) fn encoded_pk_for(table: &KitTable, values: &Map<String, Value>) -> String {
1932 encode_pk(&pk_components(table, values))
1933}
1934
1935pub(crate) fn unique_key(
1936 table: &KitTable,
1937 uq: &UniqueConstraint,
1938 values: &Map<String, Value>,
1939) -> Option<String> {
1940 let mut components = Vec::with_capacity(uq.columns.len());
1941 for name in &uq.columns {
1942 let col = table.column(name)?;
1943 let component = key_component(col, values.get(name));
1944 if component == KeyComponent::Null {
1945 return None; }
1947 components.push(component);
1948 }
1949 Some(encode_unique_key(KIT_KEY_VERSION, &uq.name, &components))
1950}
1951
1952pub(crate) fn fk_values_null(fk: &ForeignKey, values: &Map<String, Value>) -> bool {
1953 fk.columns
1954 .iter()
1955 .any(|c| values.get(c).map(|v| v.is_null()).unwrap_or(true))
1956}
1957
1958pub(crate) fn parent_pk_components(
1959 values: &Map<String, Value>,
1960 fk: &ForeignKey,
1961 parent: &KitTable,
1962) -> Vec<KeyComponent> {
1963 fk.columns
1964 .iter()
1965 .zip(&parent.primary_key)
1966 .map(|(child_col, parent_col)| {
1967 let col = parent.column(parent_col);
1968 match col {
1969 Some(c) => key_component(c, values.get(child_col)),
1970 None => KeyComponent::Null,
1971 }
1972 })
1973 .collect()
1974}
1975
1976fn parent_pk_value(
1977 values: &Map<String, Value>,
1978 fk: &ForeignKey,
1979 parent: &KitTable,
1980) -> Result<Value> {
1981 if parent.primary_key.len() == 1 {
1982 let child_col = fk
1983 .columns
1984 .first()
1985 .ok_or_else(|| KitError::Integrity("fk has no columns".into()))?;
1986 Ok(values.get(child_col).cloned().unwrap_or(Value::Null))
1987 } else {
1988 let mut obj = Map::new();
1989 for (child_col, parent_col) in fk.columns.iter().zip(&parent.primary_key) {
1990 obj.insert(
1991 parent_col.clone(),
1992 values.get(child_col).cloned().unwrap_or(Value::Null),
1993 );
1994 }
1995 Ok(Value::Object(obj))
1996 }
1997}
1998
1999fn fk_matches(
2000 child_values: &Map<String, Value>,
2001 fk: &ForeignKey,
2002 parent_pk_map: &Map<String, Value>,
2003 parent_table: &KitTable,
2004) -> bool {
2005 for (child_col, parent_col) in fk.columns.iter().zip(&parent_table.primary_key) {
2006 if child_values.get(child_col) != parent_pk_map.get(parent_col) {
2007 return false;
2008 }
2009 }
2010 true
2011}
2012
2013fn pk_string_to_value(encoded: &str, table: &KitTable) -> Result<Value> {
2018 let components = decode_pk(encoded);
2019 if components.len() != table.primary_key.len() {
2020 return Err(KitError::Validation(format!(
2021 "encoded pk \"{encoded}\" has {} components, expected {}",
2022 components.len(),
2023 table.primary_key.len()
2024 )));
2025 }
2026 if table.primary_key.len() == 1 {
2027 return Ok(component_to_value(&components[0]));
2028 }
2029 let mut obj = Map::new();
2030 for (name, component) in table.primary_key.iter().zip(&components) {
2031 obj.insert(name.clone(), component_to_value(component));
2032 }
2033 Ok(Value::Object(obj))
2034}
2035
2036fn component_to_value(component: &KeyComponent) -> Value {
2037 match component {
2038 KeyComponent::Null => Value::Null,
2039 KeyComponent::Int(i) => Value::Number((*i).into()),
2040 KeyComponent::Text(s) => Value::String(s.clone()),
2041 }
2042}
2043
2044fn row_matches_conditions(table: &KitTable, row: &Row, conditions: &[Condition]) -> bool {
2045 conditions
2046 .iter()
2047 .all(|condition| row_matches_condition(table, row, condition))
2048}
2049
2050fn row_matches_condition(table: &KitTable, row: &Row, condition: &Condition) -> bool {
2051 match condition {
2052 Condition::Pk(key) => {
2053 let Some(pk_name) = table.primary_key.first() else {
2054 return false;
2055 };
2056 let Some(col) = table.column(pk_name) else {
2057 return false;
2058 };
2059 value_index_key(col, &row.values).as_deref() == Some(key.as_slice())
2060 }
2061 Condition::BitmapEq { column_id, value } => {
2062 let Some(col) = column_by_id(table, *column_id) else {
2063 return false;
2064 };
2065 value_index_key(col, &row.values).as_deref() == Some(value.as_slice())
2066 }
2067 Condition::BitmapIn { column_id, values } => {
2068 let Some(col) = column_by_id(table, *column_id) else {
2069 return false;
2070 };
2071 let Some(key) = value_index_key(col, &row.values) else {
2072 return false;
2073 };
2074 values.iter().any(|value| value == &key)
2075 }
2076 Condition::Range { column_id, lo, hi } => {
2077 let Some(col) = column_by_id(table, *column_id) else {
2078 return false;
2079 };
2080 matches!(
2081 json_to_core(
2082 row.values.get(&col.name).unwrap_or(&Value::Null),
2083 col.storage_type
2084 ),
2085 Ok(CoreValue::Int64(v)) if v >= *lo && v <= *hi
2086 )
2087 }
2088 Condition::RangeF64 {
2089 column_id,
2090 lo,
2091 lo_inclusive,
2092 hi,
2093 hi_inclusive,
2094 } => {
2095 let Some(col) = column_by_id(table, *column_id) else {
2096 return false;
2097 };
2098 let Ok(CoreValue::Float64(v)) = json_to_core(
2099 row.values.get(&col.name).unwrap_or(&Value::Null),
2100 col.storage_type,
2101 ) else {
2102 return false;
2103 };
2104 let ge_lo = if *lo_inclusive { v >= *lo } else { v > *lo };
2105 let le_hi = if *hi_inclusive { v <= *hi } else { v < *hi };
2106 ge_lo && le_hi
2107 }
2108 Condition::FmContains { column_id, pattern } => {
2109 let Some(col) = column_by_id(table, *column_id) else {
2110 return false;
2111 };
2112 if pattern.is_empty() {
2113 return true;
2114 }
2115 match json_to_core(
2116 row.values.get(&col.name).unwrap_or(&Value::Null),
2117 col.storage_type,
2118 ) {
2119 Ok(CoreValue::Bytes(bytes)) => bytes
2120 .windows(pattern.len())
2121 .any(|window| window == pattern.as_slice()),
2122 _ => false,
2123 }
2124 }
2125 Condition::IsNull { column_id } => {
2126 let Some(col) = column_by_id(table, *column_id) else {
2127 return false;
2128 };
2129 matches!(row.values.get(&col.name), None | Some(Value::Null))
2130 }
2131 Condition::IsNotNull { column_id } => {
2132 let Some(col) = column_by_id(table, *column_id) else {
2133 return false;
2134 };
2135 !matches!(row.values.get(&col.name), None | Some(Value::Null))
2136 }
2137 _ => true,
2140 }
2141}
2142
2143fn column_by_id(table: &KitTable, column_id: u16) -> Option<&Column> {
2144 table.columns.iter().find(|col| col.id as u16 == column_id)
2145}
2146
2147fn value_index_key(col: &Column, values: &Map<String, Value>) -> Option<Vec<u8>> {
2148 let value = values.get(&col.name).unwrap_or(&Value::Null);
2149 if value.is_null() {
2150 return None;
2151 }
2152 json_to_core(value, col.storage_type)
2153 .ok()
2154 .map(|value| value.encode_key())
2155}