1//! These types are not used for generating `Index`es. They are provided to help with
2//! creating compatible JSON structures for configuring the JavaScript search
3//! function.
4//!
5//! *Reference:*
6//! <http://elasticlunr.com/docs/configuration.js.html>
7
8use std::collections::BTreeMap;
9
10/// Used to set the search configuration for a specific field.
11/// When `expand` or `bool` is `None`, elasticlunr.js will use the value from
12/// the global configuration. The `boost` field, if present,
13/// increases the importance of this field when ordering search results.
14#[derive(Serialize, Deserialize, Default, Debug, Copy, Clone, Eq, PartialEq)]
15pub struct SearchOptionsField {
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub boost: Option<u8>,
18 #[serde(skip_serializing_if = "Option::is_none")]
19 pub bool: Option<SearchBool>,
20 #[serde(skip_serializing_if = "Option::is_none")]
21 pub expand: Option<bool>,
22}
23
24/// Sets which boolean model is used for searching with
25/// multiple terms. Defaults to `Or`.
26///
27/// - *AND* requires every search term to be present in results
28/// - *OR* accepts results which have at least one term
29///
30#[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq)]
31#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
32pub enum SearchBool {
33 Or,
34 And,
35}
36
37impl Default for SearchBool {
38 fn default() -> Self {
39 SearchBool::Or
40 }
41}
42
43/// The search configuration map which is passed to the
44/// elasticlunr.js `Index.search()` function.
45///
46/// |Key |Default|
47/// |--------|-------|
48/// |`bool` |`OR` |
49/// |`expand`|`false`|
50#[derive(Serialize, Deserialize, Default, Debug, Clone, Eq, PartialEq)]
51pub struct SearchOptions {
52 pub bool: SearchBool,
53 pub expand: bool,
54 pub fields: BTreeMap<String, SearchOptionsField>,
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60 use serde_json;
61
62 #[test]
63 fn test_normal_config() {
64 let options = SearchOptions {
65 fields: btreemap![
66 "title".into() => SearchOptionsField {
67 boost: Some(5),
68 ..Default::default()
69 },
70 "body".into() => SearchOptionsField {
71 boost: Some(1),
72 ..Default::default()
73 },
74 ],
75 ..Default::default()
76 };
77 let stringed = serde_json::to_string(&options).unwrap();
78
79 assert_eq!(
80 stringed,
81 r#"{"bool":"OR","expand":false,"fields":{"body":{"boost":1},"title":{"boost":5}}}"#
82 );
83 }
84
85 #[test]
86 fn test_complex_config() {
87 let options = SearchOptions {
88 fields: btreemap! {
89 "title".into() => SearchOptionsField {
90 expand: Some(true),
91 ..Default::default()
92 },
93 "body".into() => SearchOptionsField {
94 bool: Some(SearchBool::Or),
95 ..Default::default()
96 },
97 "breadcrumbs".into() => SearchOptionsField {
98 bool: Some(SearchBool::default()),
99 boost: Some(200),
100 ..Default::default()
101 },
102 },
103 expand: false,
104 bool: SearchBool::And,
105 };
106 let stringed = serde_json::to_string_pretty(&options).unwrap();
107
108 assert_eq!(
109 stringed,
110 r#"{
111 "bool": "AND",
112 "expand": false,
113 "fields": {
114 "body": {
115 "bool": "OR"
116 },
117 "breadcrumbs": {
118 "boost": 200,
119 "bool": "OR"
120 },
121 "title": {
122 "expand": true
123 }
124 }
125}"#
126 );
127 }
128}
129