item.rs
1 use super::{ITEMS, MARKETS, STORES, TAGS}; 2 use candid::{CandidType, Decode, Deserialize, Encode}; 3 use ic_stable_structures::{storable::Bound, Storable}; 4 pub use interface::item::{ 5 attr::AttrKeys, ItemCoreDataArgs, ItemCoreDataResult, ItemPageArgs, ItemPageResult, 6 }; 7 use interface::unit::Currency; 8 use std::borrow::Cow; 9 10 pub mod attr; 11 use attr::{AttrCoreSpecificDataResult, AttrSpecificDataResult, ItemAttrs}; 12 pub mod image; 13 use image::ItemImages; 14 pub mod spec; 15 use spec::ItemSpecs; 16 17 #[derive(CandidType, Deserialize, Debug, Clone)] 18 pub struct Item { 19 pub name: String, 20 pub descriptions: Vec<String>, 21 pub store_id: u128, 22 pub tag_ids: Vec<u128>, 23 pub images: ItemImages, 24 pub specs: ItemSpecs, 25 pub attrs: ItemAttrs, 26 } 27 28 impl Storable for Item { 29 fn to_bytes(&self) -> std::borrow::Cow<[u8]> { 30 Cow::Owned(Encode!(self).unwrap()) 31 } 32 33 fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self { 34 Decode!(bytes.as_ref(), Self).unwrap() 35 } 36 37 const BOUND: Bound = Bound::Bounded { 38 max_size: 32768, 39 is_fixed_size: false, 40 }; 41 } 42 43 impl Item { 44 pub fn get_tags(&self) -> Vec<interface::item::Tag> { 45 self.tag_ids 46 .iter() 47 .map(|tag_id| { 48 let tag = TAGS.with(|p| p.borrow().get(tag_id)); 49 let tag = match tag { 50 Some(tag) => tag, 51 None => return None, // TODO: error handling 52 }; 53 Some(interface::item::Tag { 54 id: *tag_id, 55 name: tag.name.clone(), 56 }) 57 }) 58 .filter(|tag| tag.is_some()) 59 .map(|tag| tag.unwrap()) 60 .collect() 61 } 62 63 pub fn get_attr_data( 64 &self, 65 attr_keys: &AttrKeys, 66 currency: &Currency, 67 ) -> Option<AttrSpecificDataResult> { 68 let attr_data = self.attrs.map.get(attr_keys)?; 69 let price = *attr_data.price.get(currency)?; 70 let image_vec = self.images.get_image_vec(&attr_data.image_vec_key)?; 71 let specs = self.specs.get_specs(&attr_data.spec_keys); 72 73 let res = AttrSpecificDataResult { 74 stock: attr_data.stock, 75 price, 76 image_vec, 77 specs, 78 sale: attr_data.sale, 79 }; 80 81 Some(res) 82 } 83 84 pub fn get_attr_core_data( 85 &self, 86 attr_keys: &AttrKeys, 87 currency: &Currency, 88 ) -> Option<AttrCoreSpecificDataResult> { 89 let attr_data = self.attrs.map.get(attr_keys)?; 90 let price = *attr_data.price.get(currency)?; 91 let image = self 92 .images 93 .get_base_image(&attr_data.image_vec_key)? 94 .clone(); 95 96 let res = AttrCoreSpecificDataResult { 97 stock: attr_data.stock, 98 price, 99 image, 100 sale: attr_data.sale, 101 }; 102 103 Some(res) 104 } 105 } 106 107 pub fn get_item_page_info(arg: &ItemPageArgs) -> Option<ItemPageResult> { 108 let item = ITEMS.with(|p| p.borrow().get(&arg.item_id))?; 109 110 let store = STORES.with(|p| p.borrow().get(&item.store_id))?; 111 112 let market = match &arg.market_id { 113 Some(market_id) => MARKETS.with(|p| p.borrow().get(market_id)), 114 None => None, 115 }; 116 117 let market_name = match market { 118 Some(market) => Some(market.name.clone()), 119 None => None, 120 }; 121 122 let attr_data = item.get_attr_data(&arg.attr_keys, &arg.currency)?; 123 124 let res = interface::item::ItemPageResult { 125 name: item.name.clone(), 126 price: attr_data.price, 127 descriptions: item.descriptions.clone(), 128 tags: item.get_tags(), 129 image_vec: attr_data.image_vec, 130 stock: attr_data.stock, 131 store_id: item.store_id, 132 store_name: store.name.clone(), 133 market_name, 134 specs: attr_data.specs, 135 }; 136 137 Some(res) 138 } 139 140 pub fn get_item_core_data_vec(args: Vec<ItemCoreDataArgs>) -> Vec<Option<ItemCoreDataResult>> { 141 let mut res = Vec::new(); 142 143 for arg in args { 144 res.push(get_item_core_data(arg)); 145 } 146 147 res 148 } 149 150 fn get_item_core_data(arg: ItemCoreDataArgs) -> Option<ItemCoreDataResult> { 151 let item = ITEMS.with(|p| p.borrow().get(&arg.item.item_id))?; 152 153 let store = STORES.with(|p| p.borrow().get(&item.store_id))?; 154 155 let attr_core_data = item.get_attr_core_data(&arg.item.attr_keys, &arg.currency)?; 156 157 let image = attr_core_data.image; 158 159 let item_ommited_data = ItemCoreDataResult { 160 id: arg.item.item_id, 161 name: item.name.clone(), 162 price: attr_core_data.price, 163 tags: item.get_tags(), 164 image, 165 stock: attr_core_data.stock, 166 store_id: item.store_id, 167 store_name: store.name.clone(), 168 }; 169 170 Some(item_ommited_data) 171 }