nestrs-cache-manager 0.1.0

Rust port of @nestjs/cache-manager backed by moka.
Documentation
//! Port map for upstream `lib/cache.module.ts`.

use serde::{Deserialize, Serialize};

use crate::cache_constants::CACHE_MANAGER;
use crate::cache_providers::createCacheManager;
use crate::interfaces::{CacheModuleAsyncOptions, CacheModuleOptions, CacheOptions};

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ProviderKind {
    Class,
    Value,
    Factory,
    Existing,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Provider {
    pub provide: String,
    pub kind: ProviderKind,
    pub use_value: Option<serde_json::Value>,
    pub inject: Vec<String>,
    pub use_existing: Option<String>,
}

impl Provider {
    pub fn class(provide: impl Into<String>) -> Self {
        Self {
            provide: provide.into(),
            kind: ProviderKind::Class,
            use_value: None,
            inject: Vec::new(),
            use_existing: None,
        }
    }

    pub fn value<T: Serialize>(provide: impl Into<String>, value: T) -> Self {
        Self {
            provide: provide.into(),
            kind: ProviderKind::Value,
            use_value: serde_json::to_value(value).ok(),
            inject: Vec::new(),
            use_existing: None,
        }
    }

    pub fn factory(provide: impl Into<String>, inject: Vec<String>) -> Self {
        Self {
            provide: provide.into(),
            kind: ProviderKind::Factory,
            use_value: None,
            inject,
            use_existing: None,
        }
    }

    pub fn existing(provide: impl Into<String>, use_existing: impl Into<String>) -> Self {
        Self {
            provide: provide.into(),
            kind: ProviderKind::Existing,
            use_value: None,
            inject: Vec::new(),
            use_existing: Some(use_existing.into()),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct DynamicModule {
    pub global: bool,
    pub module: String,
    pub imports: Vec<String>,
    pub providers: Vec<Provider>,
    pub exports: Vec<String>,
}

impl DynamicModule {
    pub fn cache_options(&self) -> Option<CacheOptions> {
        self.providers
            .iter()
            .find(|provider| provider.provide == crate::cache_constants::CACHE_MODULE_OPTIONS)
            .and_then(|provider| provider.use_value.as_ref())
            .and_then(|value| serde_json::from_value(value.clone()).ok())
    }
}

pub struct Cache;

pub struct CacheModule;

impl CacheModule {
    pub fn register(options: CacheModuleOptions) -> DynamicModule {
        DynamicModule {
            global: options.isGlobal.unwrap_or(false),
            module: "CacheModule".to_string(),
            imports: Vec::new(),
            providers: vec![
                Provider::value(
                    crate::cache_constants::CACHE_MODULE_OPTIONS,
                    &options.cache_options,
                ),
                createCacheManager(),
                Provider::existing("Cache", CACHE_MANAGER),
            ],
            exports: vec![CACHE_MANAGER.to_string(), "Cache".to_string()],
        }
    }

    pub fn registerAsync(options: CacheModuleAsyncOptions) -> DynamicModule {
        let mut providers = Self::createAsyncProviders(options.clone());
        providers.push(createCacheManager());
        providers.push(Provider::existing("Cache", CACHE_MANAGER));
        providers.extend(options.extraProviders.iter().map(Provider::class));

        DynamicModule {
            global: options.isGlobal.unwrap_or(false),
            module: "CacheModule".to_string(),
            imports: options.imports,
            providers,
            exports: vec![CACHE_MANAGER.to_string(), "Cache".to_string()],
        }
    }

    pub fn register_async(options: CacheModuleAsyncOptions) -> DynamicModule {
        Self::registerAsync(options)
    }

    fn createAsyncProviders(options: CacheModuleAsyncOptions) -> Vec<Provider> {
        if options.useExisting.is_some() || options.useFactory {
            return vec![Self::createAsyncOptionsProvider(options)];
        }

        let use_class = options.useClass.clone().unwrap_or_default();
        vec![
            Self::createAsyncOptionsProvider(options),
            Provider::class(use_class),
        ]
    }

    fn createAsyncOptionsProvider(options: CacheModuleAsyncOptions) -> Provider {
        if options.useFactory {
            return Provider::factory(crate::cache_constants::CACHE_MODULE_OPTIONS, options.inject);
        }

        Provider::factory(
            crate::cache_constants::CACHE_MODULE_OPTIONS,
            vec![
                options
                    .useExisting
                    .unwrap_or_else(|| options.useClass.unwrap_or_default()),
            ],
        )
    }
}