wasm_dbms/integrity/
insert.rs1use 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
14pub 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 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 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 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}