/ src / item / spec.rs
spec.rs
  1  use candid::{CandidType, Deserialize};
  2  use shared::item::spec::SpecValue;
  3  use std::collections::BTreeMap;
  4  
  5  type SpecCategoryKey = u8;
  6  #[derive(CandidType, Deserialize, Debug, Clone)]
  7  pub struct SpecCategory {
  8      name: String,
  9      label_map: BTreeMap<SpecLabelKey, SpecLabel>,
 10  }
 11  
 12  impl SpecCategory {
 13      pub fn builder(name: &str) -> SpecCategoryBuilder {
 14          SpecCategoryBuilder::new(name)
 15      }
 16  
 17      pub fn get_label(&self, key: SpecLabelKey) -> Option<&SpecLabel> {
 18          self.label_map.get(&key)
 19      }
 20  }
 21  
 22  pub struct SpecCategoryBuilder {
 23      name: String,
 24      label_map: BTreeMap<SpecLabelKey, SpecLabel>,
 25  }
 26  
 27  impl SpecCategoryBuilder {
 28      pub fn new(name: &str) -> Self {
 29          Self {
 30              name: name.to_string(),
 31              label_map: BTreeMap::new(),
 32          }
 33      }
 34  
 35      pub fn label(mut self, key: SpecLabelKey, label: SpecLabel) -> Self {
 36          self.label_map.insert(key, label);
 37          self
 38      }
 39  
 40      pub fn build(self) -> SpecCategory {
 41          SpecCategory {
 42              name: self.name,
 43              label_map: self.label_map,
 44          }
 45      }
 46  }
 47  
 48  type SpecLabelKey = u8;
 49  #[derive(CandidType, Deserialize, Debug, Clone)]
 50  pub struct SpecLabel {
 51      name: String,
 52      value_map: BTreeMap<SpecValueKey, SpecValue>,
 53  }
 54  
 55  impl SpecLabel {
 56      pub fn builder(name: &str) -> SpecLabelBuilder {
 57          SpecLabelBuilder::new(name)
 58      }
 59  
 60      pub fn get_value(&self, key: &SpecValueKey) -> Option<&shared::item::spec::SpecValue> {
 61          self.value_map.get(key)
 62      }
 63  }
 64  
 65  pub struct SpecLabelBuilder {
 66      name: String,
 67      value_map: BTreeMap<SpecValueKey, SpecValue>,
 68  }
 69  
 70  impl SpecLabelBuilder {
 71      pub fn new(name: &str) -> Self {
 72          Self {
 73              name: name.to_string(),
 74              value_map: BTreeMap::new(),
 75          }
 76      }
 77  
 78      pub fn value(mut self, key: SpecValueKey, value: Vec<&str>) -> Self {
 79          let value = value.iter().map(|v| v.to_string()).collect();
 80  
 81          self.value_map.insert(key, value);
 82          self
 83      }
 84  
 85      pub fn build(self) -> SpecLabel {
 86          SpecLabel {
 87              name: self.name,
 88              value_map: self.value_map,
 89          }
 90      }
 91  }
 92  
 93  type SpecValueKey = u8;
 94  
 95  pub type SpecIndexKey = u8;
 96  
 97  #[derive(CandidType, Deserialize, Debug, Clone)]
 98  pub struct SpecKey {
 99      category_key: SpecCategoryKey,
100      label_vec: Vec<SpecKeyLabel>,
101  }
102  
103  impl SpecKey {
104      pub fn builder(category_key: SpecCategoryKey) -> SpecKeyBuilder {
105          SpecKeyBuilder::new(category_key)
106      }
107  }
108  
109  pub struct SpecKeyBuilder {
110      category_key: SpecCategoryKey,
111      label_vec: Vec<SpecKeyLabel>,
112  }
113  
114  impl SpecKeyBuilder {
115      pub fn new(category_key: SpecCategoryKey) -> Self {
116          Self {
117              category_key,
118              label_vec: Vec::new(),
119          }
120      }
121  
122      pub fn label(mut self, label_key: SpecLabelKey, value_key: SpecValueKey) -> Self {
123          self.label_vec.push(SpecKeyLabel::new(label_key, value_key));
124          self
125      }
126  
127      pub fn build(self) -> SpecKey {
128          SpecKey {
129              category_key: self.category_key,
130              label_vec: self.label_vec,
131          }
132      }
133  }
134  
135  #[derive(CandidType, Deserialize, Debug, Clone)]
136  pub struct SpecKeyLabel {
137      label_key: SpecLabelKey,
138      value_key: SpecValueKey,
139  }
140  
141  impl SpecKeyLabel {
142      pub fn new(label_key: SpecLabelKey, value_key: SpecValueKey) -> Self {
143          Self {
144              label_key,
145              value_key,
146          }
147      }
148  }
149  
150  #[derive(CandidType, Deserialize, Debug, Clone)]
151  pub struct ItemSpecsV1 {
152      // Actual data of specs
153      pub map: BTreeMap<SpecCategoryKey, SpecCategory>,
154      // Mapping of combination of specs
155      pub index_map: BTreeMap<SpecIndexKey, SpecKey>,
156  }
157  
158  impl ItemSpecsV1 {
159      pub fn builder() -> ItemSpecsV1Builder {
160          ItemSpecsV1Builder::default()
161      }
162  
163      pub fn get_specs(&self, keys: &Vec<SpecIndexKey>) -> Option<shared::item::spec::SpecResponse> {
164          let mut result = Vec::new();
165  
166          for key in keys {
167              let mut label_vec = Vec::new();
168              let spec_key = self.get_spec_key(key)?;
169  
170              let category = self.get_category(spec_key.category_key)?;
171              for spec_key_label in &spec_key.label_vec {
172                  let label = category.get_label(spec_key_label.label_key)?;
173                  let value = label.get_value(&spec_key_label.value_key)?;
174                  label_vec.push(shared::item::spec::SpecResponseLabel {
175                      label_name: label.name.clone(),
176                      value: value.clone(),
177                  });
178              }
179  
180              result.push(shared::item::spec::SpecResponseCategory {
181                  category_name: category.name.clone(),
182                  label_vec,
183              });
184          }
185  
186          Some(result)
187      }
188  
189      fn get_spec_key(&self, key: &SpecIndexKey) -> Option<&SpecKey> {
190          self.index_map.get(key)
191      }
192  
193      fn get_category(&self, key: SpecCategoryKey) -> Option<&SpecCategory> {
194          self.map.get(&key)
195      }
196  }
197  
198  #[derive(Default)]
199  pub struct ItemSpecsV1Builder {
200      pub map: BTreeMap<SpecCategoryKey, SpecCategory>,
201      pub index_map: BTreeMap<SpecIndexKey, SpecKey>,
202  }
203  
204  impl ItemSpecsV1Builder {
205      /// Add a new spec category to the builder.
206      /// This will be used to store the actual data of the specs.
207      ///
208      /// The key is used to reference the category.
209      ///
210      /// The upper is the actual data of the category.
211      /// It contains the name of the category and the mapping of the labels.
212      pub fn spec(mut self, key: SpecCategoryKey, upper: SpecCategory) -> Self {
213          self.map.insert(key, upper);
214          self
215      }
216  
217      /// Add a new spec index to the builder.
218      /// This will be used to store the mapping of the combination of specs.
219      ///
220      /// The key is used to reference the index.
221      ///
222      /// The index is the actual data of the index.
223      /// It contains the category key and the mapping of the labels.
224      pub fn index(mut self, key: SpecIndexKey, index: SpecKey) -> Self {
225          self.index_map.insert(key, index);
226          self
227      }
228  
229      pub fn build(self) -> ItemSpecsV1 {
230          ItemSpecsV1 {
231              map: self.map,
232              index_map: self.index_map,
233          }
234      }
235  }