search_flip 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'search_flip/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "search_flip"
8
+ spec.version = SearchFlip::VERSION
9
+ spec.authors = ["Benjamin Vetter"]
10
+ spec.email = ["vetter@flakks.com"]
11
+ spec.description = %q{Compositional EasticSearch client library}
12
+ spec.summary = %q{Powerful ElasticSearch client library to easily build complex queries}
13
+ spec.homepage = "https://github.com/mrkamel/search_flip"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "minitest"
24
+ spec.add_development_dependency "mocha"
25
+ spec.add_development_dependency "factory_girl"
26
+ spec.add_development_dependency "sqlite3"
27
+ spec.add_development_dependency "activerecord", ">= 3.0"
28
+ spec.add_development_dependency "webmock"
29
+ spec.add_development_dependency "timecop"
30
+
31
+ spec.add_dependency "http"
32
+ spec.add_dependency "hashie"
33
+ spec.add_dependency "oj"
34
+ end
35
+
data/test/database.yml ADDED
@@ -0,0 +1,4 @@
1
+
2
+ adapter: sqlite3
3
+ database: ":memory:"
4
+
@@ -0,0 +1,212 @@
1
+
2
+ require File.expand_path("../../test_helper", __FILE__)
3
+
4
+ class SearchFlip::AggregationTest < SearchFlip::TestCase
5
+ def test_where
6
+ product1 = create(:product, category: "category1", title: "title", description: "description")
7
+ product2 = create(:product, category: "category2", title: "title", description: "description")
8
+ product3 = create(:product, category: "category1", title: "title", description: "description")
9
+ product4 = create(:product, category: "category2", title: "title", description: "other")
10
+ product5 = create(:product, category: "category1", title: "other", description: "description")
11
+
12
+ ProductIndex.import [product1, product2, product3, product4, product5]
13
+
14
+ query = ProductIndex.aggregate(category: {}) do |aggregation|
15
+ aggregation.where(title: "title").where(description: "description").aggregate(:category)
16
+ end
17
+
18
+ assert_equal Hash["category1" => 2, "category2" => 1], query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[:key]] = bucket.doc_count }
19
+ end
20
+
21
+ def test_where_with_array
22
+ product1 = create(:product, category: "category1", title: "title1", description: "description1")
23
+ product2 = create(:product, category: "category2", title: "title2", description: "description2")
24
+ product3 = create(:product, category: "category1", title: "title3", description: "description3")
25
+ product4 = create(:product, category: "category2", title: "title4", description: "other")
26
+ product5 = create(:product, category: "category1", title: "other", description: "description")
27
+
28
+ ProductIndex.import [product1, product2, product3, product4, product5]
29
+
30
+ query = ProductIndex.aggregate(category: {}) do |aggregation|
31
+ aggregation.where(title: ["title1", "title2", "title3", "title4"]).where(description: ["description1", "description2", "description3"]).aggregate(:category)
32
+ end
33
+
34
+ assert_equal Hash["category1" => 2, "category2" => 1], query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[:key]] = bucket.doc_count }
35
+ end
36
+
37
+ def test_where_with_range
38
+ product1 = create(:product, category: "category1", title: "title1", price: 100)
39
+ product2 = create(:product, category: "category2", title: "title2", price: 150)
40
+ product3 = create(:product, category: "category1", title: "title3", price: 200)
41
+ product4 = create(:product, category: "category2", title: "title4", price: 250)
42
+ product5 = create(:product, category: "category1", title: "other", price: 200)
43
+
44
+ ProductIndex.import [product1, product2, product3, product4, product5]
45
+
46
+ query = ProductIndex.aggregate(category: {}) do |aggregation|
47
+ aggregation.where(title: "title1" .. "title3").where(price: 100 .. 200).aggregate(:category)
48
+ end
49
+
50
+ assert_equal Hash["category1" => 2, "category2" => 1], query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[:key]] = bucket.doc_count }
51
+ end
52
+
53
+ def test_where_not
54
+ product1 = create(:product, category: "category1", title: "title1")
55
+ product2 = create(:product, category: "category2", title: "title2")
56
+ product3 = create(:product, category: "category1", title: "title3")
57
+ product4 = create(:product, category: "category2", title: "title4")
58
+ product5 = create(:product, category: "category1", title: "title5")
59
+
60
+ ProductIndex.import [product1, product2, product3, product4, product5]
61
+
62
+ query = ProductIndex.aggregate(category: {}) do |aggregation|
63
+ aggregation.where_not(title: "title4").where_not(title: "title5").aggregate(:category)
64
+ end
65
+
66
+ assert_equal Hash["category1" => 2, "category2" => 1], query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[:key]] = bucket.doc_count }
67
+ end
68
+
69
+ def test_where_not_with_array
70
+ product1 = create(:product, category: "category1", title: "title1")
71
+ product2 = create(:product, category: "category2", title: "title2")
72
+ product3 = create(:product, category: "category1", title: "title3")
73
+ product4 = create(:product, category: "category2", title: "title4")
74
+ product5 = create(:product, category: "category1", title: "title5")
75
+ product6 = create(:product, category: "category2", title: "title6")
76
+ product7 = create(:product, category: "category1", title: "title7")
77
+
78
+ ProductIndex.import [product1, product2, product3, product4, product5, product6, product7]
79
+
80
+ query = ProductIndex.aggregate(category: {}) do |aggregation|
81
+ aggregation.where_not(title: ["title1", "title2"]).where_not(title: ["title6", "title7"]).aggregate(:category)
82
+ end
83
+
84
+ assert_equal Hash["category1" => 2, "category2" => 1], query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[:key]] = bucket.doc_count }
85
+ end
86
+
87
+ def test_where_not_with_range
88
+ product1 = create(:product, category: "category1", title: "title1", price: 100)
89
+ product2 = create(:product, category: "category2", title: "title2", price: 150)
90
+ product3 = create(:product, category: "category1", title: "title3", price: 200)
91
+ product4 = create(:product, category: "category2", title: "title4", price: 250)
92
+ product5 = create(:product, category: "category1", title: "title5", price: 300)
93
+ product6 = create(:product, category: "category2", title: "title6", price: 350)
94
+ product7 = create(:product, category: "category1", title: "title7", price: 400)
95
+
96
+ ProductIndex.import [product1, product2, product3, product4, product5, product6, product7]
97
+
98
+ query = ProductIndex.aggregate(category: {}) do |aggregation|
99
+ aggregation.where_not(price: 100 .. 150).where_not(title: "title6" .. "title7").aggregate(:category)
100
+ end
101
+
102
+ assert_equal Hash["category1" => 2, "category2" => 1], query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[:key]] = bucket.doc_count }
103
+ end
104
+
105
+ def test_filter
106
+ product1 = create(:product, category: "category1", title: "title", price: 100)
107
+ product2 = create(:product, category: "category2", title: "title", price: 150)
108
+ product3 = create(:product, category: "category1", title: "title", price: 200)
109
+ product4 = create(:product, category: "category2", title: "other", price: 200)
110
+ product5 = create(:product, category: "category1", title: "title", price: 250)
111
+
112
+ ProductIndex.import [product1, product2, product3, product4, product5]
113
+
114
+ query = ProductIndex.aggregate(category: {}) do |aggregation|
115
+ aggregation.filter(range: { price: { gte: 100, lte: 200 }}).filter(term: { title: "title" }).aggregate(:category)
116
+ end
117
+
118
+ assert_equal Hash["category1" => 2, "category2" => 1], query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[:key]] = bucket.doc_count }
119
+ end
120
+
121
+ def test_range
122
+ product1 = create(:product, category: "category1", title: "title1", price: 100)
123
+ product2 = create(:product, category: "category2", title: "title2", price: 150)
124
+ product3 = create(:product, category: "category1", title: "title3", price: 200)
125
+ product4 = create(:product, category: "category2", title: "title4", price: 250)
126
+ product5 = create(:product, category: "category1", title: "title5", price: 300)
127
+ product6 = create(:product, category: "category2", title: "title6", price: 350)
128
+ product7 = create(:product, category: "category1", title: "title7", price: 400)
129
+
130
+ ProductIndex.import [product1, product2, product3, product4, product5, product6, product7]
131
+
132
+ query = ProductIndex.aggregate(category: {}) do |aggregation|
133
+ aggregation.range(:price, gte: 100, lte: 200).range(:title, gte: "title1", lte: "title3").aggregate(:category)
134
+ end
135
+
136
+ assert_equal Hash["category1" => 2, "category2" => 1], query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[:key]] = bucket.doc_count }
137
+ end
138
+
139
+ def test_match_all
140
+ product1 = create(:product, category: "category1")
141
+ product2 = create(:product, category: "category2")
142
+ product3 = create(:product, category: "category1")
143
+
144
+ ProductIndex.import [product1, product2, product3]
145
+
146
+ query = ProductIndex.aggregate(category: {}) do |aggregation|
147
+ aggregation.match_all.aggregate(:category)
148
+ end
149
+
150
+ assert_equal Hash["category1" => 2, "category2" => 1], query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[:key]] = bucket.doc_count }
151
+ end
152
+
153
+ def test_exists
154
+ product1 = create(:product, category: "category1", title: "title1", price: 10)
155
+ product2 = create(:product, category: "category2", title: "title2")
156
+ product3 = create(:product, category: "category1", title: "title3", price: 20)
157
+ product4 = create(:product, category: "category2", title: "title4", price: 30)
158
+ product5 = create(:product, category: "category1", price: 40)
159
+
160
+ ProductIndex.import [product1, product2, product3, product4, product5]
161
+
162
+ query = ProductIndex.aggregate(category: {}) do |aggregation|
163
+ aggregation.exists(:title).exists(:price).aggregate(:category)
164
+ end
165
+
166
+ assert_equal Hash["category1" => 2, "category2" => 1], query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[:key]] = bucket.doc_count }
167
+ end
168
+
169
+ def test_exists_not
170
+ product1 = create(:product, category: "category1")
171
+ product2 = create(:product, category: "category2", title: "title2")
172
+ product3 = create(:product, category: "category1")
173
+ product4 = create(:product, category: "category2")
174
+ product5 = create(:product, category: "category1", price: 40)
175
+
176
+ ProductIndex.import [product1, product2, product3, product4, product5]
177
+
178
+ query = ProductIndex.aggregate(category: {}) do |aggregation|
179
+ aggregation.exists_not(:title).exists_not(:price).aggregate(:category)
180
+ end
181
+
182
+ assert_equal Hash["category1" => 2, "category2" => 1], query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[:key]] = bucket.doc_count }
183
+ end
184
+
185
+ def test_aggregate
186
+ product1 = create(:product, category: "category1", title: "title1", price: 10)
187
+ product2 = create(:product, category: "category1", title: "title2", price: 15)
188
+ product3 = create(:product, category: "category1", title: "title1", price: 20)
189
+ product4 = create(:product, category: "category2", title: "title2", price: 25)
190
+ product5 = create(:product, category: "category2", title: "title1", price: 30)
191
+ product6 = create(:product, category: "category2", title: "title2", price: 35)
192
+
193
+ ProductIndex.import [product1, product2, product3, product4, product5, product6]
194
+
195
+ query = ProductIndex.aggregate(:category) do |aggregation|
196
+ aggregation.aggregate(:title) do |_aggregation|
197
+ _aggregation.aggregate(price: { sum: { field: "price" }})
198
+ end
199
+ end
200
+
201
+ assert_equal Hash["category1" => 3, "category2" => 3], query.aggregations(:category).each_with_object({}) { |(key, agg), hash| hash[key] = agg.doc_count }
202
+
203
+ assert_equal Hash["title1" => 2, "title2" => 1], query.aggregations(:category)["category1"].title.buckets.each_with_object({}) { |bucket, hash| hash[bucket[:key]] = bucket.doc_count }
204
+ assert_equal Hash["title1" => 1, "title2" => 2], query.aggregations(:category)["category2"].title.buckets.each_with_object({}) { |bucket, hash| hash[bucket[:key]] = bucket.doc_count }
205
+
206
+ assert_equal 30, query.aggregations(:category)["category1"].title.buckets.detect { |bucket| bucket[:key] == "title1" }.price.value
207
+ assert_equal 15, query.aggregations(:category)["category1"].title.buckets.detect { |bucket| bucket[:key] == "title2" }.price.value
208
+ assert_equal 30, query.aggregations(:category)["category2"].title.buckets.detect { |bucket| bucket[:key] == "title1" }.price.value
209
+ assert_equal 60, query.aggregations(:category)["category2"].title.buckets.detect { |bucket| bucket[:key] == "title2" }.price.value
210
+ end
211
+ end
212
+
@@ -0,0 +1,55 @@
1
+
2
+ require File.expand_path("../../test_helper", __FILE__)
3
+
4
+ class SearchFlip::BulkTest < SearchFlip::TestCase
5
+ def test_bulk
6
+ product1, product2 = create_list(:product, 2)
7
+
8
+ assert_difference "ProductIndex.total_entries", 2 do
9
+ ProductIndex.bulk do |bulk|
10
+ bulk.create product1.id, ProductIndex.serialize(product1)
11
+ bulk.create product2.id, ProductIndex.serialize(product1)
12
+ end
13
+ end
14
+
15
+ assert_difference "ProductIndex.total_entries", -2 do
16
+ ProductIndex.bulk do |bulk|
17
+ bulk.delete product1.id
18
+ bulk.delete product2.id
19
+ end
20
+ end
21
+ end
22
+
23
+ def test_bulk_with_options
24
+ product1, product2 = create_list(:product, 2)
25
+
26
+ ProductIndex.import [product1, product2]
27
+
28
+ assert_raises "SearchFlip::Bulk::Error" do
29
+ ProductIndex.bulk do |bulk|
30
+ bulk.create product1.id, ProductIndex.serialize(product1)
31
+ bulk.create product2.id, ProductIndex.serialize(product1)
32
+ end
33
+ end
34
+
35
+ ProductIndex.bulk(ignore_errors: [409]) do |bulk|
36
+ bulk.create product1.id, ProductIndex.serialize(product1)
37
+ bulk.create product2.id, ProductIndex.serialize(product1)
38
+ end
39
+ end
40
+
41
+ def test_bulk_with_item_options
42
+ product = create(:product)
43
+
44
+ ProductIndex.bulk do |bulk|
45
+ bulk.index product.id, ProductIndex.serialize(product), version: 1, version_type: "external_gt"
46
+ end
47
+
48
+ assert_raises "SearchFlip::Bulk::Error" do
49
+ ProductIndex.bulk do |bulk|
50
+ bulk.index product.id, ProductIndex.serialize(product), version: 1, version_type: "external_gt"
51
+ end
52
+ end
53
+ end
54
+ end
55
+