json_surf/
registry.rs

1use std::collections::{HashMap, BTreeMap, HashSet};
2use std::convert::TryFrom;
3use std::ops::{Deref, DerefMut};
4use std::fmt;
5use std::hash::{Hash, Hasher};
6
7use tantivy::schema::{Schema, Field, TextOptions, IntOptions, IndexRecordOption};
8use tantivy::{Index, IndexReader, IndexWriter, Document, Term, DocAddress};
9use tantivy::query::{QueryParser, TermQuery};
10use tantivy::collector::{TopDocs};
11use tantivy::schema::Value as SchemaValue;
12
13
14use crate::prelude::*;
15use crate::prelude::join;
16
17use serde::{Serialize};
18use serde::de::DeserializeOwned;
19use std::fmt::{Debug, Display};
20
21
22#[derive(Clone, Eq, PartialEq)]
23pub enum SurferFieldTypes {
24    U64,
25    I64,
26    F64,
27    String,
28    Bytes,
29}
30
31#[derive(Clone, Eq, PartialEq)]
32pub struct SurferSchema {
33    schema: Schema,
34    mappings: HashMap<String, SurferFieldTypes>,
35    track_tf: bool,
36    track_tf_idf: bool,
37}
38
39impl SurferSchema {
40    pub fn new(schema: Schema, mappings: HashMap<String, SurferFieldTypes>, track_tf: bool, track_tf_idf: bool) -> Self {
41        Self {
42            schema,
43            mappings,
44            track_tf,
45            track_tf_idf,
46        }
47    }
48    pub fn resolve_mapping(&self) -> &HashMap<String, SurferFieldTypes> {
49        &self.mappings
50    }
51}
52
53impl Deref for SurferSchema {
54    type Target = Schema;
55    fn deref(&self) -> &Self::Target {
56        &self.schema
57    }
58}
59
60impl DerefMut for SurferSchema {
61    fn deref_mut(&mut self) -> &mut Self::Target {
62        &mut self.schema
63    }
64}
65
66impl fmt::Debug for SurferSchema {
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        let itr = self.schema.fields();
69        let mut fields = Vec::new();
70        for (field, entry) in itr {
71            let debug = format!("Index: {} Name: {} Type: {:?}", field.field_id(), entry.name(), entry.field_type().value_type());
72            fields.push(debug);
73        };
74        write!(f, "{:?}", fields)
75    }
76}
77
78impl fmt::Display for SurferSchema {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        let itr = self.schema.fields();
81        for (_, entry) in itr {
82            let debug = format!("Name: {} Type: {:?}\n", entry.name(), entry.field_type().value_type());
83            let _ = write!(f, "{}", debug);
84        };
85        write!(f, "\n")
86    }
87}
88
89
90/// Builder struct for Surfer
91#[derive(Debug, Clone, Eq, PartialEq)]
92pub struct SurferBuilder {
93    schemas: HashMap<String, SurferSchema>,
94    home: Option<String>,
95}
96
97impl fmt::Display for SurferBuilder {
98    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99        let home = self.home.as_ref();
100        let indexes = &self.schemas;
101        for (name, schema) in indexes {
102            let home = resolve_index_directory_path(name, home);
103            let home = match home {
104                Ok(h) => h.to_string_lossy().to_string(),
105                Err(e) => format!("<PathError {}>", e.to_string())
106            };
107            let _ = write!(f, "Index: {} Location: {}\n", name, home);
108            let _ = write!(f, "{}", schema);
109        }
110        write!(f, "\n")
111    }
112}
113
114#[derive(Serialize)]
115struct SingleValuedNamedFieldDocument<'a>(BTreeMap<&'a str, &'a SchemaValue>);
116
117/// Default impl to get things going
118impl Default for SurferBuilder {
119    fn default() -> Self {
120        let schemas = HashMap::new();
121        let home = None;
122        Self {
123            schemas,
124            home,
125        }
126    }
127}
128
129
130/// Provides access to Surfer
131impl SurferBuilder {
132    /// Surfer Schema
133    pub fn resolve_schemas(&self) -> &HashMap<String, SurferSchema> {
134        &self.schemas
135    }
136    /// Set home location - default is indexes
137    pub fn set_home(&mut self, home: &str) {
138        self.home = Some(home.to_string());
139    }
140    /// Add a schema
141    pub fn add_schema(&mut self, name: String, schema: SurferSchema) {
142        self.schemas.insert(name, schema);
143    }
144    /// Add serde value panics otherwise
145    fn add_serde<T: Serialize>(&mut self, name: String, data: &T) {
146        let (schema, mappings) = to_schema(data, None).unwrap();
147        let schema = SurferSchema::new(schema, mappings, false, false);
148        self.schemas.insert(name, schema);
149    }
150    /// Add a serializable rust struct panics otherwise
151    pub fn add_struct<T: Serialize>(&mut self, name: String, data: &T) {
152        self.add_serde::<T>(name, data);
153    }
154}
155
156#[derive(Debug, Clone, Eq, PartialEq)]
157pub struct AndCondition {
158    field_name: String,
159    field_value: String,
160}
161
162impl AndCondition {
163    pub fn new(field_name: String, field_value: String) -> Self {
164        Self {
165            field_name,
166            field_value,
167        }
168    }
169    pub fn update_field_value(&mut self, field_value: String) {
170        self.field_value = field_value;
171    }
172    pub fn resolve_field_name(&self) -> &String {
173        &self.field_name
174    }
175    pub fn resolve_field_value(&self) -> &String {
176        &self.field_value
177    }
178}
179
180#[derive(Debug, Clone, Eq, PartialEq)]
181pub struct OrCondition {
182    conditions: Vec<AndCondition>,
183}
184
185impl Display for OrCondition {
186    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
187        let mut fragments = Vec::<String>::new();
188        for (index, condition) in self.conditions.iter().enumerate() {
189            if index == 0 {
190                let fragment = format!("{} = {}", condition.resolve_field_name(), condition.resolve_field_value());
191                fragments.push(fragment);
192            }
193        }
194        let x = fragments.join::<&str>(" AND ");
195        write!(f, "{}", x)
196    }
197}
198
199impl OrCondition {
200    pub fn new(conditions: Vec<AndCondition>) -> Self {
201        Self {
202            conditions
203        }
204    }
205    pub fn resolve_conditions_for_edit(&mut self) -> &mut Vec<AndCondition> {
206        &mut self.conditions
207    }
208    pub fn resolve_conditions(&self) -> &Vec<AndCondition> {
209        &self.conditions
210    }
211}
212
213
214impl From<(String, String)> for OrCondition {
215    fn from((field_name, field_value): (String, String)) -> Self {
216        let conditions = vec![AndCondition::new(field_name, field_value)];
217        Self::new(conditions)
218    }
219}
220
221/// Surfer: Client API
222pub struct Surf {
223    surfer: Surfer
224}
225
226impl Surf {
227    pub fn new(surfer: Surfer) -> Self {
228        Self {
229            surfer,
230        }
231    }
232    /// Use apply to manage and limit the output
233    pub fn apply<T: Serialize + DeserializeOwned>(&mut self, index_name: &str, conditions: &Vec<OrCondition>, limit: Option<usize>, score: Option<f32>) -> Result<Option<Vec<T>>, IndexError> {
234        self.surfer.multiple_structs_by_field(index_name, conditions, limit, score)
235    }
236    /// Similar to SQL Select
237    pub fn select<T: Serialize + DeserializeOwned>(&mut self, index_name: &str, conditions: &Vec<OrCondition>) -> Result<Option<Vec<T>>, IndexError> {
238        let limit = Some(100usize);
239        let score = Some(0f32);
240        self.apply(index_name, conditions, limit, score)
241    }
242    /// Similar to SQL Insert
243    pub fn insert<T: Serialize>(&mut self, name: &str, payload: &Vec<T>) -> Result<(), IndexError> {
244        self.surfer.insert_structs::<T>(name, payload)
245    }
246    /// Aims to be similar to SQL Delete
247    pub fn delete(&mut self, index_name: &str, field_name: &str, field_value: &str) -> Result<(), IndexError> {
248        self.surfer.delete_structs_by_field(index_name, field_name, field_value)
249    }
250}
251
252impl Deref for Surf {
253    type Target = Surfer;
254    fn deref(&self) -> &Self::Target {
255        &self.surfer
256    }
257}
258
259impl DerefMut for Surf {
260    fn deref_mut(&mut self) -> &mut Self::Target {
261        &mut self.surfer
262    }
263}
264
265impl From<Surfer> for Surf {
266    fn from(surfer: Surfer) -> Self {
267        Self::new(surfer)
268    }
269}
270
271impl TryFrom<SurferBuilder> for Surf {
272    type Error = IndexError;
273    fn try_from(builder: SurferBuilder) -> Result<Self, Self::Error> {
274        let surfer = Surfer::try_from(builder)?;
275        Ok(Surf::from(surfer))
276    }
277}
278
279/// Surfer: Client API
280pub struct Surfer {
281    home: String,
282    indexes: HashMap<String, Index>,
283    fields: HashMap<String, Vec<Field>>,
284    readers: HashMap<String, Option<IndexReader>>,
285    writers: HashMap<String, Option<IndexWriter>>,
286    schemas: HashMap<String, SurferSchema>,
287}
288
289impl Surfer {
290    /// Access to Surfer Schema
291    pub fn resolve_schema(&self, name: &str) -> Option<&SurferSchema> {
292        self.schemas.get(name)
293    }
294    /// Location of home
295    pub fn home(&self) -> &String {
296        &self.home
297    }
298    /// Location of Index
299    pub fn which_index(&self, name: &str) -> Option<String> {
300        if !self.indexes.contains_key(name) {
301            return None;
302        }
303        if name.starts_with(&self.home) {
304            Some(name.to_string())
305        } else {
306            join(&self.home, name)
307        }
308    }
309    /// Access to Index
310    pub fn resolve_index(&self, name: &str) -> Option<&Index> {
311        if !self.indexes.contains_key(name) {
312            return None;
313        }
314        self.indexes.get(name)
315    }
316    /// Inserts a struct
317    pub fn insert_struct<T: Serialize>(&mut self, name: &str, data: &T) -> Result<(), IndexError> {
318        let data = serde_json::to_string(data)?;
319        let writer = self.writers.get(name);
320        if writer.is_none() {
321            return Ok(());
322        };
323
324        let index = self.indexes.get(name).unwrap();
325        let schema = &index.schema();
326
327        let writer = writer.unwrap();
328        if writer.is_none() {
329            let writer = open_index_writer(index)?;
330            self.writers.insert(name.to_string(), Some(writer));
331        };
332
333        let writer = self.writers.get_mut(name).unwrap().as_mut().unwrap();
334        let document = schema.parse_document(&data)?;
335        writer.add_document(document);
336        writer.commit()?;
337        Ok(())
338    }
339    /// Inserts a structs
340    pub fn insert_structs<T: Serialize>(&mut self, name: &str, payload: &Vec<T>) -> Result<(), IndexError> {
341        {
342            let result = self._prepare_index_writer(name);
343            if result.is_err() {
344                return Ok(());
345            };
346        }
347
348        let writer = self.writers.get_mut(name).unwrap().as_mut().unwrap();
349
350        let index = self.indexes.get(name).unwrap();
351        let schema = &index.schema();
352        for data in payload {
353            let data = serde_json::to_string(data)?;
354            let document = schema.parse_document(&data)?;
355            writer.add_document(document);
356        }
357
358        writer.commit()?;
359        Ok(())
360    }
361    /// Massive hack look away ;)
362    fn jsonify(&self, name: &str, document: &Document) -> Result<String, IndexError> {
363        let schema = self.indexes.get(name).unwrap().schema();
364
365        let mut field_map = BTreeMap::new();
366        for (field, field_values) in document.get_sorted_field_values() {
367            let field_name = schema.get_field_name(field);
368            let fv = field_values.get(0);
369            if fv.is_none() {
370                let message = format!("Unable to jsonify: {}", name);
371                let reason = format!("Field: {} does not have any value", field_name);
372                let error = IndexError::new(message, reason);
373                return Err(error);
374            };
375            let fv = fv.unwrap().value();
376            field_map.insert(field_name, fv);
377        };
378        let payload = SingleValuedNamedFieldDocument(field_map);
379        let result = serde_json::to_string(&payload)
380            .map_err(|e| {
381                let message = "Unable to serialize struct".to_string();
382                let reason = e.to_string();
383                IndexError::new(
384                    message,
385                    reason,
386                )
387            });
388        result
389    }
390    fn _is_index_valid(&self, name: &str) -> bool {
391        let index = self.indexes.get(name);
392        if index.is_some() {
393            true
394        } else {
395            false
396        }
397    }
398    fn _is_reader_valid(&self, name: &str) -> bool {
399        if !self.readers.contains_key(name) {
400            return false;
401        }
402        let reader = self.readers.get(name).unwrap();
403        if reader.is_some() {
404            true
405        } else {
406            false
407        }
408    }
409    fn _is_writer_valid(&self, name: &str) -> bool {
410        if !self.writers.contains_key(name) {
411            return false;
412        }
413        let writer = self.writers.get(name).unwrap();
414        if writer.is_some() {
415            true
416        } else {
417            false
418        }
419    }
420    fn _prepare_index_writer(&mut self, index_name: &str) -> Result<(), IndexError> {
421        if !self._is_index_valid(index_name) {
422            let message = format!("Unable to prepare the writer");
423            let reason = format!("Index was missing: {} ", index_name);
424            return Err(IndexError::new(message, reason));
425        };
426        if self._is_writer_valid(&index_name) {
427            return Ok(());
428        };
429        let index = self.indexes.get(index_name).unwrap();
430        let writer = open_index_writer(index)?;
431        let _ = self.writers.insert(index_name.to_string(), Some(writer));
432        Ok(())
433    }
434
435    fn _prepare_index_reader(&mut self, index_name: &str) -> Result<(), IndexError> {
436        if !self._is_index_valid(index_name) {
437            let message = format!("Unable to prepare the reader");
438            let reason = format!("Index was missing: {} ", index_name);
439            return Err(IndexError::new(message, reason));
440        };
441        if self._is_reader_valid(&index_name) {
442            return Ok(());
443        };
444        let index = self.indexes.get(index_name).unwrap();
445        let reader = open_index_reader(index)?;
446        let _ = self.readers.insert(index_name.to_string(), Some(reader));
447        Ok(())
448    }
449    fn _build_terms(&self, schema: &SurferSchema, field_value: &str) -> Result<Vec<Term>, IndexError> {
450        let mut field_names = Vec::<&String>::with_capacity(schema.mappings.len());
451        for (field_name, field_type) in schema.mappings.iter() {
452            match field_type {
453                SurferFieldTypes::String => field_names.push(field_name),
454                _ => {}
455            };
456        }
457        let mut terms = Vec::<Term>::with_capacity(schema.mappings.len());
458        if field_names.is_empty() {
459            return Ok(terms);
460        };
461        for field_name in field_names {
462            let term = self._build_term(schema, field_name, field_value)?;
463            terms.push(term);
464        }
465        Ok(terms)
466    }
467    fn _build_term(&self, schema: &SurferSchema, field_name: &str, field_value: &str) -> Result<Term, IndexError> {
468        let mappings = schema.resolve_mapping();
469
470        let field_type = mappings.get(field_name);
471        if field_type.is_none() {
472            let message = format!("Unable to perform search");
473            let reason = format!("Missing field: {}", field_name);
474            return Err(IndexError::new(message, reason));
475        };
476        let field_type = field_type.unwrap();
477
478        let field = schema.get_field(field_name);
479        if field.is_none() {
480            let message = format!("Unable to perform search");
481            let reason = format!("Missing field: {}", field_name);
482            return Err(IndexError::new(message, reason));
483        };
484        let field = field.unwrap();
485
486        let term = match field_type {
487            SurferFieldTypes::U64 => {
488                let field_value = field_value.parse::<u64>().map_err(|e| {
489                    let message = format!("Invalid search: {}", field_value);
490                    let reason = e.to_string();
491                    IndexError::new(message, reason)
492                })?;
493                Term::from_field_u64(field, field_value)
494            }
495            SurferFieldTypes::I64 => {
496                let field_value = field_value.parse::<i64>().map_err(|e| {
497                    let message = format!("Invalid search: {}", field_value);
498                    let reason = e.to_string();
499                    IndexError::new(message, reason)
500                })?;
501                Term::from_field_i64(field, field_value)
502            }
503            SurferFieldTypes::F64 => {
504                let field_value = field_value.parse::<f64>().map_err(|e| {
505                    let message = format!("Invalid search: {}", field_value);
506                    let reason = e.to_string();
507                    IndexError::new(message, reason)
508                })?;
509                Term::from_field_f64(field, field_value)
510            }
511            SurferFieldTypes::String => {
512                Term::from_field_text(field, field_value)
513            }
514            SurferFieldTypes::Bytes => {
515                let message = format!("Invalid search: {}", field_value);
516                let reason = "Cant search on bytes".to_string();
517                return Err(IndexError::new(message, reason));
518            }
519        };
520
521        Ok(term)
522    }
523
524    fn _build_term_query(&self, term: Term, segment_postings_options: Option<IndexRecordOption>) -> Result<TermQuery, IndexError> {
525        let segment_postings_options = match segment_postings_options {
526            Some(option) => option,
527            None => IndexRecordOption::Basic,
528        };
529        Ok(TermQuery::new(term, segment_postings_options))
530    }
531
532    fn _resolve_surfer_schema(&self, index_name: &str) -> Result<&SurferSchema, IndexError> {
533        let schema = self.schemas.get(index_name);
534        if schema.is_none() {
535            let message = format!("Invalid index operation for {}", index_name);
536            let reason = format!("No schema found for index: {}", index_name);
537            return Err(IndexError::new(message, reason));
538        };
539        let schema = schema.unwrap();
540        Ok(schema)
541    }
542
543    fn _resolve_limit(&self, limit: Option<usize>) -> usize {
544        match limit {
545            Some(limit) => limit,
546            None => 10
547        }
548    }
549
550    fn _resolve_score(&self, score: Option<f32>) -> f32 {
551        match score {
552            Some(score) => score,
553            None => 90f32
554        }
555    }
556
557    /// Uses term search
558    pub fn delete_structs_by_field(&mut self, index_name: &str, field_name: &str, field_value: &str) -> Result<(), IndexError> {
559        let schema = self._resolve_surfer_schema(index_name)?;
560        let term = self._build_term(&schema, field_name, field_value)?;
561        let _ = self._prepare_index_writer(index_name)?;
562        let writer = self.writers.get_mut(index_name).unwrap().as_mut().unwrap();
563        let _ = writer.delete_term(term);
564        let _ = writer.commit()?;
565        Ok(())
566    }
567
568    /// Uses full text serach
569    pub fn delete_structs(&mut self, index_name: &str, field_value: &str) -> Result<(), IndexError> {
570        let schema = self._resolve_surfer_schema(index_name)?;
571        let terms = self._build_terms(&schema, field_value)?;
572        let _ = self._prepare_index_writer(index_name)?;
573        let writer = self.writers.get_mut(index_name).unwrap().as_mut().unwrap();
574        for i in 0..terms.len() {
575            let term = terms.get(i).unwrap().to_owned();
576            let _ = writer.delete_term(term);
577        }
578        let _ = writer.commit()?;
579        Ok(())
580    }
581
582    /// Uses term search
583    pub fn read_all_structs_by_field<T: Serialize + DeserializeOwned>(&mut self, index_name: &str, field_name: &str, field_value: &str) -> Result<Option<Vec<T>>, IndexError> {
584        self.read_structs_by_field::<T>(index_name, field_name, field_value, None, Some(0f32))
585    }
586    /// Uses term search
587    pub fn read_structs_by_field<T: Serialize + DeserializeOwned>(&mut self, index_name: &str, field_name: &str, field_value: &str, limit: Option<usize>, score: Option<f32>) -> Result<Option<Vec<T>>, IndexError> {
588        let conditions = vec![OrCondition::from((field_name.to_string(), field_value.to_string()))];
589        self.multiple_structs_by_field::<T>(index_name, &conditions, limit, score)
590    }
591
592    /// Reads as string
593    pub fn read_string(&mut self, name: &str, query: &str, limit: Option<usize>, score: Option<f32>) -> Result<Option<Vec<String>>, IndexError> {
594        {
595            let result = self._prepare_index_reader(name);
596            if result.is_err() {
597                return Ok(None);
598            };
599        }
600        let index = self.indexes.get(name).unwrap();
601        let reader = self.readers.get(name).unwrap().as_ref().unwrap();
602
603        let default_fields = self.fields.get(name).unwrap().clone();
604        let searcher = reader.searcher();
605
606        let query_parser = QueryParser::for_index(&index, default_fields);
607        let query = query_parser.parse_query(query)?;
608        let limit = if limit.is_some() {
609            limit.unwrap()
610        } else {
611            10
612        };
613        let top_docs = searcher.search(&query, &TopDocs::with_limit(limit))?;
614
615        let mut docs = Vec::with_capacity(top_docs.len());
616        for (doc_score, doc_address) in top_docs {
617            if score.is_some() && doc_score < score.unwrap() {
618                continue;
619            }
620            let doc = searcher.doc(doc_address)?;
621            let doc = self.jsonify(name, &doc)?;
622            docs.push(doc);
623        };
624        Ok(Some(docs))
625    }
626
627    /// Reads as struct
628    pub fn read_all_structs<T: Serialize + DeserializeOwned>(&mut self, name: &str, query: &str) -> Result<Option<Vec<T>>, IndexError> {
629        self.read_structs(name, query, None, None)
630    }
631
632    /// Reads as struct
633    pub fn read_structs<T: Serialize + DeserializeOwned>(&mut self, name: &str, query: &str, limit: Option<usize>, score: Option<f32>) -> Result<Option<Vec<T>>, IndexError> {
634        {
635            let result = self._prepare_index_reader(name);
636            if result.is_err() {
637                return Ok(None);
638            };
639        }
640        let index = self.indexes.get(name).unwrap();
641        let reader = self.readers.get(name).unwrap().as_ref().unwrap();
642
643        let surfer_schema = self.schemas.get(name).unwrap();
644        let mappings = surfer_schema.resolve_mapping();
645
646        let mut fields = Vec::<Field>::with_capacity(mappings.len());
647        for (f, fe) in surfer_schema.schema.fields() {
648            let name = fe.name();
649            if !mappings.contains_key(name) {
650                continue;
651            };
652            let ft = mappings.get(name).unwrap();
653            match ft {
654                SurferFieldTypes::String => fields.push(f),
655                _ => {}
656            }
657        };
658
659        let searcher = reader.searcher();
660
661        let query_parser = QueryParser::for_index(&index, fields);
662        let query = query_parser.parse_query(query)?;
663        let limit = if limit.is_some() {
664            limit.unwrap()
665        } else {
666            10
667        };
668        let top_docs = searcher.search(&query, &TopDocs::with_limit(limit))?;
669
670        let mut docs = Vec::with_capacity(top_docs.len());
671        for (doc_score, doc_address) in top_docs {
672            if score.is_some() && doc_score < score.unwrap() {
673                continue;
674            }
675            let doc = searcher.doc(doc_address)?;
676            let doc = self.jsonify(name, &doc)?;
677            let doc = serde_json::from_str::<T>(&doc).unwrap();
678            docs.push(doc);
679        };
680        Ok(Some(docs))
681    }
682    /// Uses term search
683    fn multiple_structs_by_field<T: Serialize + DeserializeOwned>(&mut self, index_name: &str, conditions: &Vec<OrCondition>, limit: Option<usize>, score: Option<f32>) -> Result<Option<Vec<T>>, IndexError> {
684        let _ = self._prepare_index_reader(index_name)?;
685        let reader = self.readers.get(index_name).unwrap().as_ref().unwrap();
686        let searcher = reader.searcher();
687        let limit = self._resolve_limit(limit);
688        let cutoff = self._resolve_score(score);
689        let schema = self._resolve_surfer_schema(index_name)?;
690        let mut all_docs = HashSet::<SurferDocAddress>::new();
691
692        for condition in conditions {
693            let and = condition.resolve_conditions();
694            let mut docs = HashSet::new();
695            for (i, c) in and.iter().enumerate() {
696                let field_name = c.resolve_field_name();
697                let field_value = c.resolve_field_value();
698                let term = self._build_term(schema, field_name, field_value)?;
699                let query = self._build_term_query(term, None)?;
700                let mut tmp = HashSet::new();
701                let top_docs = searcher
702                    .search(&query, &TopDocs::with_limit(limit))
703                    .map_err(|e| {
704                        let message = "Error while term query".to_string();
705                        let reason = e.to_string();
706                        IndexError::new(message, reason)
707                    })?;
708
709
710                for (score, address) in top_docs.to_owned() {
711                    if score < cutoff {
712                        continue;
713                    };
714
715                    let address = SurferDocAddress::from(address);
716                    // println!("Found: {}", address);
717                    if i == 0 {
718                        tmp.insert(address);
719                        continue;
720                    }
721
722                    if docs.contains(&address) {
723                        tmp.insert(address);
724                    }
725                }
726
727                if tmp.is_empty() {
728                    docs.clear();
729                    break;
730                } else {
731                    docs.extend(tmp);
732                }
733            }
734            all_docs.extend(docs);
735        };
736
737        let mut docs = Vec::with_capacity(all_docs.len());
738        for doc_address in all_docs {
739            let doc = searcher.doc(doc_address.0)?;
740            let doc = self.jsonify(index_name, &doc)?;
741            let doc = serde_json::from_str::<T>(&doc).unwrap();
742            docs.push(doc);
743        };
744        Ok(Some(docs))
745    }
746}
747
748/// Panics if somethings goes wrong
749impl Surfer {
750    pub fn new(builder: SurferBuilder) -> Self {
751        Surfer::try_from(builder).unwrap()
752    }
753}
754
755/// Opens mmap dir
756fn initialize_mmap(name: &str, home: &str, schema: &Schema) -> Result<Index, IndexError> {
757    let path = resolve_index_directory_path(name, Some(home))?;
758    if path.exists() {
759        let dir = open_mmap_directory(path)?;
760        open_index(dir, None)
761    } else {
762        let dir = open_mmap_directory(path)?;
763        open_index(dir, Some(&schema))
764    }
765}
766
767/// Get home location
768fn extract_home(builder: &SurferBuilder) -> Result<String, IndexError> {
769    let home = builder.home.as_ref();
770    let home = resolve_home(home)?;
771    Ok(home.to_str().unwrap().to_string())
772}
773
774/// Setup indexes
775fn initialized_index(home: &str, builder: &SurferBuilder) -> Result<HashMap<String, Index>, IndexError> {
776    let schemas = &builder.schemas;
777    let mut indexes = HashMap::<String, Index>::with_capacity(schemas.len());
778    for (name, schema) in schemas {
779        let index = initialize_mmap(name, &home, &schema)?;
780        indexes.insert(name.to_string(), index);
781    };
782    Ok(indexes)
783}
784
785/// Extract field information
786fn extract_fields(builder: &SurferBuilder) -> HashMap<String, Vec<Field>> {
787    let data = &builder.schemas;
788    let mut fields = HashMap::<String, Vec<Field>>::with_capacity(data.len());
789    for (data, schema) in data {
790        let key = data.clone();
791        let value: Vec<Field> = schema.fields().map(|(f, _)| f).collect();
792        fields.insert(key, value);
793    };
794    fields
795}
796
797
798impl TryFrom<SurferBuilder> for Surfer {
799    type Error = IndexError;
800    fn try_from(builder: SurferBuilder) -> Result<Self, Self::Error> {
801        let home = extract_home(&builder)?;
802        let indexes = initialized_index(&home, &builder)?;
803        let fields = extract_fields(&builder);
804
805        let mut readers = HashMap::new();
806        let mut writers = HashMap::new();
807        for (name, _) in &builder.schemas {
808            let reader: Option<IndexReader> = None;
809            let writer: Option<IndexWriter> = None;
810            writers.insert(name.to_string(), writer);
811            readers.insert(name.to_string(), reader);
812        };
813        let schemas = builder.resolve_schemas().clone();
814        Ok(Surfer {
815            home,
816            indexes,
817            fields,
818            readers,
819            writers,
820            schemas,
821        })
822    }
823}
824
825struct SurferDocAddress(DocAddress);
826
827impl SurferDocAddress {
828    fn new(address: DocAddress) -> Self {
829        Self(address)
830    }
831}
832
833impl From<DocAddress> for SurferDocAddress {
834    fn from(address: DocAddress) -> Self {
835        Self::new(address)
836    }
837}
838
839
840impl Deref for SurferDocAddress {
841    type Target = DocAddress;
842
843    fn deref(&self) -> &Self::Target {
844        &self.0
845    }
846}
847
848impl DerefMut for SurferDocAddress {
849    fn deref_mut(&mut self) -> &mut Self::Target {
850        &mut self.0
851    }
852}
853
854impl Display for SurferDocAddress {
855    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
856        let address = &self.0;
857        write!(f, "SegmentLocalId = {}, DocId {})", address.0, address.1)
858    }
859}
860
861impl Debug for SurferDocAddress {
862    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
863        let address = &self.0;
864        write!(f, "SegmentLocalId = {}, DocId {})", address.0, address.1)
865    }
866}
867
868
869impl PartialEq for SurferDocAddress {
870    fn eq(&self, other: &SurferDocAddress) -> bool {
871        let doc_address = &self.0;
872        let other_doc_address = other.0;
873        doc_address.0 == other_doc_address.0 && doc_address.1 == other_doc_address.1
874    }
875}
876
877impl Hash for SurferDocAddress {
878    fn hash<H: Hasher>(&self, state: &mut H) {
879        let address = self.0;
880        state.write_u32(address.0);
881        state.write_u32(address.1);
882        state.finish();
883    }
884}
885
886impl Eq for SurferDocAddress {}
887
888/// Container to pass through config to tantivy
889pub enum Control {
890    ControlTextOptions(TextOptions),
891    ControlIntOptions(IntOptions),
892}
893
894
895#[cfg(test)]
896mod library_tests {
897    use super::*;
898    use super::super::utils;
899    use serde::{Serialize, Deserialize};
900    use std::fmt::Debug;
901    use std::path::Path;
902    use std::fs::remove_dir_all;
903    use std::cmp::{Ord, Ordering, Eq};
904    use std::collections::HashSet;
905    use std::iter::FromIterator;
906    use std::hash::{Hash, Hasher};
907
908
909    #[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
910    struct Giant {
911        a: String,
912        c: u64,
913        d: u32,
914        e: u16,
915        f: u8,
916        g: i64,
917        h: i32,
918        i: i16,
919        j: i8,
920        k: f64,
921        l: f32,
922
923    }
924
925    impl Default for Giant {
926        fn default() -> Self {
927            let a: String = "tag1".to_string();
928            let c: u64 = 10000;
929            let d: u32 = 1000;
930            let e: u16 = 100;
931            let f: u8 = 10;
932            let g: i64 = 20000;
933            let h: i32 = 2000;
934            let i: i16 = 200;
935            let j: i8 = 20;
936            let k: f64 = 10.0;
937            let l: f32 = 1.0;
938            Giant {
939                a,
940                c,
941                d,
942                e,
943                f,
944                g,
945                h,
946                i,
947                j,
948                k,
949                l,
950
951            }
952        }
953    }
954
955    #[test]
956    fn validate_giant() {
957        let name = random_string(None);
958        let home = ".validate_giant";
959        let index_path = format!("{}/{}", home, name);
960        let path = Path::new(&index_path);
961        assert!(!path.exists());
962
963        let giant = Giant::default();
964
965        let mut builder = SurferBuilder::default();
966        builder.set_home(home);
967        builder.add_struct("giant".to_string(), &giant);
968        let mut surfer = Surfer::try_from(builder).unwrap();
969        let data = vec![Giant::default()];
970        let computed = surfer.insert_structs("giant", &data);
971        assert!(computed.is_ok());
972        let a: String = "tag1".to_string();
973        let c: u64 = 10000;
974        let d: u32 = 1000;
975        let e: u16 = 100;
976        let f: u8 = 10;
977        let g: i64 = 20000;
978        let h: i32 = 2000;
979        let i: i16 = 200;
980        let j: i8 = 20;
981        let k: f64 = 10.0;
982        let l: f32 = 1.0;
983
984        let conditions = vec![
985            AndCondition::new("a".to_string(), format!("{}", a)),
986            AndCondition::new("c".to_string(), format!("{}", c)),
987            AndCondition::new("d".to_string(), format!("{}", d)),
988            AndCondition::new("e".to_string(), format!("{}", e)),
989            AndCondition::new("g".to_string(), format!("{}", g)),
990            AndCondition::new("f".to_string(), format!("{}", f)),
991            AndCondition::new("h".to_string(), format!("{}", h)),
992            AndCondition::new("i".to_string(), format!("{}", i)),
993            AndCondition::new("j".to_string(), format!("{}", j)),
994            AndCondition::new("k".to_string(), format!("{}", k)),
995            AndCondition::new("l".to_string(), format!("{}", l)),
996        ];
997        let conditions = vec![OrCondition::new(conditions)];
998        let computed = surfer.multiple_structs_by_field::<Giant>("giant", &conditions, None, Some(0.0));
999        assert!(computed.is_ok());
1000        let computed = computed.unwrap();
1001        assert!(computed.is_some());
1002        let computed = computed.unwrap();
1003        assert_eq!(computed, vec![Giant::default()]);
1004
1005        let computed = surfer.multiple_structs_by_field::<Giant>("giant", &conditions, None, None);
1006        assert!(computed.is_ok());
1007
1008
1009        let computed = surfer.delete_structs_by_field("giant", "c", "crap");
1010        assert!(computed.is_err());
1011
1012        let computed = surfer.delete_structs_by_field("giant", "c", "crap");
1013        assert!(computed.is_err());
1014
1015        let computed = surfer.delete_structs_by_field("giant", "g", "crap");
1016        assert!(computed.is_err());
1017
1018        let computed = surfer.delete_structs_by_field("giant", "k", "crap");
1019        assert!(computed.is_err());
1020
1021        let computed = surfer.delete_structs_by_field("giant", "crap", "crap");
1022        assert!(computed.is_err());
1023
1024        let computed = surfer.delete_structs_by_field("crap", "crap", "crap");
1025        assert!(computed.is_err());
1026
1027        let _ = remove_dir_all(index_path);
1028        let _ = remove_dir_all(home);
1029    }
1030
1031
1032    #[derive(Clone, Serialize, Debug, Deserialize, PartialEq)]
1033    struct OldMan {
1034        title: String,
1035        body: String,
1036    }
1037
1038    impl Default for OldMan {
1039        fn default() -> Self {
1040            let title = "".to_string();
1041            let body = "".to_string();
1042            Self {
1043                title,
1044                body,
1045            }
1046        }
1047    }
1048
1049    #[test]
1050    fn validate_read_existing_documents_as_structs() {
1051        let name = random_string(None);
1052        let home = ".validate_read_existing_documents_as_structs";
1053        let index_path = format!("{}/{}", home, name);
1054        let path = Path::new(&index_path);
1055        assert!(!path.exists());
1056
1057        let data = OldMan::default();
1058
1059        let mut builder = SurferBuilder::default();
1060        builder.set_home(home);
1061        builder.add_struct(name.clone(), &data);
1062
1063        {
1064            let title = "The Old Man and the Sea".to_string();
1065            let body = "He was an old man who fished alone in a skiff in the Gulf Stream and he had gone eighty-four days now without taking a fish.".to_string();
1066            let old_man_doc = OldMan {
1067                title,
1068                body,
1069            };
1070
1071            let mut surfer = Surfer::new(builder.clone());
1072            let _ = surfer.insert_struct(&name, &old_man_doc).unwrap();
1073        }
1074
1075        let mut surfer = Surfer::new(builder.clone());
1076        let query = "sea whale";
1077        let result = surfer.read_structs::<OldMan>(&name, query, None, None);
1078        assert!(result.is_ok());
1079        assert!(path.exists());
1080        let _ = remove_dir_all(index_path);
1081        let _ = remove_dir_all(home);
1082    }
1083
1084    #[test]
1085    fn validate_read_existing_documents_as_strings() {
1086        let title = "The Old Man and the Sea".to_string();
1087        let body = "He was an old man who fished alone in a skiff in the Gulf Stream and he had gone eighty-four days now without taking a fish.".to_string();
1088        let expected = OldMan {
1089            title,
1090            body,
1091        };
1092
1093
1094        let name = random_string(None);
1095        let mut builder = SurferBuilder::default();
1096        let data = OldMan::default();
1097        let home = ".validate_read_existing_documents_as_strings";
1098        let index_path = format!("{}/{}", home, name);
1099        let path = Path::new(&index_path);
1100        assert!(!path.exists());
1101        builder.set_home(home);
1102        builder.add_struct(name.to_string(), &data);
1103
1104        {
1105            let title = "The Old Man and the Sea".to_string();
1106            let body = "He was an old man who fished alone in a skiff in the Gulf Stream and he had gone eighty-four days now without taking a fish.".to_string();
1107            let old_man_doc = OldMan {
1108                title,
1109                body,
1110            };
1111
1112            let mut surfer = Surfer::new(builder.clone());
1113            let _ = surfer.insert_struct(&name, &old_man_doc).unwrap();
1114        }
1115
1116        let mut surfer = Surfer::new(builder.clone());
1117        let query = "sea whale";
1118        let result = surfer.read_string("Non-existent", query, None, None);
1119        assert!(result.is_ok());
1120        let result = result.unwrap();
1121        assert!(result.is_none());
1122        let result = surfer.read_string(&name, query, None, None);
1123        assert!(result.is_ok());
1124        let result = result.unwrap();
1125        assert!(result.is_some());
1126        let result = result.unwrap();
1127        let mut computed = Vec::new();
1128        for entry in result {
1129            let data: serde_json::Result<OldMan> = serde_json::from_str(&entry);
1130            let data = data.unwrap();
1131            computed.push(data);
1132        };
1133        assert_eq!(computed, vec![expected.clone()]);
1134
1135        // Reading documents again
1136        let result = surfer.read_string(&name, query, None, None);
1137        assert!(result.is_ok());
1138        let result = result.unwrap();
1139        assert!(result.is_some());
1140        let result = result.unwrap();
1141        let mut computed = Vec::new();
1142        for entry in result {
1143            let data: serde_json::Result<OldMan> = serde_json::from_str(&entry);
1144            let data = data.unwrap();
1145            computed.push(data);
1146        };
1147        assert_eq!(computed, vec![expected.clone()]);
1148
1149        let _ = remove_dir_all(&index_path);
1150        let _ = remove_dir_all(home);
1151    }
1152
1153    #[test]
1154    fn validate_as_rust_structs() {
1155        let name = random_string(None);
1156        let home = ".validate_as_rust_structs".to_string();
1157        let index_path = format!("{}/{}", home, name);
1158        let path = Path::new(&index_path);
1159        assert!(!path.exists());
1160
1161        let title = "The Old Man and the Sea".to_string();
1162        let body = "He was an old man who fished alone in a skiff in the Gulf Stream and he had gone eighty-four days now without taking a fish.".to_string();
1163        let old_man_doc = OldMan {
1164            title,
1165            body,
1166        };
1167
1168
1169        let mut builder = SurferBuilder::default();
1170        builder.set_home(home.as_str());
1171        builder.add_struct(name.to_string(), &old_man_doc);
1172        let mut surfer = Surfer::new(builder);
1173
1174        let _ = surfer.insert_struct(&name, &old_man_doc).unwrap();
1175        let query = "sea whale";
1176
1177        let result = surfer.read_structs::<OldMan>("non-existent", query, None, None);
1178        assert!(result.is_ok());
1179        let result = result.unwrap();
1180        assert!(result.is_none());
1181
1182        let result = surfer.read_structs::<OldMan>(&name, query, None, None).unwrap().unwrap();
1183        for computed in result {
1184            assert_eq!(computed, old_man_doc);
1185        };
1186        assert!(path.exists());
1187
1188        // Reading documents again
1189
1190        let result = surfer.read_structs::<OldMan>(&name, query, None, None).unwrap().unwrap();
1191        for computed in result {
1192            assert_eq!(computed, old_man_doc);
1193        };
1194
1195
1196        let _ = remove_dir_all(index_path);
1197        let _ = remove_dir_all(home);
1198    }
1199
1200    #[test]
1201    fn validate_initialize_mmap() {
1202        let home = ".validate_initialize_mmap";
1203        let index_name = "someindex";
1204        let path_to_index = ".validate_initialize_mmap/someindex";
1205        let path = Path::new(path_to_index);
1206        assert!(!path.exists());
1207        let oldman = OldMan::default();
1208        let (schema, mappings) = to_schema(&oldman, None).unwrap();
1209        let schema = SurferSchema::new(schema, mappings, false, false);
1210        let _ = initialize_mmap(index_name, home, &schema);
1211        assert!(path.exists());
1212        let _ = std::fs::remove_dir_all(path_to_index);
1213
1214        let _ = remove_dir_all(path_to_index);
1215        let _ = remove_dir_all(index_name);
1216        let _ = remove_dir_all(home);
1217    }
1218
1219    #[test]
1220    fn validate_read_existing_documents_as_structs_limit_one() {
1221        let name = random_string(None);
1222        let home = ".validate_read_existing_documents_as_structs_limit_one";
1223        let index_path = format!("{}/{}", home, name);
1224        let path = Path::new(&index_path);
1225        assert!(!path.exists());
1226
1227        let data = OldMan::default();
1228
1229        let mut builder = SurferBuilder::default();
1230        builder.set_home(home);
1231        builder.add_struct(name.clone(), &data);
1232
1233        let title = "The Old Man and the Sea".to_string();
1234        let body = "He was an old man who fished alone in a skiff in the Gulf Stream and he had gone eighty-four days now without taking a fish.".to_string();
1235        let old_man_doc = OldMan {
1236            title,
1237            body,
1238        };
1239
1240        let mut surfer = Surfer::new(builder.clone());
1241        let _ = surfer.insert_struct(&name, &old_man_doc).unwrap();
1242        let _ = surfer.insert_struct(&name, &old_man_doc).unwrap();
1243        let _ = surfer.insert_struct(&name, &old_man_doc).unwrap();
1244        let _ = surfer.insert_struct(&name, &old_man_doc).unwrap();
1245        let _ = surfer.insert_struct(&name, &old_man_doc).unwrap();
1246
1247        let query = "sea whale";
1248        let result = surfer.read_structs::<OldMan>(&name, query, None, None);
1249        assert!(result.is_ok());
1250        let result = result.unwrap().unwrap();
1251        assert_eq!(result.len(), 5);
1252
1253        let result = surfer.read_structs::<OldMan>(&name, query, Some(1), None);
1254        assert!(result.is_ok());
1255        let result = result.unwrap().unwrap();
1256        assert_eq!(result.len(), 1);
1257
1258        assert!(path.exists());
1259        let _ = remove_dir_all(index_path);
1260        let _ = remove_dir_all(home);
1261    }
1262
1263    #[test]
1264    fn validate_read_existing_documents_as_structs_default_ten() {
1265        let name = random_string(None);
1266        let home = ".validate_read_existing_documents_as_structs_default_ten";
1267        let index_path = format!("{}/{}", home, name);
1268        let path = Path::new(&index_path);
1269        assert!(!path.exists());
1270
1271        let data = OldMan::default();
1272
1273        let mut builder = SurferBuilder::default();
1274        builder.set_home(home);
1275        builder.add_struct(name.clone(), &data);
1276
1277        let title = "The Old Man and the Sea".to_string();
1278        let body = "He was an old man who fished alone in a skiff in the Gulf Stream and he had gone eighty-four days now without taking a fish.".to_string();
1279        let old_man_doc = OldMan {
1280            title,
1281            body,
1282        };
1283
1284        let mut surfer = Surfer::new(builder.clone());
1285        for _ in 0..20 {
1286            let _ = surfer.insert_struct(&name, &old_man_doc).unwrap();
1287        }
1288
1289
1290        let query = "sea whale";
1291        let result = surfer.read_structs::<OldMan>(&name, query, None, None);
1292        assert!(result.is_ok());
1293        let result = result.unwrap().unwrap();
1294        assert_eq!(result.len(), 10);
1295
1296        let result = surfer.read_structs::<OldMan>(&name, query, Some(20), None);
1297        assert!(result.is_ok());
1298        let result = result.unwrap().unwrap();
1299        assert_eq!(result.len(), 20);
1300
1301        assert!(path.exists());
1302        let _ = remove_dir_all(index_path);
1303        let _ = remove_dir_all(home);
1304    }
1305
1306    #[derive(Serialize, Deserialize)]
1307    struct Dummy {
1308        x: String,
1309        y: String,
1310        z: u64,
1311    }
1312
1313    #[test]
1314    fn check_invalid_index_name() {
1315        let home = random_string(None);
1316        let data = Dummy {
1317            x: "X".to_owned(),
1318            y: "Y".to_owned(),
1319            z: 100u64,
1320        };
1321        let mut builder = SurferBuilder::default();
1322        builder.set_home(&home);
1323        builder.add_struct("dummy".to_string(), &data);
1324        let surfer = Surfer::try_from(builder).unwrap();
1325        let computed = surfer.which_index("crap");
1326        assert!(computed.is_none());
1327        let home = Path::new(&home);
1328        assert!(home.exists());
1329        let index_path = surfer.which_index("dummy").unwrap();
1330        let _ = remove_dir_all(&index_path);
1331        let _ = remove_dir_all(&home);
1332    }
1333
1334    #[test]
1335    fn check_invalid_index_insert() {
1336        let home = random_string(None);
1337        let data = Dummy {
1338            x: "X".to_owned(),
1339            y: "Y".to_owned(),
1340            z: 100u64,
1341        };
1342        let mut builder = SurferBuilder::default();
1343        builder.set_home(&home);
1344        builder.add_struct("dummy".to_string(), &data);
1345        let mut surfer = Surfer::try_from(builder).unwrap();
1346        let data = vec![data];
1347        let computed = surfer.insert_structs("crap", &data);
1348        assert!(computed.is_ok());
1349        let index_path = surfer.which_index("dummy").unwrap();
1350        let _ = remove_dir_all(&index_path);
1351        let _ = remove_dir_all(&home);
1352    }
1353
1354    #[test]
1355    fn check_invalid_index_lookup() {
1356        let name = random_string(None);
1357        let home = ".check_invalid_index_lookup";
1358        let index_path = format!("{}/{}", home, name);
1359        let path = Path::new(&index_path);
1360        assert!(!path.exists());
1361
1362
1363        let data = Dummy {
1364            x: "X".to_owned(),
1365            y: "Y".to_owned(),
1366            z: 100u64,
1367        };
1368        let mut builder = SurferBuilder::default();
1369        builder.set_home(&home);
1370        let mut surfer = Surfer::try_from(builder).unwrap();
1371        let _ = surfer.insert_struct("dummy", &data).unwrap();
1372        let computed = surfer.read_structs::<Dummy>("crap", "X", None, None);
1373        assert!(computed.is_ok());
1374        let computed = computed.unwrap();
1375        assert!(computed.is_none());
1376        let _ = remove_dir_all(&path);
1377        let _ = remove_dir_all(&home);
1378    }
1379
1380    #[test]
1381    fn validate_surfer_schema() {
1382        let data = Dummy {
1383            x: "X".to_owned(),
1384            y: "Y".to_owned(),
1385            z: 100u64,
1386        };
1387
1388        let data = utils::as_value(&data).unwrap();
1389        let (schema, mappings) = utils::to_schema(&data, None).unwrap();
1390        let surf_schema = SurferSchema::new(schema, mappings, false, false);
1391
1392        let mut computed1 = SurferBuilder::default();
1393        computed1.add_schema("dummy".to_string(), surf_schema.clone());
1394
1395        let mut computed2 = SurferBuilder::default();
1396        computed2.add_struct("dummy".to_string(), &data);
1397
1398        assert_eq!(computed1, computed2);
1399
1400        assert_eq!(format!("{:?}", computed1.schemas), format!("{:?}", computed2.schemas))
1401    }
1402
1403    // Main struct
1404    #[derive(Serialize, Debug, Deserialize, PartialEq, PartialOrd, Clone)]
1405    struct UserInfo {
1406        first: String,
1407        last: String,
1408        age: u8,
1409    }
1410
1411    impl UserInfo {
1412        pub fn new(first: String, last: String, age: u8) -> Self {
1413            Self {
1414                first,
1415                last,
1416                age,
1417            }
1418        }
1419    }
1420
1421    impl Default for UserInfo {
1422        fn default() -> Self {
1423            let first = "".to_string();
1424            let last = "".to_string();
1425            let age = 0u8;
1426            UserInfo::new(first, last, age)
1427        }
1428    }
1429
1430    #[test]
1431    fn test_user_info() {
1432        // Specify home location for indexes
1433        let home = ".test_user_info".to_string();
1434        // Specify index name
1435        let index_name = "store".to_string();
1436
1437        // Prepare builder
1438        let mut builder = SurferBuilder::default();
1439        builder.set_home(&home);
1440
1441        let data = UserInfo::default();
1442        builder.add_struct(index_name.clone(), &data);
1443
1444        // Prepare Surfer
1445        let mut surfer = Surfer::try_from(builder).unwrap();
1446
1447        // Prepare data to insert & search
1448
1449        // User 1: John Doe
1450        let first = "John".to_string();
1451        let last = "Doe".to_string();
1452        let age = 20u8;
1453        let john_doe = UserInfo::new(first, last, age);
1454
1455        // User 2: Jane Doe
1456        let first = "Jane".to_string();
1457        let last = "Doe".to_string();
1458        let age = 18u8;
1459        let jane_doe = UserInfo::new(first, last, age);
1460
1461        // User 3: Jonny Doe
1462        let first = "Jonny".to_string();
1463        let last = "Doe".to_string();
1464        let age = 10u8;
1465        let jonny_doe = UserInfo::new(first, last, age);
1466
1467        // User 4: Jinny Doe
1468        let first = "Jinny".to_string();
1469        let last = "Doe".to_string();
1470        let age = 10u8;
1471        let jinny_doe = UserInfo::new(first, last, age);
1472
1473        // Writing structs
1474
1475        // Option 1: One struct at a time
1476        let _ = surfer.insert_struct(&index_name, &john_doe).unwrap();
1477        let _ = surfer.insert_struct(&index_name, &jane_doe).unwrap();
1478
1479        // Option 2: Write all structs together
1480        let users = vec![jonny_doe.clone(), jinny_doe.clone()];
1481        let _ = surfer.insert_structs(&index_name, &users).unwrap();
1482
1483        block_thread(1);
1484
1485        // Reading structs
1486
1487        // Option 1: Full text search
1488        let expected = vec![john_doe.clone()];
1489        let computed = surfer.read_all_structs::<UserInfo>(&index_name, "John").unwrap().unwrap();
1490        assert_eq!(expected, computed);
1491
1492        let mut expected = vec![john_doe.clone(), jane_doe.clone(), jonny_doe.clone(), jinny_doe.clone()];
1493        expected.sort();
1494        let mut computed = surfer.read_all_structs::<UserInfo>(&index_name, "doe").unwrap().unwrap();
1495        computed.sort();
1496        assert_eq!(expected, computed);
1497
1498        // Option 2: Term search
1499        let mut expected = vec![jonny_doe.clone(), jinny_doe.clone()];
1500        expected.sort();
1501        let mut computed = surfer.read_all_structs_by_field::<UserInfo>(&index_name, "age", "10").unwrap().unwrap();
1502        computed.sort();
1503        assert_eq!(expected, computed);
1504
1505        // Delete structs
1506
1507        // Option 1: Delete based on all text fields
1508        // Before delete
1509        let before = surfer.read_all_structs::<UserInfo>(&index_name, "doe").unwrap().unwrap();
1510        let before: HashSet<UserInfo> = HashSet::from_iter(before.into_iter());
1511
1512        // Delete any occurrence of John (Actual call to delete)
1513        surfer.delete_structs(&index_name, "john").unwrap();
1514
1515        // After delete
1516        let after = surfer.read_all_structs::<UserInfo>(&index_name, "doe").unwrap().unwrap();
1517        let after: HashSet<UserInfo> = HashSet::from_iter(after.into_iter());
1518        // Check difference
1519        let computed: Vec<UserInfo> = before.difference(&after).map(|e| e.clone()).collect();
1520        // Only John should be deleted
1521        let expected = vec![john_doe];
1522        assert_eq!(expected, computed);
1523
1524        // Option 2: Delete based on a specific field
1525        // Before delete
1526        let before = surfer.read_all_structs_by_field::<UserInfo>(&index_name, "age", "10").unwrap().unwrap();
1527        let before: HashSet<UserInfo> = HashSet::from_iter(before.into_iter());
1528
1529        // Delete any occurrence where age = 10 (Actual call to delete)
1530        surfer.delete_structs_by_field(&index_name, "age", "10").unwrap();
1531
1532        // After delete
1533        let after = surfer.read_all_structs_by_field::<UserInfo>(&index_name, "age", "10").unwrap().unwrap();
1534        let after: HashSet<UserInfo> = HashSet::from_iter(after.into_iter());
1535        // Check difference
1536        let mut computed: Vec<UserInfo> = before.difference(&after).map(|e| e.clone()).collect();
1537        computed.sort();
1538        // Both Jonny & Jinny should be deleted
1539        let mut expected = vec![jonny_doe, jinny_doe];
1540        expected.sort();
1541        assert_eq!(expected, computed);
1542
1543
1544        // Clean-up
1545        let path = surfer.which_index(&index_name).unwrap();
1546        let _ = remove_dir_all(&path);
1547        let _ = remove_dir_all(&home);
1548    }
1549
1550    #[test]
1551    fn test_where_clause() {
1552        // Specify home location for indexes
1553        let home = ".test_where_clause".to_string();
1554        // Specify index name
1555        let index_name = "store".to_string();
1556
1557        // Prepare builder
1558        let mut builder = SurferBuilder::default();
1559        builder.set_home(&home);
1560
1561        let data = UserInfo::default();
1562        builder.add_struct(index_name.clone(), &data);
1563
1564        // Prepare Surfer
1565        let surfer = Surfer::try_from(builder).unwrap();
1566        let mut surf = Surf::from(surfer);
1567        let surfer = &mut surf;
1568
1569        // Prepare data to insert & search
1570
1571        // User 1: John Doe
1572        let first = "John".to_string();
1573        let last = "Doe".to_string();
1574        let age = 20u8;
1575        let john_doe = UserInfo::new(first, last, age);
1576
1577        // User 2: Jane Doe
1578        let first = "Jane".to_string();
1579        let last = "Doe".to_string();
1580        let age = 18u8;
1581        let jane_doe = UserInfo::new(first, last, age);
1582
1583        // User 3: Jonny Doe
1584        let first = "Jonny".to_string();
1585        let last = "Doe".to_string();
1586        let age = 10u8;
1587        let jonny_doe = UserInfo::new(first, last, age);
1588
1589        // User 4: Jinny Doe
1590        let first = "Jinny".to_string();
1591        let last = "Doe".to_string();
1592        let age = 10u8;
1593        let jinny_doe = UserInfo::new(first, last, age);
1594
1595        // Writing structs
1596
1597        let users = vec![john_doe.clone(), jane_doe.clone(), jonny_doe.clone(), jinny_doe.clone()];
1598        let _ = surfer.insert_structs(&index_name, &users).unwrap();
1599        block_thread(1);
1600
1601        let conditions = vec![OrCondition::from(("age".to_string(), "10".to_string()))];
1602        let mut expected = vec![jonny_doe.clone(), jinny_doe.clone()];
1603        let mut computed = surfer.select::<UserInfo>(&index_name, &conditions).unwrap().unwrap();
1604        expected.sort();
1605        computed.sort();
1606        assert_eq!(expected, computed);
1607
1608        let conditions = vec![OrCondition::from(("age".to_string(), "10".to_string())),
1609                              OrCondition::from(("first".to_string(), "john".to_string()))];
1610        let mut expected = vec![john_doe.clone(), jonny_doe.clone(), jinny_doe.clone()];
1611        let mut computed = surfer.select::<UserInfo>(&index_name, &conditions).unwrap().unwrap();
1612        expected.sort();
1613        computed.sort();
1614        assert_eq!(expected, computed);
1615
1616
1617        let name_condition = AndCondition::new("first".to_string(), "jinny".to_string());
1618        let age_condition = AndCondition::new("age".to_string(), "10".to_string());
1619        let and_conditions = vec![name_condition, age_condition];
1620        let child_condition = OrCondition::new(and_conditions);
1621        let parent_condition = OrCondition::from(("first".to_string(), "john".to_string()));
1622        let conditions = vec![child_condition, parent_condition];
1623
1624        let mut expected = vec![john_doe.clone(), jinny_doe.clone()];
1625        let mut computed = surfer.select::<UserInfo>(&index_name, &conditions).unwrap().unwrap();
1626        expected.sort();
1627        computed.sort();
1628        assert_eq!(expected, computed);
1629
1630        // Clean-up
1631        let path = surfer.which_index(&index_name).unwrap();
1632        let _ = remove_dir_all(&path);
1633        let _ = remove_dir_all(&home);
1634    }
1635
1636    /// Convenience method for sorting & likely not required in user code
1637    impl Ord for UserInfo {
1638        fn cmp(&self, other: &Self) -> Ordering {
1639            if self.first == other.first && self.last == other.last {
1640                return Ordering::Equal;
1641            };
1642            if self.first == other.first {
1643                if self.last > other.last {
1644                    Ordering::Greater
1645                } else {
1646                    Ordering::Less
1647                }
1648            } else {
1649                if self.first > other.first {
1650                    Ordering::Greater
1651                } else {
1652                    Ordering::Less
1653                }
1654            }
1655        }
1656    }
1657
1658    /// Convenience method for sorting & likely not required in user code
1659    impl Eq for UserInfo {}
1660
1661    /// Convenience method for sorting & likely not required in user code
1662    impl Hash for UserInfo {
1663        fn hash<H: Hasher>(&self, state: &mut H) {
1664            for i in self.first.as_bytes() {
1665                state.write_u8(*i);
1666            }
1667            for i in self.last.as_bytes() {
1668                state.write_u8(*i);
1669            }
1670            state.write_u8(self.age);
1671            state.finish();
1672        }
1673    }
1674}