elasticsearch-facetedsearch 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +18 -0
- data/README.md +216 -0
- data/Rakefile +8 -0
- data/lib/elasticsearch/faceted_search.rb +15 -0
- data/lib/elasticsearch/faceted_search/facet_base.rb +184 -0
- data/lib/elasticsearch/faceted_search/facet_group.rb +101 -0
- data/lib/elasticsearch/faceted_search/facet_item.rb +105 -0
- data/lib/elasticsearch/faceted_search/pagination.rb +27 -0
- data/lib/elasticsearch/faceted_search/sortable.rb +62 -0
- data/lib/elasticsearch/faceted_search/version.rb +5 -0
- data/spec/lib/elasticsearch/faceted_search/facet_base_spec.rb +256 -0
- data/spec/lib/elasticsearch/faceted_search/facet_group_spec.rb +208 -0
- data/spec/lib/elasticsearch/faceted_search/facet_item_spec.rb +201 -0
- data/spec/lib/elasticsearch/faceted_search/pagination_spec.rb +52 -0
- data/spec/lib/elasticsearch/faceted_search/sortable_spec.rb +128 -0
- data/spec/spec_helper.rb +15 -0
- metadata +150 -0
@@ -0,0 +1,208 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Elasticsearch
|
4
|
+
module FacetedSearch
|
5
|
+
describe FacetGroup do
|
6
|
+
let(:objects) { {"_type"=>"terms", "missing"=>0, "total"=>476, "other"=>0, "terms"=>[{"term"=>"t", "count"=>476}, {"term"=>"f", "count"=>5}, {"term"=>"F", "count"=>476}]} }
|
7
|
+
let(:key) { 'hd' }
|
8
|
+
let(:search) { Object.new }
|
9
|
+
let(:model) { described_class.new(search, key, objects) }
|
10
|
+
|
11
|
+
describe "#initializer" do
|
12
|
+
it "sets search" do
|
13
|
+
expect(model.search).to eq(search)
|
14
|
+
end
|
15
|
+
it "symbolizes the key" do
|
16
|
+
expect(key).to be_a(String)
|
17
|
+
expect(model.key).to eq(:hd)
|
18
|
+
end
|
19
|
+
it "sets the objects from the terms key" do
|
20
|
+
expect(model.objects).to eq({"t"=>476, "f"=>481})
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#items" do
|
25
|
+
it "builds the items" do
|
26
|
+
expect(model).to receive(:build_items).and_call_original
|
27
|
+
model.items
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#title" do
|
32
|
+
it "returns title set in class" do
|
33
|
+
expect(search).to receive(:class_facets) { {hd: {title: 'HD Media'}} }
|
34
|
+
expect(model.title).to eq('HD Media')
|
35
|
+
end
|
36
|
+
it "returns the key humanized if no key exists" do
|
37
|
+
expect(search).to receive(:class_facets) { {} }
|
38
|
+
expect(model.title).to eq('Hd')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "#selected_values" do
|
43
|
+
describe ":and" do
|
44
|
+
before(:each) do
|
45
|
+
expect(model).to receive(:operator).at_least(:once) { ',' }
|
46
|
+
end
|
47
|
+
it "returns array of selected items" do
|
48
|
+
expect(search).to receive(:search_params) { {hd: 'F,T'} }
|
49
|
+
expect(model.selected_values).to eq(['f','t'])
|
50
|
+
end
|
51
|
+
it "returns nothing when no key exists" do
|
52
|
+
expect(search).to receive(:search_params) { {hello: '1,2'} }
|
53
|
+
expect(model.selected_values).to eq([])
|
54
|
+
end
|
55
|
+
pending "only returns valid keys" do
|
56
|
+
expect(search).to receive(:search_params) { {hd: 'F,T,L'} }
|
57
|
+
expect(model.selected_values).to eq(['f','t'])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe ":or" do
|
62
|
+
before(:each) do
|
63
|
+
expect(model).to receive(:operator).at_least(:once) { '|' }
|
64
|
+
end
|
65
|
+
it "returns array of selected items" do
|
66
|
+
expect(search).to receive(:search_params) { {hd: 'F|T'} }
|
67
|
+
expect(model.selected_values).to eq(['f','t'])
|
68
|
+
end
|
69
|
+
it "returns nothing when no key exists" do
|
70
|
+
expect(search).to receive(:search_params) { {hello: '1|2'} }
|
71
|
+
expect(model.selected_values).to eq([])
|
72
|
+
end
|
73
|
+
pending "only returns valid keys" do
|
74
|
+
expect(search).to receive(:search_params) { {hd: 'F|T|L'} }
|
75
|
+
expect(model.selected_values).to eq(['f','t'])
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "nil" do
|
80
|
+
before(:each) do
|
81
|
+
expect(model).to receive(:operator).at_least(:once) { nil }
|
82
|
+
end
|
83
|
+
it "returns array of selected items" do
|
84
|
+
expect(search).to receive(:search_params) { {hd: 'F|T'} }
|
85
|
+
expect(model.selected_values).to eq('f|t')
|
86
|
+
end
|
87
|
+
it "returns nothing when no key exists" do
|
88
|
+
expect(search).to receive(:search_params) { {hello: '1|2'} }
|
89
|
+
expect(model.selected_values).to eq('')
|
90
|
+
end
|
91
|
+
pending "only returns valid keys" do
|
92
|
+
expect(search).to receive(:search_params) { {hd: 'F|T|L'} }
|
93
|
+
expect(model.selected_values).to eq('f|t')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#group_params" do
|
99
|
+
describe ":and" do
|
100
|
+
before(:each) do
|
101
|
+
expect(model).to receive(:operator) { ',' }
|
102
|
+
end
|
103
|
+
|
104
|
+
it "returns empty string when no key exists" do
|
105
|
+
expect(search).to receive(:search_params) { {} }
|
106
|
+
expect(model.group_params).to eq([])
|
107
|
+
end
|
108
|
+
it "fetches the groups key" do
|
109
|
+
expect(search).to receive(:search_params) { {hd: '1,3', another: '2'} }
|
110
|
+
expect(model.group_params).to eq(['1','3'])
|
111
|
+
end
|
112
|
+
end
|
113
|
+
describe ":or" do
|
114
|
+
before(:each) do
|
115
|
+
expect(model).to receive(:operator) { '|' }
|
116
|
+
end
|
117
|
+
|
118
|
+
it "returns empty string when no key exists" do
|
119
|
+
expect(search).to receive(:search_params) { {} }
|
120
|
+
expect(model.group_params).to eq([])
|
121
|
+
end
|
122
|
+
it "fetches the groups key" do
|
123
|
+
expect(search).to receive(:search_params) { {hd: '1|3', another: '2'} }
|
124
|
+
expect(model.group_params).to eq(['1','3'])
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe "#group_params_string" do
|
130
|
+
it "returns empty string when no key exists" do
|
131
|
+
expect(search).to receive(:search_params) { {} }
|
132
|
+
expect(model.group_params_string).to eq('')
|
133
|
+
end
|
134
|
+
it "fetches the groups key" do
|
135
|
+
expect(search).to receive(:search_params) { {hd: '1', another: '2'} }
|
136
|
+
expect(model.group_params_string).to eq('1')
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "#type" do
|
141
|
+
it "returns the class_facets's #type" do
|
142
|
+
expect(search).to receive(:class_facets) { {hd: {type: 'exclusive_or'}} }
|
143
|
+
expect(model.type).to eq('exclusive_or')
|
144
|
+
end
|
145
|
+
it "returns nil if raised" do
|
146
|
+
expect(search).to receive(:class_facets) { raise "Boom!" }
|
147
|
+
expect(model.type).to be_nil
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "#operator" do
|
152
|
+
it "returns nil with a bad key" do
|
153
|
+
expect(model).to receive(:operator_for) { }
|
154
|
+
expect(model.operator).to be_nil
|
155
|
+
end
|
156
|
+
it "returns , for :and" do
|
157
|
+
expect(model).to receive(:operator_for) { :and }
|
158
|
+
expect(model.operator).to eq(',')
|
159
|
+
end
|
160
|
+
it "returns | for :or" do
|
161
|
+
expect(model).to receive(:operator_for) { :or }
|
162
|
+
expect(model.operator).to eq('|')
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "#build_items" do
|
167
|
+
it "is private" do
|
168
|
+
expect {
|
169
|
+
model.build_items
|
170
|
+
}.to raise_error(NoMethodError)
|
171
|
+
end
|
172
|
+
it "returns a group of FacetItems" do
|
173
|
+
expect(model.send(:build_items).all?{|x| x.is_a?(Elasticsearch::FacetedSearch::FacetItem)}).to eq(true)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe "#terms_collection" do
|
178
|
+
it "is private" do
|
179
|
+
expect {
|
180
|
+
model.terms_collection
|
181
|
+
}.to raise_error(NoMethodError)
|
182
|
+
end
|
183
|
+
it "returns mapped_objects if search does not respond to 'key'_collection?" do
|
184
|
+
expect(model).to receive(:mapped_objects) { 'hi' }
|
185
|
+
expect(model.send(:terms_collection)).to eq('hi')
|
186
|
+
end
|
187
|
+
it "returns collection from facet" do
|
188
|
+
expect(search).to receive(:hd_collection) { [{id: 1}, {id: 2}] }
|
189
|
+
expect(model.send(:terms_collection)).to eq([{id: 1}, {id: 2}])
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe "#hit_count_mapping" do
|
194
|
+
before(:each) do
|
195
|
+
@items = [{"term"=>"t", "count"=>476}, {"term"=>"f", "count"=>5}, {"term"=>"F", "count"=>476}]
|
196
|
+
end
|
197
|
+
it "is private" do
|
198
|
+
expect {
|
199
|
+
model.hit_count_mapping(@items)
|
200
|
+
}.to raise_error(NoMethodError)
|
201
|
+
end
|
202
|
+
it "returns merged hashes" do
|
203
|
+
expect(model.send(:hit_count_mapping, @items)).to eq({"t"=>476, "f"=>481})
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Elasticsearch
|
4
|
+
module FacetedSearch
|
5
|
+
describe FacetItem do
|
6
|
+
let(:item) { {id: 't', term: "Yes", count: 476} }
|
7
|
+
let(:key) { :hd }
|
8
|
+
let(:group) { Object.new }
|
9
|
+
let(:model) { described_class.new(group, item) }
|
10
|
+
let(:mappings) { Elasticsearch::FacetedSearch::FacetGroup::OPERATOR_MAPPING }
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
allow(group).to receive(:key) { key }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#initialize" do
|
17
|
+
it "sets #group" do
|
18
|
+
expect(model.group).to eq(group)
|
19
|
+
end
|
20
|
+
it "sets #object" do
|
21
|
+
expect(model.object.id).to eq(item[:id])
|
22
|
+
expect(model.object.term).to eq(item[:term])
|
23
|
+
expect(model.object.count).to eq(item[:count])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#selected?" do
|
28
|
+
describe "as string" do
|
29
|
+
before(:each) do
|
30
|
+
expect(group).to receive(:group_params) { 't' }
|
31
|
+
end
|
32
|
+
|
33
|
+
it "returns true when id matches" do
|
34
|
+
expect(model.id).to eq('t')
|
35
|
+
expect(model.selected?).to eq(true)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "returns false when id is not found" do
|
39
|
+
expect(model).to receive(:id) { 'fff' }
|
40
|
+
expect(model.selected?).to eq(false)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
describe "as array" do
|
45
|
+
before(:each) do
|
46
|
+
expect(group).to receive(:group_params) { ['f','t'] }
|
47
|
+
end
|
48
|
+
it "returns true when id matches" do
|
49
|
+
expect(model.selected?).to eq(true)
|
50
|
+
end
|
51
|
+
it "returns false when id is not found" do
|
52
|
+
expect(model).to receive(:id) { 'fff' }
|
53
|
+
expect(model.selected?).to eq(false)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#params_for" do
|
59
|
+
describe ":unselected" do
|
60
|
+
before(:each) do
|
61
|
+
expect(group).to receive(:group_params).at_least(:once) { ['f'] }
|
62
|
+
allow(group).to receive(:operator_mappings) { '|' }
|
63
|
+
end
|
64
|
+
it "calls add_multivalue when 'multivalue'" do
|
65
|
+
expect(group).to receive(:type) { 'multivalue' }
|
66
|
+
expect(model).to receive(:add_multivalue).and_call_original
|
67
|
+
model.params_for
|
68
|
+
end
|
69
|
+
it "calls add_multivalue(:and) when 'multivalue_and'" do
|
70
|
+
expect(group).to receive(:type) { 'multivalue_and' }
|
71
|
+
expect(model).to receive(:add_multivalue).with(:and).and_call_original
|
72
|
+
model.params_for
|
73
|
+
end
|
74
|
+
it "calls add_multivalue(:or) when 'multivalue_or'" do
|
75
|
+
expect(group).to receive(:type) { 'multivalue_or' }
|
76
|
+
expect(model).to receive(:add_multivalue).with(:or).and_call_original
|
77
|
+
model.params_for
|
78
|
+
end
|
79
|
+
it "calls add_singlevalue when 'exclusive_or'" do
|
80
|
+
expect(group).to receive(:type) { 'exclusive_or' }
|
81
|
+
expect(model).to receive(:add_singlevalue).and_call_original
|
82
|
+
model.params_for
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe ":selected" do
|
87
|
+
before(:each) do
|
88
|
+
expect(group).to receive(:group_params).at_least(:once) { ['f','t'] }
|
89
|
+
allow(group).to receive(:operator_mappings) { '|' }
|
90
|
+
end
|
91
|
+
it "calls remove_multivalue when 'multivalue'" do
|
92
|
+
expect(group).to receive(:type) { 'multivalue' }
|
93
|
+
expect(model).to receive(:remove_multivalue).and_call_original
|
94
|
+
model.params_for
|
95
|
+
end
|
96
|
+
it "calls remove_multivalue(:and) when 'multivalue_and'" do
|
97
|
+
expect(group).to receive(:type) { 'multivalue_and' }
|
98
|
+
expect(model).to receive(:remove_multivalue).with(:and).and_call_original
|
99
|
+
model.params_for
|
100
|
+
end
|
101
|
+
it "calls remove_multivalue(:or) when 'multivalue_or'" do
|
102
|
+
expect(group).to receive(:type) { 'multivalue_or' }
|
103
|
+
expect(model).to receive(:remove_multivalue).with(:or).and_call_original
|
104
|
+
model.params_for
|
105
|
+
end
|
106
|
+
it "calls remove_singlevalue when 'exclusive_or'" do
|
107
|
+
expect(group).to receive(:type) { 'exclusive_or' }
|
108
|
+
expect(model).to receive(:remove_singlevalue).and_call_original
|
109
|
+
model.params_for
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "#remove_multivalue" do
|
115
|
+
describe ":and" do
|
116
|
+
it "moves a value but keeps the rest" do
|
117
|
+
expect(group).to receive(:operator_mappings).with(:and) { mappings[:and] }
|
118
|
+
expect(group).to receive(:group_params) { ['1','2','3'] }
|
119
|
+
expect(model).to receive(:id).at_least(:once) { 1 }
|
120
|
+
expect(model.send(:remove_multivalue, :and)).to eq({hd: "2#{mappings[:and]}3"})
|
121
|
+
end
|
122
|
+
it "returns an empty hash if params is empty" do
|
123
|
+
expect(group).to receive(:operator_mappings) { mappings[:and] }
|
124
|
+
expect(group).to receive(:group_params) { ['1'] }
|
125
|
+
expect(model).to receive(:id).at_least(:once) { 1 }
|
126
|
+
expect(model.send(:remove_multivalue, :and)).to eq({hd: nil})
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe ":or" do
|
131
|
+
it "moves a value but keeps the rest" do
|
132
|
+
expect(group).to receive(:operator_mappings).with(:or) { mappings[:or] }
|
133
|
+
expect(group).to receive(:group_params) { ['1','2','3'] }
|
134
|
+
expect(model).to receive(:id).at_least(:once) { 1 }
|
135
|
+
expect(model.send(:remove_multivalue, :or)).to eq({hd: "2#{mappings[:or]}3"})
|
136
|
+
end
|
137
|
+
it "returns an empty hash if params is empty" do
|
138
|
+
expect(group).to receive(:operator_mappings) { mappings[:and] }
|
139
|
+
expect(group).to receive(:group_params) { ['1'] }
|
140
|
+
expect(model).to receive(:id).at_least(:once) { 1 }
|
141
|
+
expect(model.send(:remove_multivalue, :or)).to eq({hd: nil})
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "#remove_singlevalue" do
|
147
|
+
it "returns a single hash" do
|
148
|
+
expect(model.send(:remove_singlevalue)).to eq({hd: nil})
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe "#add_multivalue" do
|
153
|
+
describe ":and" do
|
154
|
+
it "adds a value to the array" do
|
155
|
+
expect(model).to receive(:operator_mappings).with(:and) { mappings[:and] }
|
156
|
+
expect(group).to receive(:group_params) { ['2','3'] }
|
157
|
+
expect(model).to receive(:id).at_least(:once) { 1 }
|
158
|
+
expect(model.send(:add_multivalue, :and)).to eq({hd: "2#{mappings[:and]}3#{mappings[:and]}1"})
|
159
|
+
end
|
160
|
+
it "returns a single hash if params is empty" do
|
161
|
+
expect(model).to receive(:operator_mappings) { mappings[:and] }
|
162
|
+
expect(group).to receive(:group_params) { [] }
|
163
|
+
expect(model).to receive(:id).at_least(:once) { 1 }
|
164
|
+
expect(model.send(:add_multivalue, :and)).to eq({hd: "1"})
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe ":or" do
|
169
|
+
it "adds a value to the array" do
|
170
|
+
expect(model).to receive(:operator_mappings).with(:or) { mappings[:or] }
|
171
|
+
expect(group).to receive(:group_params) { ['2','3'] }
|
172
|
+
expect(model).to receive(:id).at_least(:once) { 1 }
|
173
|
+
expect(model.send(:add_multivalue, :or)).to eq({hd: "2#{mappings[:or]}3#{mappings[:or]}1"})
|
174
|
+
end
|
175
|
+
it "returns a single hash if params is empty" do
|
176
|
+
expect(model).to receive(:operator_mappings) { mappings[:and] }
|
177
|
+
expect(group).to receive(:group_params) { [] }
|
178
|
+
expect(model).to receive(:id).at_least(:once) { 1 }
|
179
|
+
expect(model.send(:add_multivalue, :or)).to eq({hd: "1"})
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "#add_singlevalue" do
|
185
|
+
it "returns a single k/v pair" do
|
186
|
+
expect(model.send(:add_singlevalue)).to eq({hd: 't'})
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe "#matches?" do
|
191
|
+
it "compares a value to #id" do
|
192
|
+
expect(model.send(:matches?, 't')).to eq(true)
|
193
|
+
end
|
194
|
+
it "typecasts both to a string" do
|
195
|
+
expect(model).to receive(:id) { 'false' }
|
196
|
+
expect(model.send(:matches?, false)).to eq(true)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class DummyPaginatedFacets
|
4
|
+
include Elasticsearch::FacetedSearch::FacetBase
|
5
|
+
facet_exclusive_or(:hd, 'media_hd', 'HD Media')
|
6
|
+
|
7
|
+
def limit
|
8
|
+
11
|
9
|
+
end
|
10
|
+
|
11
|
+
#mock
|
12
|
+
def type
|
13
|
+
'type_here'
|
14
|
+
end
|
15
|
+
|
16
|
+
#mock
|
17
|
+
def filter_hd?
|
18
|
+
end
|
19
|
+
|
20
|
+
#mock
|
21
|
+
def hd_value
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module Elasticsearch
|
27
|
+
module FacetedSearch
|
28
|
+
describe Pagination do
|
29
|
+
let(:model) { DummyPaginatedFacets.new({}) }
|
30
|
+
|
31
|
+
describe "#total_count" do
|
32
|
+
it "returns hits total from ES result" do
|
33
|
+
expect(model).to receive(:search) { {'hits' => { 'total' => 20 }} }
|
34
|
+
expect(model.total_count).to eq(20)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#total_pages" do
|
39
|
+
it "returns total number of pages" do
|
40
|
+
expect(model).to receive(:total_count) { 25 }
|
41
|
+
expect(model.total_pages).to eq(3)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#limit_value" do
|
46
|
+
it "returns the limit from model" do
|
47
|
+
expect(model.limit).to eq(11)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|