junobuild-collections 0.5.2

The types and rules to define collections.
Documentation
use crate::assert::collection::is_system_collection;
use crate::errors::JUNO_COLLECTIONS_ERROR_RESERVED_COLLECTION;
use crate::types::core::CollectionKey;
use crate::types::interface::SetRule;
use crate::types::rules::{Memory, Rule};
use ic_cdk::api::time;
use junobuild_shared::data::version::next_version;
use junobuild_shared::types::state::{Timestamp, Version, Versioned};

impl Rule {
    pub fn mem(&self) -> Memory {
        self.memory.clone().unwrap_or_default()
    }

    pub fn prepare(
        collection: &CollectionKey,
        current_rule: &Option<&Rule>,
        user_rule: &SetRule,
    ) -> Result<Self, String> {
        if is_system_collection(collection) {
            return Self::prepare_sys_rule(collection, current_rule, user_rule);
        }

        Ok(Self::prepare_user_rule(current_rule, user_rule))
    }

    fn initialize_common_fields(current_rule: &Option<&Rule>) -> (Timestamp, Version, Timestamp) {
        let now = time();

        let created_at: Timestamp = match current_rule {
            None => now,
            Some(current_rule) => current_rule.created_at,
        };

        let version = next_version(current_rule);

        let updated_at: Timestamp = now;

        (created_at, version, updated_at)
    }

    fn prepare_user_rule(current_rule: &Option<&Rule>, user_rule: &SetRule) -> Self {
        let (created_at, version, updated_at) = Self::initialize_common_fields(current_rule);

        Rule {
            read: user_rule.read.clone(),
            write: user_rule.write.clone(),
            memory: Some(user_rule.clone().memory.unwrap_or(Memory::Stable)),
            mutable_permissions: Some(user_rule.mutable_permissions.unwrap_or(true)),
            max_size: user_rule.max_size,
            max_capacity: user_rule.max_capacity,
            max_changes_per_user: user_rule.max_changes_per_user,
            created_at,
            updated_at,
            version: Some(version),
            rate_config: user_rule.rate_config.clone(),
        }
    }

    fn prepare_sys_rule(
        collection: &CollectionKey,
        current_rule: &Option<&Rule>,
        user_rule: &SetRule,
    ) -> Result<Rule, String> {
        match current_rule {
            None => Err(format!(
                "{JUNO_COLLECTIONS_ERROR_RESERVED_COLLECTION} ({collection})"
            )),
            Some(current_rule) => {
                let (created_at, version, updated_at) =
                    Self::initialize_common_fields(&Some(current_rule));

                let rule = Rule {
                    read: current_rule.read.clone(),
                    write: current_rule.write.clone(),
                    memory: current_rule.memory.clone(),
                    mutable_permissions: current_rule.mutable_permissions,
                    max_size: current_rule.max_size,
                    max_capacity: current_rule.max_capacity,
                    max_changes_per_user: current_rule.max_changes_per_user,
                    created_at,
                    updated_at,
                    version: Some(version),
                    rate_config: user_rule.rate_config.clone(),
                };

                Ok(rule)
            }
        }
    }

    pub fn switch_rule_memory(current_rule: &Rule) -> Rule {
        let (created_at, version, updated_at) = Self::initialize_common_fields(&Some(current_rule));

        Rule {
            memory: Some(match current_rule.mem() {
                Memory::Heap => Memory::Stable,
                Memory::Stable => Memory::Heap,
            }),
            created_at,
            updated_at,
            version: Some(version),
            ..current_rule.clone()
        }
    }
}

impl From<SetRule> for Rule {
    fn from(rule: SetRule) -> Self {
        let now = time();

        Self {
            read: rule.read,
            write: rule.write,
            memory: rule.memory,
            mutable_permissions: rule.mutable_permissions,
            max_size: rule.max_size,
            max_capacity: rule.max_capacity,
            max_changes_per_user: rule.max_changes_per_user,
            created_at: now,
            updated_at: now,
            version: rule.version,
            rate_config: rule.rate_config,
        }
    }
}

impl Versioned for &Rule {
    fn version(&self) -> Option<Version> {
        self.version
    }
}