1use async_trait::async_trait;
8use serde::{Serialize, de::DeserializeOwned};
9
10use crate::Result;
11use crate::cache::Cache;
12use crate::job_queue::JobQueue;
13use crate::publisher::Publisher;
14use crate::types::Priority;
15
16#[async_trait]
18pub trait CacheExt: Cache {
19 async fn set_typed<T: Serialize + Send + Sync>(
21 &self,
22 key: &str,
23 value: &T,
24 ttl_seconds: Option<i32>,
25 ) -> Result<()> {
26 let json = serde_json::to_value(value)?;
27 self.set(key, &json, ttl_seconds).await
28 }
29
30 async fn get_typed<T: DeserializeOwned>(&self, key: &str) -> Result<Option<T>> {
32 match self.get(key).await? {
33 Some(value) => Ok(Some(serde_json::from_value(value)?)),
34 None => Ok(None),
35 }
36 }
37
38 async fn mget_typed<T: DeserializeOwned>(
40 &self,
41 keys: &[&str],
42 ) -> Result<Vec<(String, Option<T>)>> {
43 let raw = self.mget(keys).await?;
44 let mut results = Vec::with_capacity(raw.len());
45 for (key, value) in raw {
46 let parsed = match value {
47 Some(v) => Some(serde_json::from_value(v)?),
48 None => None,
49 };
50 results.push((key, parsed));
51 }
52 Ok(results)
53 }
54}
55
56impl<T: Cache + ?Sized> CacheExt for T {}
58
59#[async_trait]
61pub trait JobQueueExt: JobQueue {
62 async fn push_typed<T: Serialize + Send + Sync>(
64 &self,
65 queue_name: &str,
66 payload: &T,
67 priority: Priority,
68 ) -> Result<String> {
69 let json = serde_json::to_value(payload)?;
70 self.push(queue_name, &json, priority).await
71 }
72
73 async fn push_typed_with_options<T: Serialize + Send + Sync>(
75 &self,
76 queue_name: &str,
77 payload: &T,
78 priority: Priority,
79 delay_seconds: i32,
80 max_attempts: i32,
81 ) -> Result<String> {
82 let json = serde_json::to_value(payload)?;
83 self.push_with_options(queue_name, &json, priority, delay_seconds, max_attempts)
84 .await
85 }
86
87 async fn pop_typed<T: DeserializeOwned>(
89 &self,
90 queue_name: &str,
91 lock_duration_seconds: i32,
92 ) -> Result<Option<crate::types::TypedJob<T>>> {
93 match self.pop(queue_name, lock_duration_seconds).await? {
94 Some(job) => {
95 let payload: T = serde_json::from_value(job.payload)?;
96 Ok(Some(crate::types::TypedJob {
97 id: job.id,
98 queue_name: job.queue_name,
99 payload,
100 attempts: job.attempts,
101 max_attempts: job.max_attempts,
102 created_at: job.created_at,
103 }))
104 }
105 None => Ok(None),
106 }
107 }
108}
109
110impl<T: JobQueue + ?Sized> JobQueueExt for T {}
112
113#[async_trait]
115pub trait PublisherExt: Publisher {
116 async fn publish_typed<T: Serialize + Send + Sync>(
118 &self,
119 channel: &str,
120 payload: &T,
121 ) -> Result<()> {
122 let json = serde_json::to_value(payload)?;
123 self.publish(channel, &json).await
124 }
125
126 async fn publish_multi_typed<T: Serialize + Send + Sync>(
128 &self,
129 channels: &[&str],
130 payload: &T,
131 ) -> Result<()> {
132 let json = serde_json::to_value(payload)?;
133 self.publish_multi(channels, &json).await
134 }
135}
136
137impl<T: Publisher + ?Sized> PublisherExt for T {}