mod batch;
mod shared;
mod structural;
mod typed;
use crate::{
db::{Db, commit::CommitSchemaFingerprint, data::PersistedRow, schema::SchemaInfo},
error::InternalError,
sanitize::{SanitizeWriteContext, SanitizeWriteMode},
traits::{EntityCreateInput, EntityValue},
types::Timestamp,
};
use candid::CandidType;
use serde::Deserialize;
#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize)]
enum SaveMode {
#[default]
Insert,
Replace,
Update,
}
#[derive(Clone, Copy)]
pub(in crate::db) struct SaveExecutor<E: PersistedRow + EntityValue> {
pub(in crate::db::executor::mutation) db: Db<E::Canister>,
}
#[derive(Clone, Copy)]
enum SaveRule {
RequireAbsent,
RequirePresent,
AllowAny,
}
impl SaveRule {
const fn from_mode(mode: SaveMode) -> Self {
match mode {
SaveMode::Insert => Self::RequireAbsent,
SaveMode::Update => Self::RequirePresent,
SaveMode::Replace => Self::AllowAny,
}
}
}
#[derive(Clone, Copy)]
struct SavePreflightInputs<'a> {
schema: &'a SchemaInfo,
schema_fingerprint: CommitSchemaFingerprint,
validate_relations: bool,
write_context: SanitizeWriteContext,
authored_create_slots: Option<&'a [usize]>,
}
#[derive(Clone, Copy)]
pub enum MutationMode {
Insert,
Replace,
Update,
}
impl MutationMode {
const fn save_rule(self) -> SaveRule {
match self {
Self::Insert => SaveRule::RequireAbsent,
Self::Replace => SaveRule::AllowAny,
Self::Update => SaveRule::RequirePresent,
}
}
const fn sanitize_write_mode(self) -> SanitizeWriteMode {
match self {
Self::Insert => SanitizeWriteMode::Insert,
Self::Replace => SanitizeWriteMode::Replace,
Self::Update => SanitizeWriteMode::Update,
}
}
}
impl<E: PersistedRow + EntityValue> SaveExecutor<E> {
const fn save_write_context(mode: SaveMode, now: Timestamp) -> SanitizeWriteContext {
let mode = match mode {
SaveMode::Insert => SanitizeWriteMode::Insert,
SaveMode::Replace => SanitizeWriteMode::Replace,
SaveMode::Update => SanitizeWriteMode::Update,
};
SanitizeWriteContext::new(mode, now)
}
#[must_use]
pub(in crate::db) const fn new(db: Db<E::Canister>, _debug: bool) -> Self {
Self { db }
}
pub(crate) fn insert(&self, entity: E) -> Result<E, InternalError> {
self.save_entity(SaveMode::Insert, entity)
}
pub(crate) fn create<I>(&self, input: I) -> Result<E, InternalError>
where
I: EntityCreateInput<Entity = E>,
{
self.save_typed_create_input(input)
}
pub(crate) fn update(&self, entity: E) -> Result<E, InternalError> {
self.save_entity(SaveMode::Update, entity)
}
pub(crate) fn replace(&self, entity: E) -> Result<E, InternalError> {
self.save_entity(SaveMode::Replace, entity)
}
}