mongoid_search 0.3.2 → 0.4.0
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/LICENSE +1 -1
- data/README.md +179 -116
- data/Rakefile +5 -2
- data/lib/mongoid_search.rb +14 -7
- data/lib/mongoid_search/log.rb +2 -1
- data/lib/mongoid_search/mongoid_search.rb +61 -42
- data/lib/mongoid_search/railtie.rb +2 -5
- data/lib/mongoid_search/tasks/mongoid_search.rake +16 -0
- data/lib/mongoid_search/util.rb +19 -18
- data/spec/models/category.rb +2 -0
- data/spec/models/product.rb +15 -6
- data/spec/models/subproduct.rb +2 -1
- data/spec/models/tag.rb +3 -2
- data/spec/models/variant.rb +3 -1
- data/spec/mongoid_search_spec.rb +231 -133
- data/spec/spec_helper.rb +4 -1
- data/spec/util_spec.rb +28 -29
- metadata +56 -54
- data/VERSION +0 -1
@@ -1,10 +1,7 @@
|
|
1
|
-
require 'mongoid_search'
|
2
|
-
require 'rails'
|
3
|
-
|
4
1
|
module Mongoid::Search
|
5
2
|
class Railtie < Rails::Railtie
|
6
3
|
rake_tasks do
|
7
|
-
Dir[File.join(File.dirname(__FILE__), '
|
4
|
+
Dir[File.join(File.dirname(__FILE__), 'tasks/*.rake')].each { |f| load f }
|
8
5
|
end
|
9
6
|
end
|
10
|
-
end
|
7
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
namespace :mongoid_search do
|
2
|
+
desc 'Goes through all documents with search enabled and indexes the keywords.'
|
3
|
+
task index: :environment do
|
4
|
+
::Rails.application.eager_load!
|
5
|
+
if Mongoid::Search.classes.blank?
|
6
|
+
Mongoid::Search::Log.log "No model to index keywords.\n"
|
7
|
+
else
|
8
|
+
Mongoid::Search.classes.each do |klass|
|
9
|
+
Mongoid::Search::Log.silent = ENV['SILENT']
|
10
|
+
Mongoid::Search::Log.log "\nIndexing documents for #{klass.name}:\n"
|
11
|
+
klass.index_keywords!
|
12
|
+
end
|
13
|
+
Mongoid::Search::Log.log "\n\nDone.\n"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/mongoid_search/util.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
|
-
|
1
|
+
|
2
2
|
module Mongoid::Search::Util
|
3
3
|
def self.keywords(klass, fields)
|
4
4
|
if fields.is_a?(Array)
|
5
5
|
fields.map do |field|
|
6
|
-
|
6
|
+
keywords(klass, field)
|
7
7
|
end
|
8
8
|
elsif fields.is_a?(Hash)
|
9
9
|
fields.keys.map do |field|
|
10
10
|
attribute = klass.send(field)
|
11
11
|
unless attribute.blank?
|
12
12
|
if attribute.is_a?(Array)
|
13
|
-
attribute.map{ |a|
|
13
|
+
attribute.map { |a| keywords(a, fields[field]) }
|
14
14
|
else
|
15
|
-
|
15
|
+
keywords(attribute, fields[field])
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
19
19
|
else
|
20
|
-
value = if klass.respond_to?(fields.to_s +
|
21
|
-
klass.send(fields.to_s +
|
20
|
+
value = if klass.respond_to?(fields.to_s + '_translations')
|
21
|
+
klass.send(fields.to_s + '_translations').values
|
22
22
|
elsif klass.respond_to?(fields)
|
23
23
|
klass.send(fields)
|
24
24
|
else
|
25
|
-
value = klass[fields]
|
25
|
+
value = klass[fields]
|
26
26
|
end
|
27
27
|
value = value.join(' ') if value.respond_to?(:join)
|
28
28
|
normalize_keywords(value) if value
|
@@ -34,21 +34,22 @@ module Mongoid::Search::Util
|
|
34
34
|
ignore_list = Mongoid::Search.ignore_list
|
35
35
|
stem_keywords = Mongoid::Search.stem_keywords
|
36
36
|
stem_proc = Mongoid::Search.stem_proc
|
37
|
+
strip_symbols = Mongoid::Search.strip_symbols
|
38
|
+
strip_accents = Mongoid::Search.strip_accents
|
37
39
|
|
38
40
|
return [] if text.blank?
|
39
|
-
text = text.to_s
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
41
|
+
text = text.to_s
|
42
|
+
.mb_chars
|
43
|
+
.unicode_normalize(:nfkd)
|
44
|
+
.downcase
|
45
|
+
.to_s
|
46
|
+
.gsub(strip_symbols, ' ') # strip symbols
|
47
|
+
.gsub(strip_accents, '') # strip accents
|
48
|
+
.gsub(/[#{ligatures.keys.join("")}]/) { |c| ligatures[c] }
|
49
|
+
.split(' ')
|
50
|
+
.reject { |word| word.size < Mongoid::Search.minimum_word_size }
|
49
51
|
text = text.reject { |word| ignore_list.include?(word) } unless ignore_list.blank?
|
50
52
|
text = text.map(&stem_proc) if stem_keywords
|
51
53
|
text
|
52
54
|
end
|
53
|
-
|
54
55
|
end
|
data/spec/models/category.rb
CHANGED
data/spec/models/product.rb
CHANGED
@@ -1,15 +1,24 @@
|
|
1
1
|
class Product
|
2
2
|
include Mongoid::Document
|
3
3
|
include Mongoid::Search
|
4
|
+
include Mongoid::Attributes::Dynamic if ::Mongoid::VERSION >= '4'
|
5
|
+
|
4
6
|
field :brand
|
5
7
|
field :name
|
6
|
-
field :
|
7
|
-
field :
|
8
|
+
field :unit
|
9
|
+
field :measures, type: Array
|
10
|
+
field :attrs, type: Array
|
11
|
+
field :info, type: Hash
|
8
12
|
|
9
|
-
has_many
|
10
|
-
|
13
|
+
has_many :tags
|
14
|
+
if Mongoid::Compatibility::Version.mongoid6_or_newer?
|
15
|
+
belongs_to :category, required: false
|
16
|
+
else
|
17
|
+
belongs_to :category
|
18
|
+
end
|
11
19
|
embeds_many :subproducts
|
12
20
|
|
13
|
-
search_in :brand, :name, :outlet, :attrs, :
|
14
|
-
|
21
|
+
search_in :brand, :name, :outlet, :attrs, tags: :name, category: %i[name description],
|
22
|
+
subproducts: %i[brand name], info: %i[summary description]
|
23
|
+
search_in :unit, :measures, index: :_unit_keywords
|
15
24
|
end
|
data/spec/models/subproduct.rb
CHANGED
data/spec/models/tag.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
class Tag
|
2
2
|
include Mongoid::Document
|
3
3
|
include Mongoid::Search
|
4
|
+
include Mongoid::Attributes::Dynamic if ::Mongoid::VERSION >= '4'
|
4
5
|
|
5
6
|
field :name
|
6
7
|
|
7
8
|
belongs_to :product
|
8
9
|
|
9
10
|
def title
|
10
|
-
|
11
|
+
name
|
11
12
|
end
|
12
13
|
|
13
|
-
search_in :title, :
|
14
|
+
search_in :title, product: [:name, { info: %i[summary description], category: %i[name description] }]
|
14
15
|
end
|
data/spec/models/variant.rb
CHANGED
data/spec/mongoid_search_spec.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
4
2
|
|
5
3
|
describe Mongoid::Search do
|
6
|
-
|
7
4
|
before(:all) do
|
8
5
|
@default_proc = Mongoid::Search.stem_proc
|
6
|
+
@default_strip_symbols = Mongoid::Search.strip_symbols
|
7
|
+
@default_strip_accents = Mongoid::Search.strip_accents
|
9
8
|
end
|
10
9
|
|
11
10
|
after(:all) do
|
@@ -17,257 +16,356 @@ describe Mongoid::Search do
|
|
17
16
|
Mongoid::Search.stem_keywords = false
|
18
17
|
Mongoid::Search.ignore_list = nil
|
19
18
|
Mongoid::Search.stem_proc = @default_proc
|
20
|
-
@product = Product.create :
|
21
|
-
:
|
22
|
-
:
|
23
|
-
:
|
24
|
-
:
|
25
|
-
:
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
Product.full_text_search(
|
19
|
+
@product = Product.create brand: 'Apple',
|
20
|
+
name: 'iPhone',
|
21
|
+
unit: 'mobile olé awesome',
|
22
|
+
tags: (@tags = %w[Amazing Awesome Olé].map { |tag| Tag.new(name: tag) }),
|
23
|
+
category: Category.new(name: 'Mobile', description: 'Reviews'),
|
24
|
+
subproducts: [Subproduct.new(brand: 'Apple', name: 'Craddle')],
|
25
|
+
info: { summary: 'Info-summary',
|
26
|
+
description: 'Info-description' }
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'Serialized hash fields' do
|
30
|
+
context 'when the hash is populated' do
|
31
|
+
it 'should return the product' do
|
32
|
+
expect(Product.full_text_search('Info-summary').first).to eq @product
|
33
|
+
expect(Product.full_text_search('Info-description').first).to eq @product
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
context
|
37
|
+
context 'when the hash is empty' do
|
38
38
|
before(:each) do
|
39
39
|
@product.info = nil
|
40
40
|
@product.save
|
41
41
|
end
|
42
42
|
|
43
|
-
it
|
44
|
-
Product.full_text_search(
|
45
|
-
Product.full_text_search(
|
43
|
+
it 'should not return the product' do
|
44
|
+
expect(Product.full_text_search('Info-description').size).to eq 0
|
45
|
+
expect(Product.full_text_search('Info-summary').size).to eq 0
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
context
|
50
|
+
context 'utf-8 characters' do
|
51
51
|
before do
|
52
52
|
Mongoid::Search.stem_keywords = false
|
53
53
|
Mongoid::Search.ignore_list = nil
|
54
|
-
@product = Product.create :
|
55
|
-
:
|
56
|
-
:
|
57
|
-
:
|
58
|
-
:
|
54
|
+
@product = Product.create brand: 'Эльбрус',
|
55
|
+
name: 'Процессор',
|
56
|
+
unit: 'kílográm Olé',
|
57
|
+
tags: %w[Amazing Awesome Olé].map { |tag| Tag.new(name: tag) },
|
58
|
+
category: Category.new(name: 'процессоры'),
|
59
|
+
subproducts: []
|
59
60
|
end
|
60
61
|
|
61
|
-
it
|
62
|
-
@product._keywords.
|
62
|
+
it 'should leave utf8 characters' do
|
63
|
+
expect(@product._keywords).to eq %w[amazing awesome ole процессор процессоры эльбрус]
|
64
|
+
expect(@product._unit_keywords).to eq %w[kilogram ole]
|
63
65
|
end
|
64
66
|
|
65
67
|
it "should return results in search when case doesn't match" do
|
66
|
-
Product.full_text_search(
|
68
|
+
expect(Product.full_text_search('ЭЛЬБРУС').size).to eq 1
|
69
|
+
expect(Product.full_text_search('KILOGRAM', index: :_unit_keywords).size).to eq 1
|
67
70
|
end
|
68
71
|
end
|
69
72
|
|
70
|
-
context
|
71
|
-
context
|
72
|
-
it
|
73
|
-
|
73
|
+
context 'when references are nil' do
|
74
|
+
context 'when instance is being created' do
|
75
|
+
it 'should not complain about method missing' do
|
76
|
+
expect { Product.create! }.not_to raise_error
|
74
77
|
end
|
75
78
|
end
|
76
79
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
+
it 'should validate keywords' do
|
81
|
+
product = Product.create brand: 'Apple', name: 'iPhone', unit: 'box'
|
82
|
+
expect(product._keywords).to eq(%w[apple iphone])
|
83
|
+
expect(product._unit_keywords).to eq(%w[box])
|
84
|
+
end
|
80
85
|
end
|
81
86
|
|
82
|
-
|
83
|
-
it "should set the _keywords field for array fields also" do
|
87
|
+
it 'should set the _keywords field for array fields also' do
|
84
88
|
@product.attrs = ['lightweight', 'plastic', :red]
|
89
|
+
@product.measures = ['box', 'bunch', :bag]
|
85
90
|
@product.save!
|
86
|
-
@product._keywords.
|
91
|
+
expect(@product._keywords).to include 'lightweight', 'plastic', 'red'
|
92
|
+
expect(@product._unit_keywords).to include 'box', 'bunch', 'bag'
|
87
93
|
end
|
88
94
|
|
89
|
-
it
|
90
|
-
variant = Variant.create :
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
95
|
+
it 'should inherit _keywords field and build upon' do
|
96
|
+
variant = Variant.create brand: 'Apple',
|
97
|
+
name: 'iPhone',
|
98
|
+
tags: %w[Amazing Awesome Olé].map { |tag| Tag.new(name: tag) },
|
99
|
+
category: Category.new(name: 'Mobile'),
|
100
|
+
subproducts: [Subproduct.new(brand: 'Apple', name: 'Craddle')],
|
101
|
+
color: :white,
|
102
|
+
size: :big
|
103
|
+
expect(variant._keywords).to include 'white'
|
104
|
+
expect(variant._unit_keywords).to include 'big'
|
105
|
+
expect(Variant.full_text_search(name: 'Apple', color: :white)).to eq [variant]
|
106
|
+
expect(Variant.full_text_search({ size: 'big' }, index: :_unit_keywords)).to eq [variant]
|
98
107
|
end
|
99
108
|
|
100
|
-
it
|
109
|
+
it 'should expand the ligature to ease searching' do
|
101
110
|
# ref: http://en.wikipedia.org/wiki/Typographic_ligature, only for french right now. Rules for other languages are not know
|
102
|
-
variant1 = Variant.create :
|
103
|
-
variant2 = Variant.create :
|
111
|
+
variant1 = Variant.create tags: ['œuvre'].map { |tag| Tag.new(name: tag) }
|
112
|
+
variant2 = Variant.create tags: ['æquo'].map { |tag| Tag.new(name: tag) }
|
113
|
+
variant3 = Variant.create measures: ['ꜵquo'].map { |measure| measure }
|
104
114
|
|
105
|
-
Variant.full_text_search(
|
106
|
-
Variant.full_text_search(
|
107
|
-
Variant.full_text_search(
|
108
|
-
Variant.full_text_search(
|
115
|
+
expect(Variant.full_text_search('œuvre')).to eq [variant1]
|
116
|
+
expect(Variant.full_text_search('oeuvre')).to eq [variant1]
|
117
|
+
expect(Variant.full_text_search('æquo')).to eq [variant2]
|
118
|
+
expect(Variant.full_text_search('aequo')).to eq [variant2]
|
119
|
+
expect(Variant.full_text_search('aoquo', index: :_unit_keywords)).to eq [variant3]
|
120
|
+
expect(Variant.full_text_search('ꜵquo', index: :_unit_keywords)).to eq [variant3]
|
109
121
|
end
|
110
122
|
|
111
|
-
it
|
123
|
+
it 'should set the keywords fields with stemmed words if stem is enabled' do
|
112
124
|
Mongoid::Search.stem_keywords = true
|
113
125
|
@product.save!
|
114
|
-
@product._keywords.sort.
|
126
|
+
expect(@product._keywords.sort).to eq %w[amaz appl awesom craddl iphon mobil review ol info descript summari].sort
|
127
|
+
expect(@product._unit_keywords.sort).to eq %w[mobil awesom ol].sort
|
115
128
|
end
|
116
129
|
|
117
|
-
it
|
130
|
+
it 'should set the keywords fields with custom stemmed words if stem is enabled with a custom lambda' do
|
118
131
|
Mongoid::Search.stem_keywords = true
|
119
|
-
Mongoid::Search.stem_proc =
|
132
|
+
Mongoid::Search.stem_proc = proc { |word| word.upcase }
|
120
133
|
@product.save!
|
121
|
-
@product._keywords.sort.
|
134
|
+
expect(@product._keywords.sort).to eq %w[AMAZING APPLE AWESOME CRADDLE DESCRIPTION INFO IPHONE MOBILE OLE REVIEWS SUMMARY]
|
135
|
+
expect(@product._unit_keywords.sort).to eq %w[AWESOME MOBILE OLE]
|
122
136
|
end
|
123
137
|
|
124
|
-
it
|
125
|
-
Mongoid::Search.ignore_list = YAML.
|
138
|
+
it 'should ignore keywords in an ignore list' do
|
139
|
+
Mongoid::Search.ignore_list = YAML.safe_load(File.open(File.dirname(__FILE__) + '/config/ignorelist.yml'))['ignorelist']
|
126
140
|
@product.save!
|
127
|
-
@product._keywords.sort.
|
141
|
+
expect(@product._keywords.sort).to eq %w[apple craddle iphone mobile reviews ole info description summary].sort
|
142
|
+
expect(@product._unit_keywords.sort).to eq %w[mobile ole].sort
|
128
143
|
end
|
129
144
|
|
130
|
-
|
131
|
-
|
132
|
-
:
|
133
|
-
:
|
134
|
-
:
|
145
|
+
it 'should incorporate numbers as keywords' do
|
146
|
+
@product = Product.create brand: 'Ford',
|
147
|
+
name: 'T 1908',
|
148
|
+
tags: %w[Amazing First Car].map { |tag| Tag.new(name: tag) },
|
149
|
+
category: Category.new(name: 'Vehicle')
|
135
150
|
|
136
|
-
|
137
|
-
|
138
|
-
|
151
|
+
@product.save!
|
152
|
+
expect(@product._keywords).to eq %w[1908 amazing car first ford vehicle]
|
153
|
+
end
|
139
154
|
|
140
|
-
it
|
141
|
-
Product.full_text_search(
|
155
|
+
it 'should return results in search' do
|
156
|
+
expect(Product.full_text_search('apple').size).to eq 1
|
142
157
|
end
|
143
158
|
|
144
|
-
it
|
145
|
-
@product[:outlet] =
|
159
|
+
it 'should return results in search for dynamic attribute' do
|
160
|
+
@product[:outlet] = 'online shop'
|
146
161
|
@product.save!
|
147
|
-
Product.full_text_search(
|
162
|
+
expect(Product.full_text_search('online').size).to eq 1
|
148
163
|
end
|
149
164
|
|
150
|
-
it
|
151
|
-
Product.full_text_search(
|
152
|
-
Product.full_text_search(
|
165
|
+
it 'should return results in search even searching a accented word' do
|
166
|
+
expect(Product.full_text_search('Ole').size).to eq 1
|
167
|
+
expect(Product.full_text_search('Olé').size).to eq 1
|
153
168
|
end
|
154
169
|
|
155
170
|
it "should return results in search even if the case doesn't match" do
|
156
|
-
Product.full_text_search(
|
171
|
+
expect(Product.full_text_search('oLe').size).to eq 1
|
157
172
|
end
|
158
173
|
|
159
|
-
it
|
160
|
-
Product.full_text_search(
|
174
|
+
it 'should return results in search with a partial word by default' do
|
175
|
+
expect(Product.full_text_search('iph').size).to eq 1
|
161
176
|
end
|
162
177
|
|
163
|
-
it
|
164
|
-
Product.full_text_search(
|
178
|
+
it 'should return results for any matching word with default search' do
|
179
|
+
expect(Product.full_text_search('apple motorola').size).to eq 1
|
165
180
|
end
|
166
181
|
|
167
|
-
it
|
182
|
+
it 'should not return results when all words do not match, if using :match => :all' do
|
168
183
|
Mongoid::Search.match = :all
|
169
|
-
Product.full_text_search(
|
184
|
+
expect(Product.full_text_search('apple motorola').size).to eq 0
|
170
185
|
end
|
171
186
|
|
172
|
-
it
|
187
|
+
it 'should return results for any matching word, using :match => :all, passing :match => :any to .full_text_search' do
|
173
188
|
Mongoid::Search.match = :all
|
174
|
-
Product.full_text_search(
|
189
|
+
expect(Product.full_text_search('apple motorola', match: :any).size).to eq 1
|
175
190
|
end
|
176
191
|
|
177
|
-
it
|
178
|
-
Product.full_text_search(
|
192
|
+
it 'should not return results when all words do not match, passing :match => :all to .full_text_search' do
|
193
|
+
expect(Product.full_text_search('apple motorola', match: :all).size).to eq 0
|
179
194
|
end
|
180
195
|
|
181
|
-
it
|
196
|
+
it 'should return no results when a blank search is made' do
|
182
197
|
Mongoid::Search.allow_empty_search = false
|
183
|
-
Product.full_text_search(
|
198
|
+
expect(Product.full_text_search('').size).to eq 0
|
184
199
|
end
|
185
200
|
|
186
|
-
it
|
201
|
+
it 'should return results when a blank search is made when :allow_empty_search is true' do
|
187
202
|
Mongoid::Search.allow_empty_search = true
|
188
|
-
Product.full_text_search(
|
203
|
+
expect(Product.full_text_search('').size).to eq 1
|
189
204
|
end
|
190
205
|
|
191
|
-
it
|
192
|
-
Product.full_text_search(
|
206
|
+
it 'should search for embedded documents' do
|
207
|
+
expect(Product.full_text_search('craddle').size).to eq 1
|
193
208
|
end
|
194
209
|
|
195
|
-
it
|
196
|
-
Product.full_text_search(
|
210
|
+
it 'should search for reference documents' do
|
211
|
+
expect(Product.full_text_search('reviews').size).to eq 1
|
197
212
|
end
|
198
213
|
|
199
214
|
it 'should work in a chainable fashion' do
|
200
|
-
@product.category.products.where(:
|
201
|
-
@product.category.products.full_text_search('craddle').where(:
|
215
|
+
expect(@product.category.products.where(brand: 'Apple').full_text_search('apple').size).to eq 1
|
216
|
+
expect(@product.category.products.full_text_search('craddle').where(brand: 'Apple').size).to eq 1
|
202
217
|
end
|
203
218
|
|
204
219
|
it 'should return the classes that include the search module' do
|
205
|
-
Mongoid::Search.classes.
|
220
|
+
expect(Mongoid::Search.classes.sort_by(&:name)).to eq [Product, Tag]
|
206
221
|
end
|
207
222
|
|
208
223
|
it 'should have a method to index keywords' do
|
209
|
-
@product.index_keywords
|
224
|
+
expect(@product.index_keywords!).to include(true)
|
210
225
|
end
|
211
226
|
|
212
227
|
it 'should have a class method to index all documents keywords' do
|
213
|
-
Product.index_keywords
|
228
|
+
expect(Product.index_keywords!).not_to include(false)
|
214
229
|
end
|
215
230
|
|
216
|
-
context
|
231
|
+
context 'when regex search is false' do
|
217
232
|
before do
|
218
233
|
Mongoid::Search.regex_search = false
|
219
234
|
end
|
220
235
|
|
221
|
-
it
|
222
|
-
Product.full_text_search(
|
236
|
+
it 'should not return results in search with a partial word if not using regex search' do
|
237
|
+
expect(Product.full_text_search('iph').size).to eq 0
|
223
238
|
end
|
224
239
|
|
225
|
-
it
|
226
|
-
Product.full_text_search(
|
240
|
+
it 'should return results in search with a full word if not using regex search' do
|
241
|
+
expect(Product.full_text_search('iphone').size).to eq 1
|
227
242
|
end
|
228
243
|
end
|
229
244
|
|
230
|
-
context
|
245
|
+
context 'when regex search is true' do
|
246
|
+
before do
|
247
|
+
Mongoid::Search.regex_search = true
|
248
|
+
end
|
249
|
+
|
250
|
+
after do
|
251
|
+
Mongoid::Search.regex_search = false
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'should not return results in search with a partial word if using regex search' do
|
255
|
+
expect(Product.full_text_search('iph').size).to eq 1
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'should return results in search with a full word if using regex search' do
|
259
|
+
expect(Product.full_text_search('iphone').size).to eq 1
|
260
|
+
end
|
261
|
+
|
262
|
+
context 'when query include special characters that should not be stripped' do
|
263
|
+
before do
|
264
|
+
Mongoid::Search.strip_symbols = /[\n]/
|
265
|
+
Mongoid::Search.strip_accents = /[^\s\p{Graph}]/
|
266
|
+
end
|
267
|
+
|
268
|
+
after do
|
269
|
+
Mongoid::Search.strip_symbols = @default_strip_symbols
|
270
|
+
Mongoid::Search.strip_accents = @default_strip_accents
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'should escape regex special characters' do
|
274
|
+
expect(Product.full_text_search('iphone (steve').size).to eq 1
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
context 'Match partial words on the beginning' do
|
279
|
+
before do
|
280
|
+
Mongoid::Search.regex = proc { |query| /^#{query}/ }
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'should return results in search which starts with query string' do
|
284
|
+
expect(Product.full_text_search('iphone').size).to eq 1
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'should not return results in search which does not start with query string' do
|
288
|
+
expect(Product.full_text_search('phone').size).to eq 0
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
context 'Match partial words on the end' do
|
293
|
+
before do
|
294
|
+
Mongoid::Search.regex = proc { |query| /#{query}$/ }
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'should return results in search which ends with query string' do
|
298
|
+
expect(Product.full_text_search('phone').size).to eq 1
|
299
|
+
end
|
300
|
+
|
301
|
+
it 'should not return results in search which does not end with query string' do
|
302
|
+
expect(Product.full_text_search('phon').size).to eq 0
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
context 'relevant search' do
|
231
308
|
before do
|
232
309
|
Mongoid::Search.relevant_search = true
|
233
|
-
@imac = Product.create :
|
310
|
+
@imac = Product.create name: 'apple imac'
|
311
|
+
end
|
312
|
+
|
313
|
+
it 'should return results ordered by relevance and with correct ids' do
|
314
|
+
expect(Product.full_text_search('apple imac').map(&:_id)).to eq [@imac._id, @product._id]
|
234
315
|
end
|
235
316
|
|
236
|
-
it
|
237
|
-
Product.full_text_search('apple imac').map(&:
|
317
|
+
it 'results should be recognized as persisted objects' do
|
318
|
+
expect(Product.full_text_search('apple imac').map(&:persisted?)).not_to include false
|
238
319
|
end
|
239
320
|
|
240
|
-
it
|
241
|
-
Product.full_text_search('apple imac').map(&:
|
321
|
+
it 'should include relevance information' do
|
322
|
+
expect(Product.full_text_search('apple imac').map(&:relevance)).to eq [2, 1]
|
242
323
|
end
|
324
|
+
end
|
243
325
|
|
244
|
-
|
245
|
-
|
326
|
+
context 'when using methods for keywords' do
|
327
|
+
it 'should set the _keywords from methods' do
|
328
|
+
expect(@tags.first._keywords).to include 'amazing'
|
246
329
|
end
|
247
330
|
end
|
248
331
|
|
249
|
-
context
|
250
|
-
|
251
|
-
|
332
|
+
context 'when using deeply nested fields for keywords' do
|
333
|
+
context 'when explicitly calling set_keywords' do
|
334
|
+
it 'should set the _keywords from parent' do
|
335
|
+
@tags.first.send(:set_keywords)
|
336
|
+
expect(@tags.first._keywords).to eq %w[amazing description info iphone mobile reviews summary]
|
337
|
+
end
|
252
338
|
end
|
253
339
|
end
|
254
340
|
|
255
|
-
context
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
341
|
+
context 'when using localized fields' do
|
342
|
+
it 'should set the keywords from all localizations' do
|
343
|
+
@product = Product.create brand: 'Ford',
|
344
|
+
name: 'T 1908',
|
345
|
+
tags: %w[Amazing First Car].map { |tag| Tag.new(name: tag) },
|
346
|
+
category: Category.new(name_translations: { en: 'Vehicle', de: 'Fahrzeug' })
|
347
|
+
expect(@product._keywords).to include('fahrzeug')
|
261
348
|
end
|
262
349
|
end
|
263
350
|
|
264
|
-
context
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
351
|
+
context 'minimum word size' do
|
352
|
+
before(:each) do
|
353
|
+
Mongoid::Search.minimum_word_size = 3
|
354
|
+
end
|
355
|
+
|
356
|
+
after(:each) do
|
357
|
+
Mongoid::Search.minimum_word_size = 2
|
358
|
+
end
|
359
|
+
|
360
|
+
it 'should ignore keywords with length less than minimum word size' do
|
361
|
+
@product = Product.create name: 'a'
|
362
|
+
expect(@product._keywords.size).to eq 0
|
363
|
+
|
364
|
+
@product = Product.create name: 'ap'
|
365
|
+
expect(@product._keywords.size).to eq 0
|
366
|
+
|
367
|
+
@product = Product.create name: 'app'
|
368
|
+
expect(@product._keywords.size).to eq 1
|
271
369
|
end
|
272
370
|
end
|
273
371
|
end
|