Skip to main content

wasm_dbms/integrity/
insert.rs

1// Rust guideline compliant 2026-03-01
2// X-WHERE-CLAUSE, M-CANONICAL-DOCS
3
4//! Integrity validator for insert operations.
5
6use wasm_dbms_api::prelude::{
7    ColumnDef, Database as _, DbmsError, DbmsResult, Filter, Query, QueryError, TableSchema, Value,
8};
9use wasm_dbms_memory::prelude::{AccessControl, AccessControlList, MemoryProvider};
10
11use super::common;
12use crate::database::WasmDbmsDatabase;
13
14/// Integrity validator for insert operations.
15pub struct InsertIntegrityValidator<'a, T, M, A = AccessControlList>
16where
17    T: TableSchema,
18    M: MemoryProvider,
19    A: AccessControl,
20{
21    database: &'a WasmDbmsDatabase<'a, M, A>,
22    _marker: std::marker::PhantomData<T>,
23}
24
25impl<'a, T, M, A> InsertIntegrityValidator<'a, T, M, A>
26where
27    T: TableSchema,
28    M: MemoryProvider,
29    A: AccessControl,
30{
31    /// Creates a new insert integrity validator.
32    pub fn new(dbms: &'a WasmDbmsDatabase<'a, M, A>) -> Self {
33        Self {
34            database: dbms,
35            _marker: std::marker::PhantomData,
36        }
37    }
38}
39
40impl<T, M, A> InsertIntegrityValidator<'_, T, M, A>
41where
42    T: TableSchema,
43    M: MemoryProvider,
44    A: AccessControl,
45{
46    /// Verifies whether the given insert record is valid.
47    pub fn validate(&self, record_values: &[(ColumnDef, Value)]) -> DbmsResult<()> {
48        for (col, value) in record_values {
49            common::check_column_validate::<T>(col, value)?;
50        }
51        self.check_primary_key_conflict(record_values)?;
52        common::check_foreign_keys::<T>(self.database, record_values)?;
53        common::check_non_nullable_fields::<T>(record_values)?;
54
55        Ok(())
56    }
57
58    /// Checks for primary key conflicts.
59    fn check_primary_key_conflict(&self, record_values: &[(ColumnDef, Value)]) -> DbmsResult<()> {
60        let pk_name = T::primary_key();
61        let pk = record_values
62            .iter()
63            .find(|(col_def, _)| col_def.name == pk_name)
64            .map(|(_, value)| value.clone())
65            .ok_or(DbmsError::Query(QueryError::MissingNonNullableField(
66                pk_name.to_string(),
67            )))?;
68
69        let query: Query = Query::builder()
70            .field(pk_name)
71            .and_where(Filter::Eq(pk_name.to_string(), pk))
72            .build();
73
74        let res = self.database.select::<T>(query)?;
75        if res.is_empty() {
76            Ok(())
77        } else {
78            Err(DbmsError::Query(QueryError::PrimaryKeyConflict))
79        }
80    }
81}