hexser_potions/crud/
mod.rs1use hexser::prelude::*;
10
11#[derive(Clone, Debug, PartialEq)]
12pub struct Item {
13 pub id: u64,
14 pub name: String,
15}
16
17impl Entity for Item {
18 type Id = u64;
19}
20
21pub trait ItemRepository: Repository<Item> {}
22
23#[derive(Default)]
24pub struct InMemoryItemRepository {
25 pub items: Vec<Item>,
26}
27
28impl Repository<Item> for InMemoryItemRepository {
29 fn save(&mut self, entity: Item) -> HexResult<()> {
30 if let Some(existing) = self.items.iter_mut().find(|e| e.id == entity.id) {
31 *existing = entity;
32 } else {
33 self.items.push(entity);
34 }
35 Ok(())
36 }
37}
38
39#[derive(Clone, Debug, PartialEq, Eq)]
40pub enum ItemFilter { All, ById(u64) }
41#[derive(Clone, Copy, Debug, PartialEq, Eq)]
42pub enum ItemSortKey { Id }
43
44impl hexser::ports::repository::QueryRepository<Item> for InMemoryItemRepository {
45 type Filter = ItemFilter;
46 type SortKey = ItemSortKey;
47
48 fn find_one(&self, filter: &ItemFilter) -> HexResult<Option<Item>> {
49 let found = match filter {
50 ItemFilter::All => self.items.first().cloned(),
51 ItemFilter::ById(id) => self.items.iter().find(|e| e.id == *id).cloned(),
52 };
53 Ok(found)
54 }
55
56 fn find(&self, filter: &ItemFilter, _opts: hexser::ports::repository::FindOptions<ItemSortKey>) -> HexResult<Vec<Item>> {
57 let items: Vec<Item> = match filter {
58 ItemFilter::All => self.items.clone(),
59 ItemFilter::ById(id) => self.items.iter().filter(|e| e.id == *id).cloned().collect(),
60 };
61 Ok(items)
62 }
63
64 fn delete_where(&mut self, filter: &ItemFilter) -> HexResult<u64> {
65 let before = self.items.len();
66 match filter {
67 ItemFilter::All => self.items.clear(),
68 ItemFilter::ById(id) => self.items.retain(|e| e.id != *id),
69 }
70 Ok((before.saturating_sub(self.items.len())) as u64)
71 }
72}
73
74impl ItemRepository for InMemoryItemRepository {}
75
76pub fn create<R>(repo: &mut R, id: u64, name: impl Into<String>) -> HexResult<Item>
77where
78 R: ItemRepository + hexser::ports::repository::QueryRepository<Item, Filter = ItemFilter>,
79{
80 let item = Item { id, name: name.into() };
81 if <R as hexser::ports::repository::QueryRepository<Item>>::exists(repo, &ItemFilter::ById(id))? {
83 return Err(hexser::Hexserror::domain("E_HEXSER_POTIONS_ID_TAKEN", "ID already exists"));
84 }
85 repo.save(item.clone())?;
86 Ok(item)
87}
88
89pub fn get<R>(repo: &R, id: u64) -> HexResult<Item>
90where
91 R: ItemRepository + hexser::ports::repository::QueryRepository<Item, Filter = ItemFilter>,
92{
93 <R as hexser::ports::repository::QueryRepository<Item>>::find_one(repo, &ItemFilter::ById(id))?
94 .ok_or_else(|| hexser::Hexserror::not_found("Item", &id.to_string()))
95}
96
97pub fn delete<R>(repo: &mut R, id: u64) -> HexResult<()>
98where
99 R: ItemRepository + hexser::ports::repository::QueryRepository<Item, Filter = ItemFilter>,
100{
101 let _ = <R as hexser::ports::repository::QueryRepository<Item>>::delete_where(repo, &ItemFilter::ById(id))?;
102 Ok(())
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn crud_flow() {
111 let mut repo = InMemoryItemRepository::default();
112 let a = create(&mut repo, 1, "A").unwrap();
113 assert_eq!(a.name, "A");
114 let fetched = get(&repo, 1).unwrap();
115 assert_eq!(fetched, a);
116 delete(&mut repo, 1).unwrap();
117 assert!(get(&repo, 1).is_err());
118 }
119}