/ src / backend / src / item / spec.rs
spec.rs
  1  use candid::{CandidType, Deserialize};
  2  use interface::item::spec::SpecValue;
  3  use std::collections::BTreeMap;
  4  
  5  type SpecUpperCategoryKey = u8;
  6  #[derive(CandidType, Deserialize, Debug, Clone)]
  7  pub struct SpecUpperCategory {
  8      name: String,
  9      lower_category_map: BTreeMap<SpecLowerCategoryKey, SpecLowerCategory>,
 10  }
 11  
 12  impl SpecUpperCategory {
 13      pub fn new_str(name: &str, lower_categories: Vec<SpecLowerCategory>) -> Self {
 14          let lower_category_map = lower_categories
 15              .into_iter()
 16              .enumerate()
 17              .map(|(i, v)| (i as u8, v))
 18              .collect();
 19  
 20          Self {
 21              name: name.to_string(),
 22              lower_category_map,
 23          }
 24      }
 25  
 26      pub fn get_lower_category(&self, key: SpecLowerCategoryKey) -> Option<&SpecLowerCategory> {
 27          self.lower_category_map.get(&key)
 28      }
 29  }
 30  
 31  type SpecLowerCategoryKey = u8;
 32  #[derive(CandidType, Deserialize, Debug, Clone)]
 33  pub struct SpecLowerCategory {
 34      name: String,
 35      value_map: BTreeMap<SpecValueKey, SpecValue>,
 36  }
 37  
 38  impl SpecLowerCategory {
 39      pub fn new_str(name: &str, values: Vec<Vec<&str>>) -> Self {
 40          let value_map = values
 41              .into_iter()
 42              .enumerate()
 43              .map(|(i, v)| (i as u8, v.into_iter().map(|v| v.to_string()).collect()))
 44              .collect();
 45  
 46          Self {
 47              name: name.to_string(),
 48              value_map,
 49          }
 50      }
 51  
 52      pub fn get_value(&self, key: &SpecValueKey) -> Option<&interface::item::spec::SpecValue> {
 53          self.value_map.get(key)
 54      }
 55  }
 56  
 57  type SpecValueKey = u8;
 58  
 59  pub type SpecIndexKey = u8;
 60  
 61  #[derive(CandidType, Deserialize, Debug, Clone)]
 62  pub struct SpecKey {
 63      upper_category_key: SpecUpperCategoryKey,
 64      lower_category_vec: Vec<SpecKeyLowerCategory>,
 65  }
 66  
 67  impl SpecKey {
 68      pub fn new(
 69          upper_category_key: SpecUpperCategoryKey,
 70          lower_category_vec: Vec<(u8, u8)>,
 71      ) -> Self {
 72          let lower_category_vec = lower_category_vec
 73              .into_iter()
 74              .map(|(lower_category_key, value_key)| {
 75                  SpecKeyLowerCategory::new(lower_category_key, value_key)
 76              })
 77              .collect();
 78  
 79          Self {
 80              upper_category_key,
 81              lower_category_vec,
 82          }
 83      }
 84  }
 85  
 86  #[derive(CandidType, Deserialize, Debug, Clone)]
 87  pub struct SpecKeyLowerCategory {
 88      lower_category_key: SpecLowerCategoryKey,
 89      value_key: SpecValueKey,
 90  }
 91  
 92  impl SpecKeyLowerCategory {
 93      pub fn new(lower_category_key: SpecLowerCategoryKey, value_key: SpecValueKey) -> Self {
 94          Self {
 95              lower_category_key,
 96              value_key,
 97          }
 98      }
 99  }
100  
101  #[derive(CandidType, Deserialize, Debug, Clone)]
102  pub struct ItemSpecs {
103      // Actual data of specs
104      pub map: BTreeMap<SpecUpperCategoryKey, SpecUpperCategory>,
105      // Mapping of combination of specs
106      pub index_map: BTreeMap<SpecIndexKey, SpecKey>,
107  }
108  
109  impl ItemSpecs {
110      pub fn new_str(
111          data: Vec<(&str, Vec<(&str, Vec<Vec<&str>>)>)>,
112          index: Vec<(u8, Vec<(u8, u8)>)>,
113      ) -> Self {
114          let map = data
115              .into_iter()
116              .enumerate()
117              .map(|(i, v)| {
118                  (
119                      i as u8,
120                      SpecUpperCategory::new_str(
121                          v.0,
122                          v.1.into_iter()
123                              .map(|v| SpecLowerCategory::new_str(v.0, v.1))
124                              .collect(),
125                      ),
126                  )
127              })
128              .collect();
129  
130          let index_map = index
131              .into_iter()
132              .enumerate()
133              .map(|(i, v)| (i as u8, SpecKey::new(v.0, v.1)))
134              .collect();
135  
136          Self { map, index_map }
137      }
138  
139      pub fn get_specs(&self, keys: &Vec<SpecIndexKey>) -> Option<interface::item::spec::SpecResult> {
140          let mut result = Vec::new();
141  
142          for key in keys {
143              let mut lower_category_vec = Vec::new();
144              let spec_key = self.get_spec_key(key)?;
145  
146              let upper_category = self.get_upper_category(spec_key.upper_category_key)?;
147              for spec_key_lower_category in &spec_key.lower_category_vec {
148                  let lower_category = upper_category
149                      .get_lower_category(spec_key_lower_category.lower_category_key)?;
150                  let value = lower_category.get_value(&spec_key_lower_category.value_key)?;
151                  lower_category_vec.push(interface::item::spec::SpecResultLowerCategory {
152                      lower_category_name: lower_category.name.clone(),
153                      value: value.clone(),
154                  });
155              }
156  
157              result.push(interface::item::spec::SpecResultUpperCategory {
158                  upper_category_name: upper_category.name.clone(),
159                  lower_category_vec,
160              });
161          }
162  
163          Some(result)
164      }
165  
166      fn get_spec_key(&self, key: &SpecIndexKey) -> Option<&SpecKey> {
167          self.index_map.get(key)
168      }
169  
170      fn get_upper_category(&self, key: SpecUpperCategoryKey) -> Option<&SpecUpperCategory> {
171          self.map.get(&key)
172      }
173  }