Skip to main content

jira_core/
field_cache.rs

1use std::collections::HashMap;
2use std::time::{Duration, Instant};
3
4use crate::{client::JiraClient, error::Result, model::field::Field};
5
6const TTL: Duration = Duration::from_secs(300); // 5 minutes
7
8struct CacheEntry {
9    fields: Vec<Field>,
10    fetched_at: Instant,
11}
12
13impl CacheEntry {
14    fn is_fresh(&self) -> bool {
15        self.fetched_at.elapsed() < TTL
16    }
17}
18
19/// In-memory cache for Jira field metadata, keyed by "project:issue_type_id".
20pub struct FieldCache {
21    entries: HashMap<String, CacheEntry>,
22}
23
24impl FieldCache {
25    pub fn new() -> Self {
26        Self {
27            entries: HashMap::new(),
28        }
29    }
30
31    /// Return cached fields or fetch from the API if stale / missing.
32    pub async fn get_or_fetch(
33        &mut self,
34        client: &JiraClient,
35        project_key: &str,
36        issue_type_id: &str,
37    ) -> Result<Vec<Field>> {
38        let key = format!("{project_key}:{issue_type_id}");
39
40        if let Some(entry) = self.entries.get(&key) {
41            if entry.is_fresh() {
42                return Ok(entry.fields.clone());
43            }
44        }
45
46        let fields = client
47            .get_fields_for_issue_type(project_key, issue_type_id)
48            .await?;
49
50        self.entries.insert(
51            key,
52            CacheEntry {
53                fields: fields.clone(),
54                fetched_at: Instant::now(),
55            },
56        );
57
58        Ok(fields)
59    }
60}
61
62impl Default for FieldCache {
63    fn default() -> Self {
64        Self::new()
65    }
66}