Skip to main content

flippico_cache/
lib.rs

1use crate::types::provider::{Provider, ProviderEither};
2
3pub mod core;
4pub mod providers;
5pub mod types;
6
7pub struct Cache {
8    provider: ProviderEither,
9}
10
11impl Cache {
12    pub fn new() -> Self {
13        Self {
14            provider: Provider::Redis.create_provider(),
15        }
16    }
17
18    pub fn pub_sub(
19        self,
20    ) -> Result<
21        Box<
22            dyn types::provider::ConnectablePubSubProvider<
23                    Channels = types::channels::SubscriptionChannel,
24                > + Send
25                + Sync,
26        >,
27        &'static str,
28    > {
29        self.provider.pub_sub()
30    }
31
32    pub fn fifo(
33        self,
34    ) -> Result<Box<dyn types::provider::ConnectableFifoProvider + Send + Sync>, &'static str> {
35        self.provider.fifo()
36    }
37
38    pub fn cache(
39        self,
40    ) -> Result<Box<dyn types::provider::ConnectableCacheProvider + Send + Sync>, &'static str>
41    {
42        self.provider.cache()
43    }
44
45    pub fn sorted_set(
46        self,
47    ) -> Result<Box<dyn types::provider::ConnectableSortedSetProvider + Send + Sync>, &'static str>
48    {
49        self.provider.sorted_set()
50    }
51
52    /// Build the BullMQ capability.
53    ///
54    /// This builder is `async` while the other four are not. That is
55    /// deliberate: BullMQ's job lifecycle cannot be driven from a blocking
56    /// call. See the design spec, section 4.1.
57    #[cfg(feature = "bullmq")]
58    pub async fn bullmq(
59        self,
60    ) -> Result<Box<dyn types::bullmq::BullMqProvider + Send + Sync>, types::queues::BullMqError>
61    {
62        self.provider.bullmq().await
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use crate::types::channels::{
69        CacheSpace, ChannelMessage, ListChannel, ListMessage, SubscriptionChannel,
70    };
71    use std::sync::Arc;
72
73    use super::*;
74
75    fn get_test_msg() -> ChannelMessage {
76        ChannelMessage {
77            channel: SubscriptionChannel::BajkomatApi,
78            meta: None,
79            body: None,
80        }
81    }
82
83    fn get_test_list_msg() -> ListMessage {
84        ListMessage {
85            meta: None,
86            body: serde_json::json!({"body": "test"}).into(),
87        }
88    }
89
90    #[tokio::test]
91    async fn fifo_test() {
92        let cache = Arc::new(Cache::new().fifo().unwrap());
93        let cache_clone = cache.clone();
94        cache.push(
95            ListChannel::BajkomatApi,
96            "job_key",
97            serde_json::json!({"body": "test"}),
98        );
99        let fifo_value = cache_clone.pop(ListChannel::BajkomatApi, "job_key");
100        let msg2 = get_test_list_msg();
101        assert_eq!(fifo_value.unwrap(), msg2);
102    }
103
104    #[test]
105    fn publish_test() {
106        let mut cache = Cache::new().pub_sub().unwrap();
107        cache.publish(SubscriptionChannel::BajkomatApi, get_test_msg());
108    }
109
110    #[test]
111    fn cache_test_set() {
112        let cache = Cache::new().cache().unwrap();
113        let test_data = serde_json::json!({"data": "test"});
114        cache.set(CacheSpace::Shopify, "SomeKey", test_data, None);
115        let value = cache.get(CacheSpace::Shopify, "SomeKey", None);
116        assert_eq!("{\"meta\":null,\"value\":{\"data\":\"test\"}}", value);
117    }
118
119    #[test]
120    fn cache_test_del() {
121        let cache = Cache::new().cache().unwrap();
122        let test_data = serde_json::json!({"data": "test"});
123        cache.set(CacheSpace::Shopify, "SomeKey", test_data, None);
124        let value = cache.get(CacheSpace::Shopify, "SomeKey", None);
125        assert_eq!("{\"meta\":null,\"value\":{\"data\":\"test\"}}", value);
126        cache.delete(CacheSpace::Shopify, "SomeKey", None);
127        let value = cache.get(CacheSpace::Shopify, "SomeKey", None);
128        assert_eq!("", value);
129    }
130
131    // #[tokio::test]
132    // async fn subscribe_test() {
133    //     let subscriber_cache = Cache::new().pub_sub().unwrap();
134    //     let mut publisher_cache = Cache::new().pub_sub().unwrap();
135
136    //     // Use a channel to signal when the callback is executed
137    //     let (tx, rx) = tokio::sync::oneshot::channel();
138    //     let tx = std::sync::Arc::new(std::sync::Mutex::new(Some(tx)));
139
140    //     let sub_clbk = move |msg: ChannelMessage| {
141    //         let tx_clone = tx.clone();
142    //         Box::pin(async move {
143    //             let msg2 = get_test_msg();
144    //             assert_eq!(msg, msg2);
145    //             if let Ok(mut tx_guard) = tx_clone.lock() {
146    //                 if let Some(sender) = tx_guard.take() {
147    //                     let _ = sender.send(());
148    //                 }
149    //             }
150    //         }) as Pin<Box<dyn std::future::Future<Output = ()> + Send + Sync>>
151    //     };
152
153    //     // Start the subscription task by moving the cache into the spawned task
154    //     let _handle = tokio::spawn(async move {
155    //         let subscription_task =
156    //             subscriber_cache.subscribe(Box::new(sub_clbk), SubscriptionChannel::BajkomatApi);
157    //         let _ = subscription_task.await;
158    //     });
159
160    //     // Wait a moment for subscription to be established
161    //     tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
162
163    //     // Publish the message
164    //     publisher_cache.publish(SubscriptionChannel::BajkomatApi, get_test_msg());
165
166    //     // Wait for the callback to be executed with timeout
167    //     let timeout_result = tokio::time::timeout(tokio::time::Duration::from_secs(10), rx).await;
168    //     match timeout_result {
169    //         Ok(Ok(())) => {
170    //             // Test passed
171    //         }
172    //         Ok(Err(e)) => {
173    //             panic!("Callback channel error: {:?}", e);
174    //         }
175    //         Err(_error) => {
176    //             // Check if Redis is available - if not, skip the test
177    //             println!("Test timed out - Redis may not be available, skipping test");
178    //             return;
179    //         }
180    //     }
181    // }
182}