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::memtable::{Row as CoreRow, Value as CoreValue};
31use mongreldb_core::query::Condition;
32use mongreldb_core::RowId;
33use mongreldb_core::UpsertAction;
34use mongreldb_core::{NativeAgg, NativeAggResult};
35use mongreldb_kit_core::keys::{
36 decode_pk, encode_pk, encode_row_guard_key, encode_unique_key, KeyComponent, KIT_KEY_VERSION,
37};
38use mongreldb_kit_core::planner::{plan_delete, DeletePlan};
39use mongreldb_kit_core::query::{
40 AggFunc, AggregateQuery, Cte, Expr, JoinQuery, OnConflict, Query, Select,
41};
42use mongreldb_kit_core::schema::{
43 Column, ColumnType, DefaultKind, ForeignKey, Table as KitTable, UniqueConstraint,
44};
45use serde_json::{Map, Value};
46use std::cell::RefCell;
47use std::collections::{HashMap, HashSet};
48
49pub struct Transaction<'a> {
51 db: &'a crate::db::Database,
52 core: mongreldb_core::txn::Transaction<'a>,
53 staged: Vec<StagedOp>,
54 staged_unique: Vec<StagedUnique>,
56 touched_guards: HashSet<String>,
58 next_temp_id: u64,
59}
60
61#[derive(Debug, Clone)]
62enum StagedOp {
63 Insert {
64 table: String,
65 values: Map<String, Value>,
66 },
67 Update {
68 table: String,
69 old_pk: String,
70 row_id: u64,
71 values: Map<String, Value>,
72 },
73 Delete {
76 table: String,
77 pk: String,
78 },
79 Truncate {
80 table: String,
81 },
82}
83
84#[derive(Debug, Clone)]
85struct StagedUnique {
86 encoded_key: String,
87 owner_table: String,
88 owner_pk: String,
89}
90
91impl<'a> Transaction<'a> {
92 pub(crate) fn new(
93 db: &'a crate::db::Database,
94 core: mongreldb_core::txn::Transaction<'a>,
95 ) -> Self {
96 Self {
97 db,
98 core,
99 staged: Vec::new(),
100 staged_unique: Vec::new(),
101 touched_guards: HashSet::new(),
102 next_temp_id: 1,
103 }
104 }
105
106 pub fn insert(&mut self, table: &str, row: Map<String, Value>) -> Result<Row> {
108 let t = self.require_table(table)?.clone();
109 self.do_insert(table, &t, row, None)
110 }
111
112 pub fn insert_returning(
113 &mut self,
114 table: &str,
115 row: Map<String, Value>,
116 returning: Vec<String>,
117 ) -> Result<Value> {
118 let inserted = self.insert(table, row)?;
119 project_returning(&inserted, &returning)
120 }
121
122 pub fn insert_many(&mut self, table: &str, rows: Vec<Map<String, Value>>) -> Result<Vec<Row>> {
131 let t = self.require_table(table)?.clone();
132 let mut pk_seen: Option<HashSet<String>> = if t.primary_key.len() == 1 {
135 let mut set = HashSet::new();
136 for r in self.snapshot_rows(table)? {
137 set.insert(encoded_pk_for(&t, &r.values));
138 }
139 Some(set)
140 } else {
141 None
142 };
143 let mut out = Vec::with_capacity(rows.len());
144 for row in rows {
145 out.push(self.do_insert(table, &t, row, pk_seen.as_mut())?);
146 }
147 Ok(out)
148 }
149
150 fn do_insert(
155 &mut self,
156 table: &str,
157 t: &KitTable,
158 mut row: Map<String, Value>,
159 pk_seen: Option<&mut HashSet<String>>,
160 ) -> Result<Row> {
161 let pk_explicit = pk_is_explicit(t, &row);
165
166 self.apply_defaults(&mut row, t)?;
167 for col in &t.columns {
170 row.entry(col.name.clone()).or_insert(Value::Null);
171 }
172 mongreldb_kit_core::validation::validate_row(t, &row)?;
173
174 self.check_unique_constraints(t, &row, None)?;
176 self.check_pk(t, &row, pk_explicit, pk_seen)?;
177 self.check_foreign_keys(t, &row)?;
178
179 self.reserve_unique_guards(t, &row, None)?;
181 self.reserve_pk_guard(t, &row, pk_explicit)?;
182 self.touch_foreign_key_guards(t, &row)?;
183
184 let cells = row_to_core_cells(&row, t)?;
185 self.core.put(table, cells).map_err(KitError::from)?;
186 let temp_id = self.alloc_temp_id();
187 self.staged.push(StagedOp::Insert {
188 table: table.to_string(),
189 values: row.clone(),
190 });
191 Ok(Row {
192 row_id: temp_id,
193 values: row,
194 })
195 }
196
197 pub fn update(&mut self, table: &str, pk: &Value, patch: Map<String, Value>) -> Result<Row> {
199 let t = self.require_table(table)?.clone();
200 let pk_map = pk_to_map(pk, &t)?;
201 let old_row = self
202 .get_by_pk_internal(table, &pk_map)?
203 .ok_or_else(|| KitError::Integrity(format!("row not found in {table}")))?;
204
205 let patch_keys: HashSet<String> = patch.keys().cloned().collect();
206 let mut values = old_row.values.clone();
207 for (k, v) in patch {
208 if t.column(&k).is_some() {
209 values.insert(k, v);
210 }
211 }
212 self.apply_update_defaults(&mut values, &patch_keys, &t);
213 mongreldb_kit_core::validation::validate_row(&t, &values)?;
214 self.check_unique_constraints(&t, &values, Some(&old_row.values))?;
215 self.check_foreign_keys(&t, &values)?;
216
217 self.reserve_unique_guards(&t, &values, Some(&old_row.values))?;
219 self.touch_foreign_key_guards(&t, &values)?;
220
221 let cells = row_to_core_cells(&values, &t)?;
222 self.core
223 .delete(table, RowId(old_row.row_id))
224 .map_err(KitError::from)?;
225 self.core.put(table, cells).map_err(KitError::from)?;
226 let temp_id = self.alloc_temp_id();
227 self.staged.push(StagedOp::Update {
228 table: table.to_string(),
229 old_pk: encoded_pk_for(&t, &old_row.values),
230 row_id: old_row.row_id,
231 values: values.clone(),
232 });
233 Ok(Row {
234 row_id: temp_id,
235 values,
236 })
237 }
238
239 fn delete_row(&mut self, table: &str, row: &Row) -> Result<u64> {
243 let t = self.require_table(table)?.clone();
244 let (plan, row_cache) = self.plan_delete(table, row)?;
245 if !plan.restricted.is_empty() {
246 let msg = format!(
247 "delete restricted by {}",
248 plan.restricted
249 .iter()
250 .map(|r| format!("{}.{}", r.table, r.constraint))
251 .collect::<Vec<_>>()
252 .join(", ")
253 );
254 return Err(KitError::Restrict(msg));
255 }
256
257 for set_null in &plan.set_null {
261 let key = format!("{}:{}", set_null.table, set_null.pk);
262 if let Some(child_row) = row_cache.get(&key).cloned() {
263 self.apply_set_null(set_null, &child_row)?;
264 }
265 }
266 for del in &plan.delete {
267 if del.table == table {
268 continue; }
270 let child_table = self.require_table(&del.table)?.clone();
271 let key = format!("{}:{}", del.table, del.pk);
272 if let Some(child_row) = row_cache.get(&key) {
273 let row_id = child_row.row_id;
274 let values = child_row.values.clone();
275 self.delete_guards_for(&child_table, &values)?;
276 self.core
277 .delete(&del.table, RowId(row_id))
278 .map_err(KitError::from)?;
279 self.staged.push(StagedOp::Delete {
280 table: del.table.clone(),
281 pk: del.pk.clone(),
282 });
283 }
284 }
285
286 self.delete_guards_for(&t, &row.values)?;
289 self.touch_row_guard(table, &pk_components(&t, &row.values))?;
290 self.staged.push(StagedOp::Delete {
291 table: table.to_string(),
292 pk: encoded_pk_for(&t, &row.values),
293 });
294 Ok(row.row_id)
295 }
296
297 pub fn delete(&mut self, table: &str, pk: &Value) -> Result<()> {
299 let t = self.require_table(table)?.clone();
300 let pk_map = pk_to_map(pk, &t)?;
301 let row = self
302 .get_by_pk_internal(table, &pk_map)?
303 .ok_or_else(|| KitError::Integrity(format!("row not found in {table}")))?;
304 let row_id = self.delete_row(table, &row)?;
305 self.core
306 .delete(table, RowId(row_id))
307 .map_err(KitError::from)?;
308 Ok(())
309 }
310
311 pub fn truncate(&mut self, table: &str) -> Result<()> {
312 let t = self.require_table(table)?.clone();
313 let has_data_writes = self.staged.iter().any(|op| match op {
316 StagedOp::Insert { table: t, .. }
317 | StagedOp::Update { table: t, .. }
318 | StagedOp::Delete { table: t, .. } => t == table,
319 StagedOp::Truncate { .. } => false,
320 });
321 if has_data_writes {
322 return Err(KitError::Validation(format!(
323 "truncate cannot be combined with prior writes on {table}"
324 )));
325 }
326 if self.db.schema.tables.iter().any(|other| {
327 other.name != t.name
328 && other
329 .foreign_keys
330 .iter()
331 .any(|fk| fk.references_table == t.name)
332 }) {
333 return Err(KitError::Restrict(format!(
334 "table {} is referenced by a foreign key",
335 t.name
336 )));
337 }
338 self.delete_all_guards_for_table(&t)?;
339 self.core.truncate(table).map_err(KitError::from)?;
340 self.staged.push(StagedOp::Truncate { table: t.name });
341 Ok(())
342 }
343
344 pub fn upsert(
345 &mut self,
346 table: &str,
347 row: Map<String, Value>,
348 on_conflict: OnConflict,
349 returning: Vec<String>,
350 ) -> Result<Value> {
351 let t = self.require_table(table)?.clone();
352 let mut values = row;
353 self.apply_defaults(&mut values, &t)?;
354 for col in &t.columns {
355 values.entry(col.name.clone()).or_insert(Value::Null);
356 }
357 mongreldb_kit_core::validation::validate_row(&t, &values)?;
358 let pk_map = pk_values_map(&t, &values);
359 let existing = self.get_by_pk_internal(table, &pk_map)?;
360 match (existing, on_conflict) {
361 (Some(old), OnConflict::DoNothing) => project_returning(&old, &returning),
362 (Some(old), OnConflict::DoUpdate(patch)) => {
363 let mut merged = values.clone();
364 let mut patch_keys = HashSet::new();
365 for (k, v) in patch {
366 if t.column(&k).is_some() {
367 merged.insert(k.clone(), v);
368 patch_keys.insert(k);
369 }
370 }
371 self.apply_update_defaults(&mut merged, &patch_keys, &t);
372 mongreldb_kit_core::validation::validate_row(&t, &merged)?;
373 self.check_unique_constraints(&t, &merged, Some(&old.values))?;
374 self.check_foreign_keys(&t, &merged)?;
375 self.reserve_unique_guards(&t, &merged, Some(&old.values))?;
376 self.touch_foreign_key_guards(&t, &merged)?;
377
378 let insert_cells = row_to_core_cells(&merged, &t)?;
379 let mut patch_values = Map::new();
380 for k in &patch_keys {
381 patch_values.insert(k.clone(), merged.get(k).cloned().unwrap_or(Value::Null));
382 }
383 let update_cells = patch_to_core_cells(&patch_values, &t)?;
384
385 self.core
386 .upsert(table, insert_cells, UpsertAction::DoUpdate(update_cells))
387 .map_err(KitError::from)?;
388 self.staged.push(StagedOp::Update {
389 table: table.to_string(),
390 old_pk: encoded_pk_for(&t, &old.values),
391 row_id: old.row_id,
392 values: merged.clone(),
393 });
394 project_returning(
395 &Row {
396 row_id: old.row_id,
397 values: merged,
398 },
399 &returning,
400 )
401 }
402 (None, on_conflict) => {
403 self.check_unique_constraints(&t, &values, None)?;
404 self.check_foreign_keys(&t, &values)?;
405 self.reserve_unique_guards(&t, &values, None)?;
406 let pk_explicit = pk_is_explicit(&t, &values);
407 self.reserve_pk_guard(&t, &values, pk_explicit)?;
408 self.touch_foreign_key_guards(&t, &values)?;
409 let cells = row_to_core_cells(&values, &t)?;
410 let action = match on_conflict {
411 OnConflict::DoNothing => UpsertAction::DoNothing,
412 OnConflict::DoUpdate(patch) => {
413 UpsertAction::DoUpdate(patch_to_core_cells(&patch, &t)?)
414 }
415 };
416 self.core
417 .upsert(table, cells, action)
418 .map_err(KitError::from)?;
419 self.staged.push(StagedOp::Insert {
420 table: table.to_string(),
421 values: values.clone(),
422 });
423 project_returning(&Row { row_id: 0, values }, &returning)
424 }
425 }
426 }
427
428 pub fn update_where(
429 &mut self,
430 table: &str,
431 filter: Option<Expr>,
432 patch: Map<String, Value>,
433 returning: Vec<String>,
434 ) -> Result<Vec<Value>> {
435 let t = self.require_table(table)?.clone();
436 let rows = self.select(&Query::Select(select_all(table, filter)))?;
437 let mut updates = Vec::with_capacity(rows.len());
438 let mut out = Vec::with_capacity(rows.len());
439 let patch_keys: HashSet<String> = patch.keys().cloned().collect();
440 for row in rows {
441 let mut values = row.values.clone();
442 for (k, v) in &patch {
443 if t.column(k).is_some() {
444 values.insert(k.clone(), v.clone());
445 }
446 }
447 self.apply_update_defaults(&mut values, &patch_keys, &t);
448 mongreldb_kit_core::validation::validate_row(&t, &values)?;
449 self.check_unique_constraints(&t, &values, Some(&row.values))?;
450 self.check_foreign_keys(&t, &values)?;
451 self.reserve_unique_guards(&t, &values, Some(&row.values))?;
452 self.touch_foreign_key_guards(&t, &values)?;
453
454 let cells = row_to_core_cells(&values, &t)?;
455 updates.push((RowId(row.row_id), cells));
456 self.staged.push(StagedOp::Update {
457 table: table.to_string(),
458 old_pk: encoded_pk_for(&t, &row.values),
459 row_id: row.row_id,
460 values: values.clone(),
461 });
462 out.push(project_returning(
463 &Row {
464 row_id: row.row_id,
465 values,
466 },
467 &returning,
468 )?);
469 }
470 if !updates.is_empty() {
471 self.core
472 .update_many(table, updates)
473 .map_err(KitError::from)?;
474 }
475 Ok(out)
476 }
477
478 pub fn delete_where(
479 &mut self,
480 table: &str,
481 filter: Option<Expr>,
482 returning: Vec<String>,
483 ) -> Result<Vec<Value>> {
484 self.require_table(table)?;
485 let rows = self.select(&Query::Select(select_all(table, filter)))?;
486 let mut out = Vec::with_capacity(rows.len());
487 let mut ids = Vec::with_capacity(rows.len());
488 for row in rows {
489 out.push(project_returning(&row, &returning)?);
490 ids.push(self.delete_row(table, &row)?);
491 }
492 if !ids.is_empty() {
493 self.core
494 .delete_many(table, ids.into_iter().map(RowId).collect())
495 .map_err(KitError::from)?;
496 }
497 Ok(out)
498 }
499
500 pub fn get_by_pk(&self, table: &str, pk: &Value) -> Result<Option<Row>> {
502 let t = self.require_table(table)?;
503 let pk_map = pk_to_map(pk, t)?;
504 self.get_by_pk_internal(table, &pk_map)
505 }
506
507 pub fn select(&self, query: &Query) -> Result<Vec<Row>> {
511 let select = match query {
512 Query::Select(s) => s,
513 _ => return Err(KitError::Validation("only SELECT supported".into())),
514 };
515 let ctx = self.exec_ctx();
516 run_select(&ctx, select)
517 }
518
519 pub fn select_distinct(&self, query: &Query) -> Result<Vec<Row>> {
523 let select = match query {
524 Query::Select(s) => s,
525 _ => return Err(KitError::Validation("only SELECT supported".into())),
526 };
527 let ctx = self.exec_ctx();
528 let rows = run_select(&ctx, select)?;
529 Ok(project_distinct(select, rows))
530 }
531
532 pub fn select_with(&self, ctes: &[Cte], body: &Select) -> Result<Vec<Row>> {
535 let mut ctx = self.exec_ctx();
536 for cte in ctes {
537 let rows = run_select(&ctx, &cte.query)?;
538 ctx.add_cte(cte.name.clone(), rows);
539 }
540 run_select(&ctx, body)
541 }
542
543 pub fn aggregate(&self, query: &AggregateQuery) -> Result<Vec<Row>> {
547 if let Some(rows) = self.try_native_aggregate(query)? {
548 return Ok(rows);
549 }
550 let ctx = self.exec_ctx();
551 run_aggregate(&ctx, query)
552 }
553
554 fn try_native_aggregate(&self, query: &AggregateQuery) -> Result<Option<Vec<Row>>> {
564 if !query.group_by.is_empty() || query.having.is_some() || query.aggregates.len() != 1 {
565 return Ok(None);
566 }
567 let agg = &query.aggregates[0];
568 if self.has_staged_for(&query.table) {
569 return Ok(None); }
571
572 if agg.distinct {
577 if !matches!(agg.func, AggFunc::Count) || query.filter.is_some() {
578 return Ok(None);
579 }
580 let Some(col_name) = &agg.column else {
581 return Ok(None);
582 };
583 let t = self.require_table(&query.table)?;
584 let Some(col) = t.columns.iter().find(|c| &c.name == col_name) else {
585 return Ok(None);
586 };
587 let Some(n) = self.db.count_distinct_core_at(
588 &query.table,
589 col.id as u16,
590 self.core.read_snapshot(),
591 )?
592 else {
593 return Ok(None);
594 };
595 let mut values = Map::new();
596 values.insert(agg.alias.clone(), Value::Number((n as i64).into()));
597 return Ok(Some(vec![Row { row_id: 0, values }]));
598 }
599
600 let conditions: Vec<Condition> = match &query.filter {
601 None => Vec::new(),
602 Some(filter) => {
603 let t = self.require_table(&query.table)?;
604 match crate::pushdown::translate_predicate(t, filter) {
605 Some(plan) if plan.can_push() && plan.fully_translated => plan.conditions,
607 _ => return Ok(None),
608 }
609 }
610 };
611 let snapshot = self.core.read_snapshot();
612
613 let value: Value = match (agg.func, &agg.column) {
614 (AggFunc::Count, None) => {
616 let Some(n) = self
617 .db
618 .count_core_rows_at(&query.table, &conditions, snapshot)?
619 else {
620 return Ok(None);
621 };
622 Value::Number((n as i64).into())
623 }
624 (func, Some(col_name)) => {
627 let t = self.require_table(&query.table)?;
628 let Some(col) = t.columns.iter().find(|c| &c.name == col_name) else {
629 return Ok(None);
630 };
631 let native = match func {
632 AggFunc::Count => NativeAgg::Count,
633 AggFunc::Sum => NativeAgg::Sum,
634 AggFunc::Min => NativeAgg::Min,
635 AggFunc::Max => NativeAgg::Max,
636 AggFunc::Avg => NativeAgg::Avg,
637 };
638 let Some(result) = self.db.aggregate_core_at(
639 &query.table,
640 Some(col.id as u16),
641 &conditions,
642 native,
643 snapshot,
644 )?
645 else {
646 return Ok(None);
647 };
648 match result {
651 NativeAggResult::Count(n) => Value::Number((n as i64).into()),
652 NativeAggResult::Int(x) => Value::Number(x.into()),
653 NativeAggResult::Float(f) => serde_json::Number::from_f64(f)
654 .map(Value::Number)
655 .unwrap_or(Value::Null),
656 NativeAggResult::Null => Value::Null,
657 }
658 }
659 _ => return Ok(None),
661 };
662
663 let mut values = Map::new();
664 values.insert(agg.alias.clone(), value);
665 Ok(Some(vec![Row { row_id: 0, values }]))
666 }
667
668 pub fn join(&self, query: &JoinQuery) -> Result<Vec<JoinRow>> {
671 let ctx = self.exec_ctx();
672 run_join(&ctx, query)
673 }
674
675 pub fn ann_search(
680 &self,
681 table: &str,
682 column: &str,
683 query: Vec<f32>,
684 k: usize,
685 ) -> Result<Vec<Row>> {
686 let t = self.require_table(table)?;
687 let col = t
688 .column(column)
689 .ok_or_else(|| KitError::Validation(format!("unknown column \"{column}\"")))?;
690 let cond = Condition::Ann {
691 column_id: col.id as u16,
692 query,
693 k,
694 };
695 self.snapshot_rows_pushed(table, &[cond])
696 }
697
698 pub fn sparse_match(
703 &self,
704 table: &str,
705 column: &str,
706 query: Vec<(u32, f32)>,
707 k: usize,
708 ) -> Result<Vec<Row>> {
709 let t = self.require_table(table)?;
710 let col = t
711 .column(column)
712 .ok_or_else(|| KitError::Validation(format!("unknown column \"{column}\"")))?;
713 let cond = Condition::SparseMatch {
714 column_id: col.id as u16,
715 query,
716 k,
717 };
718 self.snapshot_rows_pushed(table, &[cond])
719 }
720
721 pub fn execute(&mut self, query: &Query) -> Result<Vec<Value>> {
722 match query {
723 Query::Select(_) => Err(KitError::Validation("use select() for SELECT".into())),
724 Query::Insert(insert) => Ok(vec![self.insert_returning(
725 &insert.table,
726 insert.values.clone(),
727 insert.returning.clone(),
728 )?]),
729 Query::Upsert(upsert) => Ok(vec![self.upsert(
730 &upsert.table,
731 upsert.values.clone(),
732 upsert.on_conflict.clone(),
733 upsert.returning.clone(),
734 )?]),
735 Query::Update(update) => {
736 if update.pk.is_some() && update.filter.is_some() {
737 return Err(KitError::Validation(
738 "update cannot specify both pk and filter".into(),
739 ));
740 }
741 if let Some(pk) = &update.pk {
742 let row = self.update(&update.table, pk, update.set.clone())?;
743 Ok(vec![project_returning(&row, &update.returning)?])
744 } else if let Some(filter) = &update.filter {
745 self.update_where(
746 &update.table,
747 Some(filter.clone()),
748 update.set.clone(),
749 update.returning.clone(),
750 )
751 } else {
752 Err(KitError::Validation(
753 "update requires either a pk or a filter".into(),
754 ))
755 }
756 }
757 Query::Delete(delete) => {
758 if delete.pk.is_some() && delete.filter.is_some() {
759 return Err(KitError::Validation(
760 "delete cannot specify both pk and filter".into(),
761 ));
762 }
763 if let Some(pk) = &delete.pk {
764 let t = self.require_table(&delete.table)?;
765 let pk_map = pk_to_map(pk, t)?;
766 let projected = match self.get_by_pk_internal(&delete.table, &pk_map)? {
767 Some(row) => project_returning(&row, &delete.returning)?,
768 None => {
769 self.delete(&delete.table, pk)?;
771 unreachable!("delete returned Ok for a missing row")
772 }
773 };
774 self.delete(&delete.table, pk)?;
775 Ok(vec![projected])
776 } else if let Some(filter) = &delete.filter {
777 self.delete_where(
778 &delete.table,
779 Some(filter.clone()),
780 delete.returning.clone(),
781 )
782 } else {
783 Err(KitError::Validation(
784 "delete requires either a pk or a filter".into(),
785 ))
786 }
787 }
788 Query::Aggregate(_) | Query::Join(_) => Err(KitError::Validation(
789 "aggregate/join are not mutating statements".into(),
790 )),
791 }
792 }
793
794 fn exec_ctx(&self) -> ExecCtx<'_> {
798 ExecCtx::new(
799 Some(&self.db.schema),
800 |name: &str, conds: Option<&[Condition]>| match conds {
801 Some(c) if !c.is_empty() => self.snapshot_rows_pushed(name, c),
802 _ => self.snapshot_rows(name),
803 },
804 )
805 }
806
807 pub fn commit(self) -> Result<()> {
819 const FLUSH_AFTER_ROWS: usize = 1000;
820 let mut counts: HashMap<&str, usize> = HashMap::new();
821 for op in &self.staged {
822 let table = match op {
823 StagedOp::Insert { table, .. }
824 | StagedOp::Update { table, .. }
825 | StagedOp::Delete { table, .. }
826 | StagedOp::Truncate { table } => table.as_str(),
827 };
828 *counts.entry(table).or_default() += 1;
829 }
830 let tables_to_flush: Vec<&str> = counts
831 .into_iter()
832 .filter(|&(_, n)| n >= FLUSH_AFTER_ROWS)
833 .map(|(table, _)| table)
834 .collect();
835 let db = self.db;
836 self.core.commit().map_err(KitError::from)?;
837 for table in tables_to_flush {
838 let _ = db.flush_table(table);
839 }
840 Ok(())
841 }
842
843 pub fn rollback(self) {
845 self.core.rollback();
846 }
847
848 fn alloc_temp_id(&mut self) -> u64 {
851 let id = self.next_temp_id;
852 self.next_temp_id += 1;
853 id
854 }
855
856 fn require_table(&self, name: &str) -> Result<&KitTable> {
857 self.db
858 .table(name)
859 .ok_or_else(|| KitError::Integrity(format!("table {name} not found")))
860 }
861
862 pub fn all_rows(&self, table: &str) -> Result<Vec<Row>> {
864 self.snapshot_rows(table)
865 }
866
867 fn snapshot_rows(&self, table: &str) -> Result<Vec<Row>> {
868 let t = self.require_table(table)?;
869 let core_rows = self
870 .db
871 .visible_core_rows_at(table, self.core.read_snapshot())?;
872 let mut rows = core_rows
873 .into_iter()
874 .map(|r| core_row_to_json(&r, t))
875 .collect::<Result<Vec<_>>>()?;
876 self.replay_staged_rows(t, &mut rows);
877 Ok(rows)
878 }
879
880 fn snapshot_rows_pushed(&self, table: &str, conditions: &[Condition]) -> Result<Vec<Row>> {
884 let t = self.require_table(table)?;
885 if self.has_staged_for(table) {
886 return Ok(self
887 .snapshot_rows(table)?
888 .into_iter()
889 .filter(|r| row_matches_conditions(t, r, conditions))
890 .collect());
891 }
892 let core_rows = self
893 .db
894 .query_core_rows_at(table, conditions, self.core.read_snapshot())?;
895 core_rows
896 .into_iter()
897 .map(|r| core_row_to_json(&r, t))
898 .collect()
899 }
900
901 fn get_by_pk_internal(&self, table: &str, pk_map: &Map<String, Value>) -> Result<Option<Row>> {
902 let t = self.require_table(table)?;
903 if self.has_staged_for(table) {
904 let rows = self.snapshot_rows(table)?;
905 return Ok(rows.into_iter().find(|r| pk_matches(&r.values, pk_map, t)));
906 }
907 if let Some(conditions) = crate::pushdown::pk_conditions(t, pk_map) {
910 let core_rows =
911 self.db
912 .query_core_rows_at(table, &conditions, self.core.read_snapshot())?;
913 return Ok(core_rows
914 .into_iter()
915 .filter_map(|r| core_row_to_json(&r, t).ok())
916 .find(|r| pk_matches(&r.values, pk_map, t)));
917 }
918 let rows = self.snapshot_rows(table)?;
919 Ok(rows.into_iter().find(|r| pk_matches(&r.values, pk_map, t)))
920 }
921
922 fn internal_rows(&self, table: &str) -> Result<Vec<CoreRow>> {
923 self.db
924 .visible_core_rows_at(table, self.core.read_snapshot())
925 }
926
927 fn check_unique_constraints(
932 &self,
933 table: &KitTable,
934 values: &Map<String, Value>,
935 old_values: Option<&Map<String, Value>>,
936 ) -> Result<()> {
937 if table.unique_constraints.is_empty() {
938 return Ok(());
939 }
940 let owner_pk = encoded_pk_for(table, values);
941 let committed = self.internal_rows(UNIQUE_KEYS)?;
942 for uq in &table.unique_constraints {
943 let Some(key) = unique_key(table, uq, values) else {
944 continue;
945 };
946 if let Some(old) = old_values {
948 if unique_key(table, uq, old).as_deref() == Some(key.as_str()) {
949 continue;
950 }
951 }
952 self.assert_key_free(&committed, table, uq, &key, &owner_pk)?;
953 }
954 Ok(())
955 }
956
957 fn assert_key_free(
958 &self,
959 committed: &[CoreRow],
960 table: &KitTable,
961 uq: &UniqueConstraint,
962 key: &str,
963 owner_pk: &str,
964 ) -> Result<()> {
965 for guard in committed {
966 if internal_bytes(guard, cols::UQ_ENCODED).as_deref() == Some(key) {
967 let g_table = internal_bytes(guard, cols::UQ_OWNER_TABLE).unwrap_or_default();
968 let g_pk = internal_bytes(guard, cols::UQ_OWNER_PK).unwrap_or_default();
969 if g_table != table.name || g_pk != owner_pk {
970 return Err(KitError::Duplicate(format!(
971 "unique constraint {} on {}",
972 uq.name, table.name
973 )));
974 }
975 }
976 }
977 for staged in &self.staged_unique {
978 if staged.encoded_key == key
979 && (staged.owner_table != table.name || staged.owner_pk != owner_pk)
980 {
981 return Err(KitError::Duplicate(format!(
982 "unique constraint {} on {}",
983 uq.name, table.name
984 )));
985 }
986 }
987 Ok(())
988 }
989
990 fn reserve_unique_guards(
993 &mut self,
994 table: &KitTable,
995 values: &Map<String, Value>,
996 old_values: Option<&Map<String, Value>>,
997 ) -> Result<()> {
998 let owner_pk = encoded_pk_for(table, values);
999 for uq in &table.unique_constraints {
1000 let new_key = unique_key(table, uq, values);
1001 let old_key = old_values.and_then(|old| unique_key(table, uq, old));
1002 if new_key == old_key {
1003 continue;
1004 }
1005 if let Some(key) = &new_key {
1006 self.put_unique_guard(&uq.name, key, &table.name, &owner_pk)?;
1007 }
1008 if let Some(key) = &old_key {
1009 self.delete_unique_guard(key)?;
1010 }
1011 }
1012 Ok(())
1013 }
1014
1015 fn put_unique_guard(
1016 &mut self,
1017 constraint: &str,
1018 encoded_key: &str,
1019 owner_table: &str,
1020 owner_pk: &str,
1021 ) -> Result<()> {
1022 let now = iso_now();
1023 self.core
1024 .put(
1025 UNIQUE_KEYS,
1026 vec![
1027 (cols::UQ_ENCODED, CoreValue::Bytes(encoded_key.into())),
1028 (cols::UQ_CONSTRAINT, CoreValue::Bytes(constraint.into())),
1029 (cols::UQ_OWNER_TABLE, CoreValue::Bytes(owner_table.into())),
1030 (cols::UQ_OWNER_PK, CoreValue::Bytes(owner_pk.into())),
1031 (cols::UQ_CREATED, CoreValue::Bytes(now.into_bytes())),
1032 ],
1033 )
1034 .map_err(KitError::from)?;
1035 self.staged_unique.push(StagedUnique {
1036 encoded_key: encoded_key.to_string(),
1037 owner_table: owner_table.to_string(),
1038 owner_pk: owner_pk.to_string(),
1039 });
1040 Ok(())
1041 }
1042
1043 fn delete_unique_guard(&mut self, encoded_key: &str) -> Result<()> {
1044 let committed = self.internal_rows(UNIQUE_KEYS)?;
1045 for guard in &committed {
1046 if internal_bytes(guard, cols::UQ_ENCODED).as_deref() == Some(encoded_key) {
1047 self.core
1048 .delete(UNIQUE_KEYS, guard.row_id)
1049 .map_err(KitError::from)?;
1050 }
1051 }
1052 self.staged_unique.retain(|s| s.encoded_key != encoded_key);
1053 Ok(())
1054 }
1055
1056 fn delete_unique_guards_for_owner(&mut self, table: &KitTable, owner_pk: &str) -> Result<()> {
1058 let constraint_names: HashSet<&str> = table
1059 .unique_constraints
1060 .iter()
1061 .map(|u| u.name.as_str())
1062 .collect();
1063 let committed = self.internal_rows(UNIQUE_KEYS)?;
1064 for guard in &committed {
1065 let g_table = internal_bytes(guard, cols::UQ_OWNER_TABLE).unwrap_or_default();
1066 let g_pk = internal_bytes(guard, cols::UQ_OWNER_PK).unwrap_or_default();
1067 let g_constraint = internal_bytes(guard, cols::UQ_CONSTRAINT).unwrap_or_default();
1068 if g_table == table.name
1069 && g_pk == owner_pk
1070 && (constraint_names.contains(g_constraint.as_str())
1071 || g_constraint == pk_guard_constraint(table))
1072 {
1073 self.core
1074 .delete(UNIQUE_KEYS, guard.row_id)
1075 .map_err(KitError::from)?;
1076 }
1077 }
1078 let owner_pk = owner_pk.to_string();
1079 let name = table.name.clone();
1080 self.staged_unique
1081 .retain(|s| !(s.owner_table == name && s.owner_pk == owner_pk));
1082 Ok(())
1083 }
1084
1085 fn check_pk(
1095 &self,
1096 table: &KitTable,
1097 values: &Map<String, Value>,
1098 pk_explicit: bool,
1099 pk_seen: Option<&mut HashSet<String>>,
1100 ) -> Result<()> {
1101 if table.primary_key.is_empty() || !pk_explicit {
1103 return Ok(());
1104 }
1105
1106 if table.primary_key.len() == 1 {
1107 let duplicate = match pk_seen {
1112 Some(seen) => {
1113 let key = encoded_pk_for(table, values);
1114 if seen.contains(&key) {
1115 true
1116 } else {
1117 seen.insert(key);
1118 false
1119 }
1120 }
1121 None => {
1122 self.parent_exists(&table.name, values)?
1123 || self.staged_row_exists(table, values)
1124 }
1125 };
1126 if duplicate {
1127 return Err(KitError::Duplicate(format!(
1128 "primary key {} on {}",
1129 encoded_pk_for(table, values),
1130 table.name
1131 )));
1132 }
1133 return Ok(());
1134 }
1135
1136 let key = pk_guard_key(table, values);
1139 let owner_pk = encoded_pk_for(table, values);
1140 let committed = self.internal_rows(UNIQUE_KEYS)?;
1141 for guard in &committed {
1142 if internal_bytes(guard, cols::UQ_ENCODED).as_deref() == Some(key.as_str()) {
1143 return Err(KitError::Duplicate(format!(
1144 "primary key {} on {}",
1145 owner_pk, table.name
1146 )));
1147 }
1148 }
1149 for staged in &self.staged_unique {
1150 if staged.encoded_key == key {
1151 return Err(KitError::Duplicate(format!(
1152 "primary key {} on {}",
1153 owner_pk, table.name
1154 )));
1155 }
1156 }
1157 Ok(())
1158 }
1159
1160 fn reserve_pk_guard(
1161 &mut self,
1162 table: &KitTable,
1163 values: &Map<String, Value>,
1164 pk_explicit: bool,
1165 ) -> Result<()> {
1166 if table.primary_key.len() < 2 || !pk_explicit {
1169 return Ok(());
1170 }
1171 let key = pk_guard_key(table, values);
1172 let owner_pk = encoded_pk_for(table, values);
1173 let constraint = pk_guard_constraint(table);
1174 self.put_unique_guard(&constraint, &key, &table.name, &owner_pk)
1175 }
1176
1177 fn check_foreign_keys(&self, table: &KitTable, values: &Map<String, Value>) -> Result<()> {
1180 for fk in &table.foreign_keys {
1181 if fk_values_null(fk, values) {
1182 continue;
1183 }
1184 let parent = self.require_table(&fk.references_table)?;
1185 let parent_pk = parent_pk_value(values, fk, parent)?;
1186 let parent_pk_map = pk_to_map(&parent_pk, parent)?;
1187 if self.parent_exists(&fk.references_table, &parent_pk_map)?
1188 || self.staged_row_exists(parent, &parent_pk_map)
1189 {
1190 continue;
1191 }
1192 return Err(KitError::ForeignKey(format!(
1193 "{} references {}({})",
1194 fk.name,
1195 fk.references_table,
1196 fk.references_columns.join(",")
1197 )));
1198 }
1199 Ok(())
1200 }
1201
1202 fn touch_foreign_key_guards(
1203 &mut self,
1204 table: &KitTable,
1205 values: &Map<String, Value>,
1206 ) -> Result<()> {
1207 for fk in table.foreign_keys.clone() {
1208 if fk_values_null(&fk, values) {
1209 continue;
1210 }
1211 let parent = self.require_table(&fk.references_table)?.clone();
1212 let components = parent_pk_components(values, &fk, &parent);
1213 self.touch_row_guard(&parent.name, &components)?;
1214 }
1215 Ok(())
1216 }
1217
1218 fn parent_exists(&self, table: &str, pk_map: &Map<String, Value>) -> Result<bool> {
1219 let t = self.require_table(table)?;
1220 if self.has_staged_for(table) {
1221 let rows = self.snapshot_rows(table)?;
1222 return Ok(rows.iter().any(|r| pk_matches(&r.values, pk_map, t)));
1223 }
1224 if let Some(conditions) = crate::pushdown::pk_conditions(t, pk_map) {
1227 let core_rows =
1228 self.db
1229 .query_core_rows_at(table, &conditions, self.core.read_snapshot())?;
1230 return Ok(!core_rows.is_empty());
1231 }
1232 let rows = self.snapshot_rows(table)?;
1233 Ok(rows.iter().any(|r| pk_matches(&r.values, pk_map, t)))
1234 }
1235
1236 fn staged_row_exists(&self, table: &KitTable, pk_map: &Map<String, Value>) -> bool {
1242 let target = encode_pk(&pk_components(table, pk_map));
1243 let mut exists = false;
1244 for staged in &self.staged {
1245 match staged {
1246 StagedOp::Insert { table: t, values }
1247 | StagedOp::Update {
1248 table: t, values, ..
1249 } => {
1250 if t == &table.name && pk_matches(values, pk_map, table) {
1251 exists = true;
1252 }
1253 }
1254 StagedOp::Delete { table: t, pk } => {
1255 if t == &table.name && *pk == target {
1256 exists = false;
1257 }
1258 }
1259 StagedOp::Truncate { table: t } => {
1260 if t == &table.name {
1261 exists = false;
1262 }
1263 }
1264 }
1265 }
1266 exists
1267 }
1268
1269 fn touch_row_guard(&mut self, table: &str, pk_components: &[KeyComponent]) -> Result<()> {
1272 let encoded_pk = encode_pk(pk_components);
1273 let guard_key = encode_row_guard_key(table, &encoded_pk);
1274 if !self.touched_guards.insert(guard_key.clone()) {
1275 return Ok(());
1276 }
1277 let mut version = 1i64;
1281 let committed = self.db.query_core_rows_at(
1282 ROW_GUARDS,
1283 &[Condition::Pk(guard_key.as_bytes().to_vec())],
1284 self.core.read_snapshot(),
1285 )?;
1286 for guard in &committed {
1287 if internal_bytes(guard, cols::RG_ENCODED).as_deref() == Some(guard_key.as_str()) {
1288 if let Some(CoreValue::Int64(v)) = guard.columns.get(&cols::RG_VERSION) {
1289 version = v + 1;
1290 }
1291 self.core
1292 .delete(ROW_GUARDS, guard.row_id)
1293 .map_err(KitError::from)?;
1294 }
1295 }
1296 let now = iso_now();
1297 self.core
1298 .put(
1299 ROW_GUARDS,
1300 vec![
1301 (cols::RG_ENCODED, CoreValue::Bytes(guard_key.into_bytes())),
1302 (cols::RG_TABLE, CoreValue::Bytes(table.into())),
1303 (cols::RG_PK, CoreValue::Bytes(encoded_pk.into_bytes())),
1304 (cols::RG_VERSION, CoreValue::Int64(version)),
1305 (cols::RG_UPDATED, CoreValue::Bytes(now.into_bytes())),
1306 ],
1307 )
1308 .map_err(KitError::from)?;
1309 Ok(())
1310 }
1311
1312 fn has_staged_for(&self, table: &str) -> bool {
1313 self.staged.iter().any(|op| match op {
1314 StagedOp::Insert { table: t, .. }
1315 | StagedOp::Update { table: t, .. }
1316 | StagedOp::Delete { table: t, .. }
1317 | StagedOp::Truncate { table: t } => t == table,
1318 })
1319 }
1320
1321 fn replay_staged_rows(&self, table: &KitTable, rows: &mut Vec<Row>) {
1322 for staged in &self.staged {
1323 match staged {
1324 StagedOp::Insert { table: t, values } if t == &table.name => {
1325 let pk = encoded_pk_for(table, values);
1326 rows.retain(|r| encoded_pk_for(table, &r.values) != pk);
1327 rows.push(Row {
1328 row_id: 0,
1329 values: values.clone(),
1330 });
1331 }
1332 StagedOp::Update {
1333 table: t,
1334 old_pk,
1335 row_id,
1336 values,
1337 } if t == &table.name => {
1338 let new_pk = encoded_pk_for(table, values);
1339 rows.retain(|r| {
1340 let pk = encoded_pk_for(table, &r.values);
1341 pk != *old_pk && pk != new_pk
1342 });
1343 rows.push(Row {
1344 row_id: *row_id,
1345 values: values.clone(),
1346 });
1347 }
1348 StagedOp::Delete { table: t, pk } if t == &table.name => {
1349 rows.retain(|r| encoded_pk_for(table, &r.values) != *pk);
1350 }
1351 StagedOp::Truncate { table: t } if t == &table.name => {
1352 rows.clear();
1353 }
1354 _ => {}
1355 }
1356 }
1357 }
1358
1359 fn delete_guards_for(&mut self, table: &KitTable, values: &Map<String, Value>) -> Result<()> {
1361 let owner_pk = encoded_pk_for(table, values);
1362 self.delete_unique_guards_for_owner(table, &owner_pk)
1363 }
1364
1365 fn delete_all_guards_for_table(&mut self, table: &KitTable) -> Result<()> {
1366 for guard in self.internal_rows(UNIQUE_KEYS)? {
1367 let owner_table = internal_bytes(&guard, cols::UQ_OWNER_TABLE).unwrap_or_default();
1368 if owner_table == table.name {
1369 self.core
1370 .delete(UNIQUE_KEYS, guard.row_id)
1371 .map_err(KitError::from)?;
1372 }
1373 }
1374 for guard in self.internal_rows(ROW_GUARDS)? {
1375 let owner_table = internal_bytes(&guard, cols::RG_TABLE).unwrap_or_default();
1376 if owner_table == table.name {
1377 self.core
1378 .delete(ROW_GUARDS, guard.row_id)
1379 .map_err(KitError::from)?;
1380 }
1381 }
1382 self.staged_unique.retain(|s| s.owner_table != table.name);
1383 self.touched_guards
1384 .retain(|key| !key.starts_with(&format!("{}:", table.name)));
1385 Ok(())
1386 }
1387
1388 fn plan_delete(&self, table: &str, row: &Row) -> Result<(DeletePlan, HashMap<String, Row>)> {
1391 let schema = &self.db.schema;
1392 let t = self.require_table(table)?;
1393 let pk_str = encoded_pk_for(t, &row.values);
1394 let row_cache: RefCell<HashMap<String, Row>> = RefCell::new(HashMap::new());
1399 let find_children =
1400 |child_table: &KitTable, fk: &ForeignKey, parent_pk: &str| -> Vec<(String, String)> {
1401 let parent_pk_value = match pk_string_to_value(parent_pk, t) {
1402 Ok(v) => v,
1403 Err(_) => return Vec::new(),
1404 };
1405 let parent_pk_map = match pk_to_map(&parent_pk_value, t) {
1406 Ok(m) => m,
1407 Err(_) => return Vec::new(),
1408 };
1409 let child_rows = match self.snapshot_rows(&child_table.name) {
1410 Ok(r) => r,
1411 Err(_) => return Vec::new(),
1412 };
1413 let mut out = Vec::new();
1414 for child_row in child_rows {
1415 if fk_matches(&child_row.values, fk, &parent_pk_map, t) {
1416 let child_pk = encoded_pk_for(child_table, &child_row.values);
1417 row_cache
1418 .borrow_mut()
1419 .insert(format!("{}:{}", child_table.name, child_pk), child_row);
1420 out.push((child_pk, parent_pk.to_string()));
1421 }
1422 }
1423 out
1424 };
1425 let plan = plan_delete(schema, table, &pk_str, find_children).map_err(KitError::from)?;
1426 Ok((plan, row_cache.into_inner()))
1427 }
1428
1429 fn apply_set_null(
1430 &mut self,
1431 set_null: &mongreldb_kit_core::planner::SetNullUpdate,
1432 child_row: &Row,
1433 ) -> Result<()> {
1434 let child_table = self.require_table(&set_null.table)?.clone();
1435 let mut values = child_row.values.clone();
1436 for col in &set_null.columns {
1437 let col_def = child_table
1438 .column(col)
1439 .ok_or_else(|| KitError::Integrity(format!("set-null column {col} not found")))?;
1440 if !col_def.nullable {
1441 return Err(KitError::Restrict(format!(
1442 "set-null on non-nullable column {col}"
1443 )));
1444 }
1445 values.insert(col.clone(), Value::Null);
1446 }
1447 mongreldb_kit_core::validation::validate_row(&child_table, &values)?;
1449 self.delete_guards_for(&child_table, &child_row.values)?;
1453 let cells = row_to_core_cells(&values, &child_table)?;
1454 self.core
1455 .delete(&set_null.table, RowId(child_row.row_id))
1456 .map_err(KitError::from)?;
1457 self.core
1458 .put(&set_null.table, cells)
1459 .map_err(KitError::from)?;
1460 self.reserve_unique_guards(&child_table, &values, None)?;
1461 self.reserve_pk_guard(&child_table, &values, true)?;
1465 self.staged.push(StagedOp::Update {
1466 table: set_null.table.clone(),
1467 old_pk: encoded_pk_for(&child_table, &child_row.values),
1468 row_id: child_row.row_id,
1469 values: values.clone(),
1470 });
1471 Ok(())
1472 }
1473
1474 fn apply_defaults(&self, row: &mut Map<String, Value>, table: &KitTable) -> Result<()> {
1477 for col in &table.columns {
1478 if row.contains_key(&col.name) && row.get(&col.name) != Some(&Value::Null) {
1479 continue;
1480 }
1481 let Some(default) = &col.default else {
1482 continue;
1483 };
1484 let value = match default {
1485 DefaultKind::Static(v) => v.clone(),
1486 DefaultKind::Now => {
1487 let now = iso_now();
1488 if col.storage_type == ColumnType::Date {
1489 Value::String(now[..10].to_string())
1490 } else {
1491 Value::String(now)
1492 }
1493 }
1494 DefaultKind::Uuid => Value::String(uuid::Uuid::new_v4().to_string()),
1495 DefaultKind::Sequence(name) => {
1496 let start = self.db.allocate_sequence(name, 1)?;
1497 Value::Number(start.into())
1498 }
1499 DefaultKind::CustomName(name) => {
1500 let provider = self.db.default_providers.get(name).ok_or_else(|| {
1501 KitError::Validation(format!("custom default \"{name}\" is not registered"))
1502 })?;
1503 provider()
1504 }
1505 };
1506 row.insert(col.name.clone(), value);
1507 }
1508 Ok(())
1509 }
1510
1511 fn apply_update_defaults(
1519 &self,
1520 merged: &mut Map<String, Value>,
1521 patch_keys: &HashSet<String>,
1522 table: &KitTable,
1523 ) {
1524 let mut now: Option<String> = None;
1525 for col in &table.columns {
1526 if patch_keys.contains(&col.name) {
1527 continue;
1528 }
1529 if col.generated && matches!(col.default, Some(DefaultKind::Now)) {
1530 let stamp = now.get_or_insert_with(iso_now);
1531 let value = if col.storage_type == ColumnType::Date {
1532 Value::String(stamp[..10].to_string())
1533 } else {
1534 Value::String(stamp.clone())
1535 };
1536 merged.insert(col.name.clone(), value);
1537 }
1538 }
1539 }
1540}
1541
1542fn project_returning(row: &Row, columns: &[String]) -> Result<Value> {
1545 let mut out = Map::new();
1546 for c in columns {
1547 out.insert(c.clone(), row.values.get(c).cloned().unwrap_or(Value::Null));
1548 }
1549 Ok(Value::Object(out))
1550}
1551
1552fn pk_values_map(table: &KitTable, values: &Map<String, Value>) -> Map<String, Value> {
1553 let mut out = Map::new();
1554 for name in &table.primary_key {
1555 out.insert(
1556 name.clone(),
1557 values.get(name).cloned().unwrap_or(Value::Null),
1558 );
1559 }
1560 out
1561}
1562
1563fn patch_to_core_cells(
1567 patch: &Map<String, Value>,
1568 table: &KitTable,
1569) -> Result<Vec<(u16, CoreValue)>> {
1570 let mut cells = Vec::new();
1571 for (name, value) in patch {
1572 let Some(col) = table.column(name) else {
1573 continue;
1574 };
1575 cells.push((col.id as u16, json_to_core(value, col.storage_type)?));
1576 }
1577 Ok(cells)
1578}
1579
1580fn select_all(table: &str, filter: Option<Expr>) -> Select {
1581 Select {
1582 table: table.to_string(),
1583 columns: vec![],
1584 filter,
1585 order_by: vec![],
1586 limit: None,
1587 offset: None,
1588 }
1589}
1590
1591fn pk_matches(values: &Map<String, Value>, pk_map: &Map<String, Value>, table: &KitTable) -> bool {
1592 for name in &table.primary_key {
1593 if values.get(name) != pk_map.get(name) {
1594 return false;
1595 }
1596 }
1597 true
1598}
1599
1600fn pk_is_explicit(table: &KitTable, row: &Map<String, Value>) -> bool {
1606 !table.primary_key.is_empty()
1607 && table
1608 .primary_key
1609 .iter()
1610 .all(|name| matches!(row.get(name), Some(v) if !v.is_null()))
1611}
1612
1613fn pk_guard_constraint(table: &KitTable) -> String {
1614 format!("__pk_{}", table.name)
1615}
1616
1617fn pk_guard_key(table: &KitTable, values: &Map<String, Value>) -> String {
1618 encode_unique_key(
1619 KIT_KEY_VERSION,
1620 &pk_guard_constraint(table),
1621 &pk_components(table, values),
1622 )
1623}
1624
1625pub(crate) fn key_component(col: &Column, value: Option<&Value>) -> KeyComponent {
1627 match value {
1628 None | Some(Value::Null) => KeyComponent::Null,
1629 Some(v) => match col.storage_type {
1630 ColumnType::Int8
1631 | ColumnType::Int16
1632 | ColumnType::Int32
1633 | ColumnType::Int64
1634 | ColumnType::TimestampNanos => KeyComponent::Int(v.as_i64().unwrap_or(0)),
1635 _ => KeyComponent::Text(value_to_text(v)),
1636 },
1637 }
1638}
1639
1640fn value_to_text(value: &Value) -> String {
1641 match value {
1642 Value::String(s) => s.clone(),
1643 other => other.to_string(),
1644 }
1645}
1646
1647fn pk_components(table: &KitTable, values: &Map<String, Value>) -> Vec<KeyComponent> {
1648 table
1649 .primary_key
1650 .iter()
1651 .map(|name| {
1652 let col = table.column(name);
1653 match col {
1654 Some(c) => key_component(c, values.get(name)),
1655 None => KeyComponent::Null,
1656 }
1657 })
1658 .collect()
1659}
1660
1661pub(crate) fn encoded_pk_for(table: &KitTable, values: &Map<String, Value>) -> String {
1662 encode_pk(&pk_components(table, values))
1663}
1664
1665pub(crate) fn unique_key(
1666 table: &KitTable,
1667 uq: &UniqueConstraint,
1668 values: &Map<String, Value>,
1669) -> Option<String> {
1670 let mut components = Vec::with_capacity(uq.columns.len());
1671 for name in &uq.columns {
1672 let col = table.column(name)?;
1673 let component = key_component(col, values.get(name));
1674 if component == KeyComponent::Null {
1675 return None; }
1677 components.push(component);
1678 }
1679 Some(encode_unique_key(KIT_KEY_VERSION, &uq.name, &components))
1680}
1681
1682pub(crate) fn fk_values_null(fk: &ForeignKey, values: &Map<String, Value>) -> bool {
1683 fk.columns
1684 .iter()
1685 .any(|c| values.get(c).map(|v| v.is_null()).unwrap_or(true))
1686}
1687
1688pub(crate) fn parent_pk_components(
1689 values: &Map<String, Value>,
1690 fk: &ForeignKey,
1691 parent: &KitTable,
1692) -> Vec<KeyComponent> {
1693 fk.columns
1694 .iter()
1695 .zip(&parent.primary_key)
1696 .map(|(child_col, parent_col)| {
1697 let col = parent.column(parent_col);
1698 match col {
1699 Some(c) => key_component(c, values.get(child_col)),
1700 None => KeyComponent::Null,
1701 }
1702 })
1703 .collect()
1704}
1705
1706fn parent_pk_value(
1707 values: &Map<String, Value>,
1708 fk: &ForeignKey,
1709 parent: &KitTable,
1710) -> Result<Value> {
1711 if parent.primary_key.len() == 1 {
1712 let child_col = fk
1713 .columns
1714 .first()
1715 .ok_or_else(|| KitError::Integrity("fk has no columns".into()))?;
1716 Ok(values.get(child_col).cloned().unwrap_or(Value::Null))
1717 } else {
1718 let mut obj = Map::new();
1719 for (child_col, parent_col) in fk.columns.iter().zip(&parent.primary_key) {
1720 obj.insert(
1721 parent_col.clone(),
1722 values.get(child_col).cloned().unwrap_or(Value::Null),
1723 );
1724 }
1725 Ok(Value::Object(obj))
1726 }
1727}
1728
1729fn fk_matches(
1730 child_values: &Map<String, Value>,
1731 fk: &ForeignKey,
1732 parent_pk_map: &Map<String, Value>,
1733 parent_table: &KitTable,
1734) -> bool {
1735 for (child_col, parent_col) in fk.columns.iter().zip(&parent_table.primary_key) {
1736 if child_values.get(child_col) != parent_pk_map.get(parent_col) {
1737 return false;
1738 }
1739 }
1740 true
1741}
1742
1743fn pk_string_to_value(encoded: &str, table: &KitTable) -> Result<Value> {
1748 let components = decode_pk(encoded);
1749 if components.len() != table.primary_key.len() {
1750 return Err(KitError::Validation(format!(
1751 "encoded pk \"{encoded}\" has {} components, expected {}",
1752 components.len(),
1753 table.primary_key.len()
1754 )));
1755 }
1756 if table.primary_key.len() == 1 {
1757 return Ok(component_to_value(&components[0]));
1758 }
1759 let mut obj = Map::new();
1760 for (name, component) in table.primary_key.iter().zip(&components) {
1761 obj.insert(name.clone(), component_to_value(component));
1762 }
1763 Ok(Value::Object(obj))
1764}
1765
1766fn component_to_value(component: &KeyComponent) -> Value {
1767 match component {
1768 KeyComponent::Null => Value::Null,
1769 KeyComponent::Int(i) => Value::Number((*i).into()),
1770 KeyComponent::Text(s) => Value::String(s.clone()),
1771 }
1772}
1773
1774fn row_matches_conditions(table: &KitTable, row: &Row, conditions: &[Condition]) -> bool {
1775 conditions
1776 .iter()
1777 .all(|condition| row_matches_condition(table, row, condition))
1778}
1779
1780fn row_matches_condition(table: &KitTable, row: &Row, condition: &Condition) -> bool {
1781 match condition {
1782 Condition::Pk(key) => {
1783 let Some(pk_name) = table.primary_key.first() else {
1784 return false;
1785 };
1786 let Some(col) = table.column(pk_name) else {
1787 return false;
1788 };
1789 value_index_key(col, &row.values).as_deref() == Some(key.as_slice())
1790 }
1791 Condition::BitmapEq { column_id, value } => {
1792 let Some(col) = column_by_id(table, *column_id) else {
1793 return false;
1794 };
1795 value_index_key(col, &row.values).as_deref() == Some(value.as_slice())
1796 }
1797 Condition::BitmapIn { column_id, values } => {
1798 let Some(col) = column_by_id(table, *column_id) else {
1799 return false;
1800 };
1801 let Some(key) = value_index_key(col, &row.values) else {
1802 return false;
1803 };
1804 values.iter().any(|value| value == &key)
1805 }
1806 Condition::Range { column_id, lo, hi } => {
1807 let Some(col) = column_by_id(table, *column_id) else {
1808 return false;
1809 };
1810 matches!(
1811 json_to_core(
1812 row.values.get(&col.name).unwrap_or(&Value::Null),
1813 col.storage_type
1814 ),
1815 Ok(CoreValue::Int64(v)) if v >= *lo && v <= *hi
1816 )
1817 }
1818 Condition::RangeF64 {
1819 column_id,
1820 lo,
1821 lo_inclusive,
1822 hi,
1823 hi_inclusive,
1824 } => {
1825 let Some(col) = column_by_id(table, *column_id) else {
1826 return false;
1827 };
1828 let Ok(CoreValue::Float64(v)) = json_to_core(
1829 row.values.get(&col.name).unwrap_or(&Value::Null),
1830 col.storage_type,
1831 ) else {
1832 return false;
1833 };
1834 let ge_lo = if *lo_inclusive { v >= *lo } else { v > *lo };
1835 let le_hi = if *hi_inclusive { v <= *hi } else { v < *hi };
1836 ge_lo && le_hi
1837 }
1838 Condition::FmContains { column_id, pattern } => {
1839 let Some(col) = column_by_id(table, *column_id) else {
1840 return false;
1841 };
1842 if pattern.is_empty() {
1843 return true;
1844 }
1845 match json_to_core(
1846 row.values.get(&col.name).unwrap_or(&Value::Null),
1847 col.storage_type,
1848 ) {
1849 Ok(CoreValue::Bytes(bytes)) => bytes
1850 .windows(pattern.len())
1851 .any(|window| window == pattern.as_slice()),
1852 _ => false,
1853 }
1854 }
1855 Condition::IsNull { column_id } => {
1856 let Some(col) = column_by_id(table, *column_id) else {
1857 return false;
1858 };
1859 matches!(row.values.get(&col.name), None | Some(Value::Null))
1860 }
1861 Condition::IsNotNull { column_id } => {
1862 let Some(col) = column_by_id(table, *column_id) else {
1863 return false;
1864 };
1865 !matches!(row.values.get(&col.name), None | Some(Value::Null))
1866 }
1867 _ => true,
1870 }
1871}
1872
1873fn column_by_id(table: &KitTable, column_id: u16) -> Option<&Column> {
1874 table.columns.iter().find(|col| col.id as u16 == column_id)
1875}
1876
1877fn value_index_key(col: &Column, values: &Map<String, Value>) -> Option<Vec<u8>> {
1878 let value = values.get(&col.name).unwrap_or(&Value::Null);
1879 if value.is_null() {
1880 return None;
1881 }
1882 json_to_core(value, col.storage_type)
1883 .ok()
1884 .map(|value| value.encode_key())
1885}