helloworld/
01_helloworld.rs

1use std::convert::TryFrom;
2use std::collections::HashSet;
3use std::iter::FromIterator;
4use std::hash::{Hash, Hasher};
5use std::cmp::{Ord, Ordering, Eq};
6
7use std::fs::remove_dir_all;
8
9use serde::{Serialize, Deserialize};
10
11use json_surf::prelude::*;
12
13
14// Main struct
15#[derive(Serialize, Debug, Deserialize, PartialEq, PartialOrd, Clone)]
16struct UserInfo {
17    first: String,
18    last: String,
19    age: u8,
20}
21
22impl UserInfo {
23    pub fn new(first: String, last: String, age: u8) -> Self {
24        Self {
25            first,
26            last,
27            age,
28        }
29    }
30}
31
32impl Default for UserInfo {
33    fn default() -> Self {
34        let first = "".to_string();
35        let last = "".to_string();
36        let age = 0u8;
37        UserInfo::new(first, last, age)
38    }
39}
40
41
42fn main() {
43    // Specify home location for indexes
44    let home = ".store".to_string();
45    // Specify index name
46    let index_name = "test_user_info".to_string();
47
48    // Prepare builder
49    let mut builder = SurferBuilder::default();
50    builder.set_home(&home);
51
52    let data = UserInfo::default();
53    builder.add_struct(index_name.clone(), &data);
54
55    // Prepare Surfer
56    let mut surfer = Surfer::try_from(builder).unwrap();
57
58    // Prepare data to insert & search
59
60    // User 1: John Doe
61    let first = "John".to_string();
62    let last = "Doe".to_string();
63    let age = 20u8;
64    let john_doe = UserInfo::new(first, last, age);
65
66    // User 2: Jane Doe
67    let first = "Jane".to_string();
68    let last = "Doe".to_string();
69    let age = 18u8;
70    let jane_doe = UserInfo::new(first, last, age);
71
72    // User 3: Jonny Doe
73    let first = "Jonny".to_string();
74    let last = "Doe".to_string();
75    let age = 10u8;
76    let jonny_doe = UserInfo::new(first, last, age);
77
78    // User 4: Jinny Doe
79    let first = "Jinny".to_string();
80    let last = "Doe".to_string();
81    let age = 10u8;
82    let jinny_doe = UserInfo::new(first, last, age);
83
84    // Writing structs
85
86    // Option 1: One struct at a time
87    let _ = surfer.insert_struct(&index_name, &john_doe).unwrap();
88    let _ = surfer.insert_struct(&index_name, &jane_doe).unwrap();
89
90    // Option 2: Write all structs together
91    let users = vec![jonny_doe.clone(), jinny_doe.clone()];
92    let _ = surfer.insert_structs(&index_name, &users).unwrap();
93
94    block_thread(1);
95
96    // Reading structs
97
98    // Option 1: Full text search
99    let expected = vec![john_doe.clone()];
100    let computed = surfer.read_all_structs::<UserInfo>(&index_name, "John").unwrap().unwrap();
101    assert_eq!(expected, computed);
102
103    let mut expected = vec![john_doe.clone(), jane_doe.clone(), jonny_doe.clone(), jinny_doe.clone()];
104    expected.sort();
105    let mut computed = surfer.read_all_structs::<UserInfo>(&index_name, "doe").unwrap().unwrap();
106    computed.sort();
107    assert_eq!(expected, computed);
108
109    // Option 2: Term search
110    let mut expected = vec![jonny_doe.clone(), jinny_doe.clone()];
111    expected.sort();
112    let mut computed = surfer.read_all_structs_by_field::<UserInfo>(&index_name, "age", "10").unwrap().unwrap();
113    computed.sort();
114    assert_eq!(expected, computed);
115
116    // Delete structs
117
118    // Option 1: Delete based on all text fields
119    // Before delete
120    let before = surfer.read_all_structs::<UserInfo>(&index_name, "doe").unwrap().unwrap();
121    let before: HashSet<UserInfo> = HashSet::from_iter(before.into_iter());
122
123    // Delete any occurrence of John (Actual call to delete)
124    surfer.delete_structs(&index_name, "john").unwrap();
125
126    // After delete
127    let after = surfer.read_all_structs::<UserInfo>(&index_name, "doe").unwrap().unwrap();
128    let after: HashSet<UserInfo> = HashSet::from_iter(after.into_iter());
129    // Check difference
130    let computed: Vec<UserInfo> = before.difference(&after).map(|e| e.clone()).collect();
131    // Only John should be deleted
132    let expected = vec![john_doe];
133    assert_eq!(expected, computed);
134
135    // Option 2: Delete based on a specific field
136    // Before delete
137    let before = surfer.read_all_structs_by_field::<UserInfo>(&index_name, "age", "10").unwrap().unwrap();
138    let before: HashSet<UserInfo> = HashSet::from_iter(before.into_iter());
139
140    // Delete any occurrence where age = 10 (Actual call to delete)
141    surfer.delete_structs_by_field(&index_name, "age", "10").unwrap();
142
143    // After delete
144    let after = surfer.read_all_structs_by_field::<UserInfo>(&index_name, "age", "10").unwrap().unwrap();
145    let after: HashSet<UserInfo> = HashSet::from_iter(after.into_iter());
146    // Check difference
147    let mut computed: Vec<UserInfo> = before.difference(&after).map(|e| e.clone()).collect();
148    computed.sort();
149    // Both Jonny & Jinny should be deleted
150    let mut expected = vec![jonny_doe, jinny_doe];
151    expected.sort();
152    assert_eq!(expected, computed);
153
154
155    // Clean-up
156    let path = surfer.which_index(&index_name).unwrap();
157    let _ = remove_dir_all(&path);
158    let _ = remove_dir_all(&home);
159}
160
161/// Convenience method for sorting & likely not required in user code
162impl Ord for UserInfo {
163    fn cmp(&self, other: &Self) -> Ordering {
164        if self.first == other.first && self.last == other.last {
165            return Ordering::Equal;
166        };
167        if self.first == other.first {
168            if self.last > other.last {
169                Ordering::Greater
170            } else {
171                Ordering::Less
172            }
173        } else {
174            if self.first > other.first {
175                Ordering::Greater
176            } else {
177                Ordering::Less
178            }
179        }
180    }
181}
182
183/// Convenience method for sorting & likely not required in user code
184impl Eq for UserInfo {}
185
186/// Convenience method for sorting & likely not required in user code
187impl Hash for UserInfo {
188    fn hash<H: Hasher>(&self, state: &mut H) {
189        for i in self.first.as_bytes() {
190            state.write_u8(*i);
191        }
192        for i in self.last.as_bytes() {
193            state.write_u8(*i);
194        }
195        state.write_u8(self.age);
196        state.finish();
197    }
198}