wasm_dbms/integrity/
update.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 UpdateIntegrityValidator<'a, T, M, A = AccessControlList>
19where
20 T: TableSchema,
21 M: MemoryProvider,
22 A: AccessControl,
23{
24 database: &'a WasmDbmsDatabase<'a, M, A>,
25 old_pk: Value,
27 _marker: std::marker::PhantomData<T>,
28}
29
30impl<'a, T, M, A> UpdateIntegrityValidator<'a, T, M, A>
31where
32 T: TableSchema,
33 M: MemoryProvider,
34 A: AccessControl,
35{
36 pub fn new(dbms: &'a WasmDbmsDatabase<'a, M, A>, old_pk: Value) -> Self {
38 Self {
39 database: dbms,
40 old_pk,
41 _marker: std::marker::PhantomData,
42 }
43 }
44}
45
46impl<T, M, A> UpdateIntegrityValidator<'_, T, M, A>
47where
48 T: TableSchema,
49 M: MemoryProvider,
50 A: AccessControl,
51{
52 pub fn validate(&self, record_values: &[(ColumnDef, Value)]) -> DbmsResult<()> {
54 for (col, value) in record_values {
55 common::check_column_validate::<T>(col, value)?;
56 }
57 self.check_primary_key_conflict(record_values)?;
58 common::check_foreign_keys::<T>(self.database, record_values)?;
59 common::check_non_nullable_fields::<T>(record_values)?;
60
61 Ok(())
62 }
63
64 fn check_primary_key_conflict(&self, record_values: &[(ColumnDef, Value)]) -> DbmsResult<()> {
66 let pk_name = T::primary_key();
67 let new_pk = record_values
68 .iter()
69 .find(|(col_def, _)| col_def.name == pk_name)
70 .map(|(_, value)| value.clone())
71 .ok_or(DbmsError::Query(QueryError::MissingNonNullableField(
72 pk_name.to_string(),
73 )))?;
74
75 let query = Query::builder()
76 .field(pk_name)
77 .and_where(Filter::Eq(pk_name.to_string(), new_pk.clone()))
78 .build();
79
80 let res = self.database.select::<T>(query)?;
81 match res.len() {
82 0 => Ok(()),
83 1 => {
84 if new_pk == self.old_pk {
85 Ok(())
86 } else {
87 Err(DbmsError::Query(QueryError::PrimaryKeyConflict))
88 }
89 }
90 _ => Err(DbmsError::Query(QueryError::PrimaryKeyConflict)),
91 }
92 }
93}