mongoid_search 0.3.2 → 0.3.3
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 +9 -6
- data/VERSION +1 -1
- data/lib/mongoid_search.rb +6 -3
- data/lib/mongoid_search/mongoid_search.rb +24 -23
- data/lib/mongoid_search/railtie.rb +2 -5
- data/lib/mongoid_search/tasks/mongoid_search.rake +16 -0
- data/lib/mongoid_search/util.rb +1 -1
- data/spec/models/category.rb +2 -0
- data/spec/models/product.rb +2 -0
- data/spec/models/subproduct.rb +2 -1
- data/spec/models/tag.rb +1 -0
- data/spec/mongoid_search_spec.rb +147 -76
- data/spec/util_spec.rb +12 -12
- metadata +36 -46
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: eaeb19566825291c03bd018b9013d0c06a8b01c4
|
4
|
+
data.tar.gz: 2b930fec009de9031350c4b7fbc658c928224eed
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3111148a9311c26712eb3bbbccf7ec3c8c8d1db7283ac3e8435244558a16d157cdc22e039715bef5192234dc1a1ca80308d2a3805f7a8479eb27d8de4f689b92
|
7
|
+
data.tar.gz: 9ed30923429cba88f73916057671a598ecc0589ea67016817b74ffb68b4721ded77c58c07af285914dcad92998c70b69c5a5f64d81fc53670a15ef73c6e3e9f4
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -26,11 +26,12 @@ Examples
|
|
26
26
|
include Mongoid::Search
|
27
27
|
field :brand
|
28
28
|
field :name
|
29
|
+
field :info, :type => Hash
|
29
30
|
|
30
31
|
has_many :tags
|
31
32
|
belongs_to :category
|
32
33
|
|
33
|
-
search_in :brand, :name, :tags => :name, :category => :name
|
34
|
+
search_in :brand, :name, :tags => :name, :category => :name, :info => [:summary, :description]
|
34
35
|
end
|
35
36
|
|
36
37
|
class Tag
|
@@ -49,14 +50,14 @@ Examples
|
|
49
50
|
|
50
51
|
Now when you save a product, you get a _keywords field automatically:
|
51
52
|
|
52
|
-
p = Product.new :brand => "Apple", :name => "iPhone"
|
53
|
+
p = Product.new :brand => "Apple", :name => "iPhone", :info => {:summary => "Info-summary", :description => "Info-description"}
|
53
54
|
p.tags << Tag.new(:name => "Amazing")
|
54
55
|
p.tags << Tag.new(:name => "Awesome")
|
55
56
|
p.tags << Tag.new(:name => "Superb")
|
56
57
|
p.save
|
57
58
|
=> true
|
58
59
|
p._keywords
|
59
|
-
=> ["amazing", "apple", "awesome", "iphone", "superb"]
|
60
|
+
=> ["amazing", "apple", "awesome", "iphone", "superb", "Info-summary", "Info-description"]
|
60
61
|
|
61
62
|
Now you can run search, which will look in the _keywords field and return all matching results:
|
62
63
|
|
@@ -73,6 +74,9 @@ code to search for 'iphone' in products cheaper than $499
|
|
73
74
|
|
74
75
|
@category.products.where(:price.lt => 499).full_text_search('iphone').asc(:price)
|
75
76
|
|
77
|
+
To index or reindex all existing records, run this rake task
|
78
|
+
|
79
|
+
$ rake mongoid_search:index
|
76
80
|
|
77
81
|
Options
|
78
82
|
-------
|
@@ -113,7 +117,7 @@ relevant_search:
|
|
113
117
|
Product.full_text_search('amazing apple', relevant_search: true)
|
114
118
|
=> [#<Product _id: 5016e7d16af54efe1c000001, _type: nil, brand: "Apple", name: "iPhone", attrs: nil, info: nil, category_id: nil, _keywords: ["amazing", "apple", "awesome", "iphone", "superb"], relevance: 2.0>]
|
115
119
|
|
116
|
-
Please note that relevant_search will return an Array and not a Criteria object. The search method
|
120
|
+
Please note that relevant_search will return an Array and not a Criteria object. The search method should always be called in the end of the method chain.
|
117
121
|
|
118
122
|
Initializer
|
119
123
|
-----------
|
@@ -155,7 +159,7 @@ Alternatively, you can create an initializer to setup those options:
|
|
155
159
|
config.regex = Proc.new { |query| /#{query}/ }
|
156
160
|
|
157
161
|
## Match partial words on the beginning or in the end (slightly faster)
|
158
|
-
# config.regex = Proc.new { |query|
|
162
|
+
# config.regex = Proc.new { |query| /^#{query}/ }
|
159
163
|
# config.regex = Proc.new { |query| /#{query}$/ }
|
160
164
|
|
161
165
|
# Ligatures to be replaced
|
@@ -165,4 +169,3 @@ Alternatively, you can create an initializer to setup those options:
|
|
165
169
|
# Minimum word size. Words smaller than it won't be indexed
|
166
170
|
config.minimum_word_size = 2
|
167
171
|
end
|
168
|
-
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.3
|
data/lib/mongoid_search.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require 'mongoid_search/railtie' if defined?(Rails)
|
4
3
|
require 'mongoid_search/mongoid_search'
|
5
4
|
|
5
|
+
if defined?(Rails)
|
6
|
+
require 'mongoid_search/railtie'
|
7
|
+
end
|
8
|
+
|
6
9
|
module Mongoid::Search
|
7
10
|
## Default matching type. Match :any or :all searched keywords
|
8
11
|
mattr_accessor :match
|
@@ -45,7 +48,7 @@ module Mongoid::Search
|
|
45
48
|
@@regex = Proc.new { |query| /#{query}/ }
|
46
49
|
|
47
50
|
## Match partial words on the beginning or in the end (slightly faster)
|
48
|
-
# @@regex = Proc.new { |query|
|
51
|
+
# @@regex = Proc.new { |query| /^#{query}/ }
|
49
52
|
# @@regex = Proc.new { |query| /#{query}$/ }
|
50
53
|
|
51
54
|
# Ligatures to be replaced
|
@@ -63,4 +66,4 @@ module Mongoid::Search
|
|
63
66
|
end
|
64
67
|
|
65
68
|
require 'mongoid_search/util'
|
66
|
-
require 'mongoid_search/log'
|
69
|
+
require 'mongoid_search/log'
|
@@ -1,11 +1,10 @@
|
|
1
1
|
module Mongoid::Search
|
2
|
-
|
3
|
-
base.send(:cattr_accessor, :search_fields)
|
4
|
-
|
5
|
-
base.extend ClassMethods
|
2
|
+
extend ActiveSupport::Concern
|
6
3
|
|
4
|
+
included do
|
5
|
+
cattr_accessor :search_fields
|
7
6
|
@@classes ||= []
|
8
|
-
@@classes <<
|
7
|
+
@@classes << self
|
9
8
|
end
|
10
9
|
|
11
10
|
def self.classes
|
@@ -15,7 +14,7 @@ module Mongoid::Search
|
|
15
14
|
module ClassMethods #:nodoc:
|
16
15
|
# Set a field or a number of fields as sources for search
|
17
16
|
def search_in(*args)
|
18
|
-
args,
|
17
|
+
args, _options = args_and_options(args)
|
19
18
|
self.search_fields = (self.search_fields || []).concat args
|
20
19
|
|
21
20
|
field :_keywords, :type => Array
|
@@ -27,6 +26,8 @@ module Mongoid::Search
|
|
27
26
|
|
28
27
|
def full_text_search(query, options={})
|
29
28
|
options = extract_options(options)
|
29
|
+
attr_accessor :relevance if options[:relevant_search].eql? true
|
30
|
+
|
30
31
|
return (options[:allow_empty_search] ? criteria.all : []) if query.blank?
|
31
32
|
|
32
33
|
if options[:relevant_search]
|
@@ -47,6 +48,7 @@ module Mongoid::Search
|
|
47
48
|
end
|
48
49
|
|
49
50
|
private
|
51
|
+
|
50
52
|
def query(keywords, options)
|
51
53
|
keywords_hash = keywords.map do |kw|
|
52
54
|
kw = Mongoid::Search.regex.call(kw) if Mongoid::Search.regex_search
|
@@ -58,9 +60,9 @@ module Mongoid::Search
|
|
58
60
|
|
59
61
|
def args_and_options(args)
|
60
62
|
options = args.last.is_a?(Hash) &&
|
61
|
-
|
62
|
-
|
63
|
-
|
63
|
+
[:match,
|
64
|
+
:allow_empty_search,
|
65
|
+
:relevant_search].include?(args.last.keys.first) ? args.pop : {}
|
64
66
|
|
65
67
|
[args, extract_options(options)]
|
66
68
|
end
|
@@ -93,25 +95,25 @@ module Mongoid::Search
|
|
93
95
|
keywords = Mongoid::Search::Util.normalize_keywords(query)
|
94
96
|
|
95
97
|
map = %Q{
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
98
|
+
function() {
|
99
|
+
var entries = 0;
|
100
|
+
for(i in keywords) {
|
101
|
+
for(j in this._keywords) {
|
102
|
+
if(this._keywords[j] == keywords[i]) {
|
103
|
+
entries++;
|
104
|
+
}
|
102
105
|
}
|
103
106
|
}
|
107
|
+
if(entries > 0) {
|
108
|
+
emit(this, entries);
|
109
|
+
}
|
104
110
|
}
|
105
|
-
if(entries > 0) {
|
106
|
-
emit(this, entries);
|
107
|
-
}
|
108
|
-
}
|
109
111
|
}
|
110
112
|
|
111
113
|
reduce = %Q{
|
112
|
-
|
113
|
-
|
114
|
-
|
114
|
+
function(key, values) {
|
115
|
+
return(values);
|
116
|
+
}
|
115
117
|
}
|
116
118
|
|
117
119
|
query(keywords, options).map_reduce(map, reduce).scope(:keywords => keywords).out(:inline => 1)
|
@@ -122,7 +124,6 @@ module Mongoid::Search
|
|
122
124
|
update_attribute(:_keywords, set_keywords)
|
123
125
|
end
|
124
126
|
|
125
|
-
private
|
126
127
|
def set_keywords
|
127
128
|
self._keywords = Mongoid::Search::Util.keywords(self, self.search_fields).
|
128
129
|
flatten.reject{|k| k.nil? || k.empty?}.uniq.sort
|
@@ -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
@@ -42,7 +42,7 @@ module Mongoid::Search::Util
|
|
42
42
|
downcase.
|
43
43
|
to_s.
|
44
44
|
gsub(/[._:;'"`,?|+={}()!@#%^&*<>~\$\-\\\/\[\]]/, ' '). # strip punctuation
|
45
|
-
gsub(/[
|
45
|
+
gsub(/[^\s\p{Alnum}]/,''). # strip accents
|
46
46
|
gsub(/[#{ligatures.keys.join("")}]/) {|c| ligatures[c]}.
|
47
47
|
split(' ').
|
48
48
|
reject { |word| word.size < Mongoid::Search.minimum_word_size }
|
data/spec/models/category.rb
CHANGED
data/spec/models/product.rb
CHANGED
data/spec/models/subproduct.rb
CHANGED
data/spec/models/tag.rb
CHANGED
data/spec/mongoid_search_spec.rb
CHANGED
@@ -18,19 +18,19 @@ describe Mongoid::Search do
|
|
18
18
|
Mongoid::Search.ignore_list = nil
|
19
19
|
Mongoid::Search.stem_proc = @default_proc
|
20
20
|
@product = Product.create :brand => "Apple",
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
:name => "iPhone",
|
22
|
+
:tags => (@tags = ["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
27
|
end
|
28
28
|
|
29
29
|
describe "Serialized hash fields" do
|
30
30
|
context "when the hash is populated" do
|
31
31
|
it "should return the product" do
|
32
|
-
Product.full_text_search("Info-summary").first.
|
33
|
-
Product.full_text_search("Info-description").first.
|
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
|
|
@@ -41,8 +41,8 @@ describe Mongoid::Search do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
it "should not return the product" do
|
44
|
-
Product.full_text_search("Info-description").size.
|
45
|
-
Product.full_text_search("Info-summary").size.
|
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
|
@@ -52,49 +52,50 @@ describe Mongoid::Search do
|
|
52
52
|
Mongoid::Search.stem_keywords = false
|
53
53
|
Mongoid::Search.ignore_list = nil
|
54
54
|
@product = Product.create :brand => "Эльбрус",
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
55
|
+
:name => "Процессор",
|
56
|
+
:tags => ["Amazing", "Awesome", "Olé"].map { |tag| Tag.new(:name => tag) },
|
57
|
+
:category => Category.new(:name => "процессоры"),
|
58
|
+
:subproducts => []
|
59
59
|
end
|
60
60
|
|
61
61
|
it "should leave utf8 characters" do
|
62
|
-
@product._keywords.
|
62
|
+
expect(@product._keywords).to eq ["amazing", "awesome", "ole", "процессор", "процессоры", "эльбрус"]
|
63
63
|
end
|
64
64
|
|
65
65
|
it "should return results in search when case doesn't match" do
|
66
|
-
Product.full_text_search("ЭЛЬБРУС").size.
|
66
|
+
expect(Product.full_text_search("ЭЛЬБРУС").size).to eq 1
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
70
|
context "when references are nil" do
|
71
71
|
context "when instance is being created" do
|
72
72
|
it "should not complain about method missing" do
|
73
|
-
|
73
|
+
expect { Product.create! }.not_to raise_error
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
|
77
|
+
it 'should validate keywords' do
|
78
|
+
product = Product.create :brand => "Apple", :name => "iPhone"
|
79
|
+
expect(product._keywords).to eq(["apple", "iphone"])
|
80
|
+
end
|
80
81
|
end
|
81
82
|
|
82
83
|
|
83
84
|
it "should set the _keywords field for array fields also" do
|
84
85
|
@product.attrs = ['lightweight', 'plastic', :red]
|
85
86
|
@product.save!
|
86
|
-
@product._keywords.
|
87
|
+
expect(@product._keywords).to include 'lightweight', 'plastic', 'red'
|
87
88
|
end
|
88
89
|
|
89
90
|
it "should inherit _keywords field and build upon" do
|
90
91
|
variant = Variant.create :brand => "Apple",
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
variant._keywords.
|
97
|
-
Variant.full_text_search(:name => 'Apple', :color => :white).
|
92
|
+
:name => "iPhone",
|
93
|
+
:tags => ["Amazing", "Awesome", "Olé"].map { |tag| Tag.new(:name => tag) },
|
94
|
+
:category => Category.new(:name => "Mobile"),
|
95
|
+
:subproducts => [Subproduct.new(:brand => "Apple", :name => "Craddle")],
|
96
|
+
:color => :white
|
97
|
+
expect(variant._keywords).to include 'white'
|
98
|
+
expect(Variant.full_text_search(:name => 'Apple', :color => :white)).to eq [variant]
|
98
99
|
end
|
99
100
|
|
100
101
|
it "should expand the ligature to ease searching" do
|
@@ -102,115 +103,115 @@ describe Mongoid::Search do
|
|
102
103
|
variant1 = Variant.create :tags => ["œuvre"].map {|tag| Tag.new(:name => tag)}
|
103
104
|
variant2 = Variant.create :tags => ["æquo"].map {|tag| Tag.new(:name => tag)}
|
104
105
|
|
105
|
-
Variant.full_text_search("œuvre").
|
106
|
-
Variant.full_text_search("oeuvre").
|
107
|
-
Variant.full_text_search("æquo").
|
108
|
-
Variant.full_text_search("aequo").
|
106
|
+
expect(Variant.full_text_search("œuvre")).to eq [variant1]
|
107
|
+
expect(Variant.full_text_search("oeuvre")).to eq [variant1]
|
108
|
+
expect(Variant.full_text_search("æquo")).to eq [variant2]
|
109
|
+
expect(Variant.full_text_search("aequo")).to eq [variant2]
|
109
110
|
end
|
110
111
|
|
111
112
|
it "should set the _keywords field with stemmed words if stem is enabled" do
|
112
113
|
Mongoid::Search.stem_keywords = true
|
113
114
|
@product.save!
|
114
|
-
@product._keywords.sort.
|
115
|
+
expect(@product._keywords.sort).to eq ["amaz", "appl", "awesom", "craddl", "iphon", "mobil", "review", "ol", "info", "descript", "summari"].sort
|
115
116
|
end
|
116
117
|
|
117
118
|
it "should set the _keywords field with custom stemmed words if stem is enabled with a custom lambda" do
|
118
119
|
Mongoid::Search.stem_keywords = true
|
119
120
|
Mongoid::Search.stem_proc = Proc.new { |word| word.upcase }
|
120
121
|
@product.save!
|
121
|
-
@product._keywords.sort.
|
122
|
+
expect(@product._keywords.sort).to eq ["AMAZING", "APPLE", "AWESOME", "CRADDLE", "DESCRIPTION", "INFO", "IPHONE", "MOBILE", "OLE", "REVIEWS", "SUMMARY"]
|
122
123
|
end
|
123
124
|
|
124
125
|
it "should ignore keywords in an ignore list" do
|
125
126
|
Mongoid::Search.ignore_list = YAML.load(File.open(File.dirname(__FILE__) + '/config/ignorelist.yml'))["ignorelist"]
|
126
127
|
@product.save!
|
127
|
-
@product._keywords.sort.
|
128
|
+
expect(@product._keywords.sort).to eq ["apple", "craddle", "iphone", "mobile", "reviews", "ole", "info", "description", "summary"].sort
|
128
129
|
end
|
129
130
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
131
|
+
it "should incorporate numbers as keywords" do
|
132
|
+
@product = Product.create :brand => "Ford",
|
133
|
+
:name => "T 1908",
|
134
|
+
:tags => ["Amazing", "First", "Car"].map { |tag| Tag.new(:name => tag) },
|
135
|
+
:category => Category.new(:name => "Vehicle")
|
135
136
|
|
136
|
-
|
137
|
-
|
138
|
-
|
137
|
+
@product.save!
|
138
|
+
expect(@product._keywords).to eq ["1908", "amazing", "car", "first", "ford", "vehicle"]
|
139
|
+
end
|
139
140
|
|
140
141
|
it "should return results in search" do
|
141
|
-
|
142
|
+
expect(Product.full_text_search("apple").size).to eq 1
|
142
143
|
end
|
143
144
|
|
144
145
|
it "should return results in search for dynamic attribute" do
|
145
146
|
@product[:outlet] = "online shop"
|
146
147
|
@product.save!
|
147
|
-
|
148
|
+
expect(Product.full_text_search("online").size).to eq 1
|
148
149
|
end
|
149
150
|
|
150
151
|
it "should return results in search even searching a accented word" do
|
151
|
-
|
152
|
-
|
152
|
+
expect(Product.full_text_search("Ole").size).to eq 1
|
153
|
+
expect(Product.full_text_search("Olé").size).to eq 1
|
153
154
|
end
|
154
155
|
|
155
156
|
it "should return results in search even if the case doesn't match" do
|
156
|
-
|
157
|
+
expect(Product.full_text_search("oLe").size).to eq 1
|
157
158
|
end
|
158
159
|
|
159
160
|
it "should return results in search with a partial word by default" do
|
160
|
-
|
161
|
+
expect(Product.full_text_search("iph").size).to eq 1
|
161
162
|
end
|
162
163
|
|
163
164
|
it "should return results for any matching word with default search" do
|
164
|
-
|
165
|
+
expect(Product.full_text_search("apple motorola").size).to eq 1
|
165
166
|
end
|
166
167
|
|
167
168
|
it "should not return results when all words do not match, if using :match => :all" do
|
168
169
|
Mongoid::Search.match = :all
|
169
|
-
|
170
|
+
expect(Product.full_text_search("apple motorola").size).to eq 0
|
170
171
|
end
|
171
172
|
|
172
173
|
it "should return results for any matching word, using :match => :all, passing :match => :any to .full_text_search" do
|
173
174
|
Mongoid::Search.match = :all
|
174
|
-
|
175
|
+
expect(Product.full_text_search("apple motorola", :match => :any).size).to eq 1
|
175
176
|
end
|
176
177
|
|
177
178
|
it "should not return results when all words do not match, passing :match => :all to .full_text_search" do
|
178
|
-
|
179
|
+
expect(Product.full_text_search("apple motorola", :match => :all).size).to eq 0
|
179
180
|
end
|
180
181
|
|
181
182
|
it "should return no results when a blank search is made" do
|
182
183
|
Mongoid::Search.allow_empty_search = false
|
183
|
-
|
184
|
+
expect(Product.full_text_search("").size).to eq 0
|
184
185
|
end
|
185
186
|
|
186
187
|
it "should return results when a blank search is made when :allow_empty_search is true" do
|
187
188
|
Mongoid::Search.allow_empty_search = true
|
188
|
-
|
189
|
+
expect(Product.full_text_search("").size).to eq 1
|
189
190
|
end
|
190
191
|
|
191
192
|
it "should search for embedded documents" do
|
192
|
-
|
193
|
+
expect(Product.full_text_search("craddle").size).to eq 1
|
193
194
|
end
|
194
195
|
|
195
196
|
it "should search for reference documents" do
|
196
|
-
|
197
|
+
expect(Product.full_text_search("reviews").size).to eq 1
|
197
198
|
end
|
198
199
|
|
199
200
|
it 'should work in a chainable fashion' do
|
200
|
-
@product.category.products.where(:brand => 'Apple').full_text_search('apple').size.
|
201
|
-
@product.category.products.full_text_search('craddle').where(:brand => 'Apple').size.
|
201
|
+
expect(@product.category.products.where(:brand => 'Apple').full_text_search('apple').size).to eq 1
|
202
|
+
expect(@product.category.products.full_text_search('craddle').where(:brand => 'Apple').size).to eq 1
|
202
203
|
end
|
203
204
|
|
204
205
|
it 'should return the classes that include the search module' do
|
205
|
-
Mongoid::Search.classes.
|
206
|
+
expect(Mongoid::Search.classes).to eq [Product, Tag]
|
206
207
|
end
|
207
208
|
|
208
209
|
it 'should have a method to index keywords' do
|
209
|
-
@product.index_keywords
|
210
|
+
expect(@product.index_keywords!).to eq true
|
210
211
|
end
|
211
212
|
|
212
213
|
it 'should have a class method to index all documents keywords' do
|
213
|
-
Product.index_keywords
|
214
|
+
expect(Product.index_keywords!).not_to include(false)
|
214
215
|
end
|
215
216
|
|
216
217
|
context "when regex search is false" do
|
@@ -219,11 +220,60 @@ describe Mongoid::Search do
|
|
219
220
|
end
|
220
221
|
|
221
222
|
it "should not return results in search with a partial word if not using regex search" do
|
222
|
-
|
223
|
+
expect(Product.full_text_search("iph").size).to eq 0
|
223
224
|
end
|
224
225
|
|
225
226
|
it "should return results in search with a full word if not using regex search" do
|
226
|
-
|
227
|
+
expect(Product.full_text_search("iphone").size).to eq 1
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context "when regex search is true" do
|
232
|
+
|
233
|
+
before do
|
234
|
+
Mongoid::Search.regex_search = true
|
235
|
+
end
|
236
|
+
|
237
|
+
after do
|
238
|
+
Mongoid::Search.regex_search = false
|
239
|
+
end
|
240
|
+
|
241
|
+
it "should not return results in search with a partial word if using regex search" do
|
242
|
+
expect(Product.full_text_search("iph").size).to eq 1
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should return results in search with a full word if using regex search" do
|
246
|
+
expect(Product.full_text_search("iphone").size).to eq 1
|
247
|
+
end
|
248
|
+
|
249
|
+
context 'Match partial words on the beginning' do
|
250
|
+
|
251
|
+
before do
|
252
|
+
Mongoid::Search.regex = Proc.new { |query| /^#{query}/ }
|
253
|
+
end
|
254
|
+
|
255
|
+
it "should return results in search which starts with query string" do
|
256
|
+
expect(Product.full_text_search("iphone").size).to eq 1
|
257
|
+
end
|
258
|
+
|
259
|
+
it "should not return results in search which does not start with query string" do
|
260
|
+
expect(Product.full_text_search("phone").size).to eq 0
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
context 'Match partial words on the end' do
|
265
|
+
|
266
|
+
before do
|
267
|
+
Mongoid::Search.regex = Proc.new { |query| /#{query}$/ }
|
268
|
+
end
|
269
|
+
|
270
|
+
it "should return results in search which ends with query string" do
|
271
|
+
expect(Product.full_text_search("phone").size).to eq 1
|
272
|
+
end
|
273
|
+
|
274
|
+
it "should not return results in search which does not end with query string" do
|
275
|
+
expect(Product.full_text_search("phon").size).to eq 0
|
276
|
+
end
|
227
277
|
end
|
228
278
|
end
|
229
279
|
|
@@ -234,40 +284,61 @@ describe Mongoid::Search do
|
|
234
284
|
end
|
235
285
|
|
236
286
|
it "should return results ordered by relevance and with correct ids" do
|
237
|
-
|
287
|
+
expect(Product.full_text_search('apple imac').map(&:_id)).to eq [@imac._id, @product._id]
|
238
288
|
end
|
239
289
|
|
240
290
|
it "results should be recognized as persisted objects" do
|
241
|
-
|
291
|
+
expect(Product.full_text_search('apple imac').map(&:persisted?)).not_to include false
|
242
292
|
end
|
243
293
|
|
244
294
|
it "should include relevance information" do
|
245
|
-
|
295
|
+
expect(Product.full_text_search('apple imac').map(&:relevance)).to eq [2, 1]
|
246
296
|
end
|
247
297
|
end
|
248
298
|
|
249
299
|
context "when using methods for keywords" do
|
250
300
|
it "should set the _keywords from methods" do
|
251
|
-
@tags.first._keywords.
|
301
|
+
expect(@tags.first._keywords).to include "amazing"
|
252
302
|
end
|
253
303
|
end
|
254
304
|
|
255
305
|
context "when using deeply nested fields for keywords" do
|
256
306
|
context "when explicitly calling set_keywords" do
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
307
|
+
it "should set the _keywords from parent" do
|
308
|
+
@tags.first.send(:set_keywords)
|
309
|
+
expect(@tags.first._keywords).to eq ["amazing", "description", "info", "iphone", "mobile", "reviews", "summary"]
|
310
|
+
end
|
261
311
|
end
|
262
312
|
end
|
263
313
|
|
264
314
|
context "when using localized fields" do
|
265
315
|
it "should set the keywords from all localizations" do
|
266
316
|
@product = Product.create :brand => "Ford",
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
@product._keywords.
|
317
|
+
:name => "T 1908",
|
318
|
+
:tags => ["Amazing", "First", "Car"].map { |tag| Tag.new(:name => tag) },
|
319
|
+
:category => Category.new(:name_translations => { :en => "Vehicle", :de => "Fahrzeug" })
|
320
|
+
expect(@product._keywords).to include("fahrzeug")
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
context "minimum word size" do
|
325
|
+
before(:each) do
|
326
|
+
Mongoid::Search.minimum_word_size = 3
|
327
|
+
end
|
328
|
+
|
329
|
+
after(:each) do
|
330
|
+
Mongoid::Search.minimum_word_size = 2
|
331
|
+
end
|
332
|
+
|
333
|
+
it "should ignore keywords with length less than minimum word size" do
|
334
|
+
@product = Product.create :name => 'a'
|
335
|
+
expect(@product._keywords.size).to eq 0
|
336
|
+
|
337
|
+
@product = Product.create :name => 'ap'
|
338
|
+
expect(@product._keywords.size).to eq 0
|
339
|
+
|
340
|
+
@product = Product.create :name => 'app'
|
341
|
+
expect(@product._keywords.size).to eq 1
|
271
342
|
end
|
272
343
|
end
|
273
344
|
end
|
data/spec/util_spec.rb
CHANGED
@@ -18,56 +18,56 @@ describe Mongoid::Search::Util do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
it "should return an empty array if no text is passed" do
|
21
|
-
Mongoid::Search::Util.normalize_keywords("").
|
21
|
+
expect(Mongoid::Search::Util.normalize_keywords("")).to eq []
|
22
22
|
end
|
23
23
|
|
24
24
|
it "should return an array of keywords" do
|
25
|
-
Mongoid::Search::Util.normalize_keywords("keyword").class.
|
25
|
+
expect(Mongoid::Search::Util.normalize_keywords("keyword").class).to eq Array
|
26
26
|
end
|
27
27
|
|
28
28
|
it "should return an array of strings" do
|
29
|
-
Mongoid::Search::Util.normalize_keywords("keyword").first.class.
|
29
|
+
expect(Mongoid::Search::Util.normalize_keywords("keyword").first.class).to eq String
|
30
30
|
end
|
31
31
|
|
32
32
|
it "should remove accents from the text passed" do
|
33
|
-
Mongoid::Search::Util.normalize_keywords("café").
|
33
|
+
expect(Mongoid::Search::Util.normalize_keywords("café")).to eq ["cafe"]
|
34
34
|
end
|
35
35
|
|
36
36
|
it "should downcase the text passed" do
|
37
|
-
Mongoid::Search::Util.normalize_keywords("CaFé").
|
37
|
+
expect(Mongoid::Search::Util.normalize_keywords("CaFé")).to eq ["cafe"]
|
38
38
|
end
|
39
39
|
|
40
40
|
it "should downcase utf-8 chars of the text passed" do
|
41
|
-
Mongoid::Search::Util.normalize_keywords("Кафе").
|
41
|
+
expect(Mongoid::Search::Util.normalize_keywords("Кафе")).to eq ["кафе"]
|
42
42
|
end
|
43
43
|
|
44
44
|
it "should split whitespaces, hifens, dots, underlines, etc.." do
|
45
|
-
Mongoid::Search::Util.normalize_keywords("CaFé-express.com delicious;come visit, and 'win' an \"iPad\"").
|
45
|
+
expect(Mongoid::Search::Util.normalize_keywords("CaFé-express.com delicious;come visit, and 'win' an \"iPad\"")).to eq ["cafe", "express", "com", "delicious", "come", "visit", "and", "win", "an", "ipad"]
|
46
46
|
end
|
47
47
|
|
48
48
|
it "should stem keywords" do
|
49
49
|
Mongoid::Search.stem_keywords = true
|
50
|
-
Mongoid::Search::Util.normalize_keywords("A runner running and eating").
|
50
|
+
expect(Mongoid::Search::Util.normalize_keywords("A runner running and eating")).to eq ["runner", "run", "and", "eat"]
|
51
51
|
end
|
52
52
|
|
53
53
|
it "should stem keywords using a custom proc" do
|
54
54
|
Mongoid::Search.stem_keywords = true
|
55
55
|
Mongoid::Search.stem_proc = lambda { |word| word.upcase }
|
56
56
|
|
57
|
-
Mongoid::Search::Util.normalize_keywords("A runner running and eating").
|
57
|
+
expect(Mongoid::Search::Util.normalize_keywords("A runner running and eating")).to eq ["RUNNER", "RUNNING", "AND", "EATING"]
|
58
58
|
end
|
59
59
|
|
60
60
|
it "should ignore keywords from ignore list" do
|
61
61
|
Mongoid::Search.stem_keywords = true
|
62
62
|
Mongoid::Search.ignore_list = YAML.load(File.open(File.dirname(__FILE__) + '/config/ignorelist.yml'))["ignorelist"]
|
63
|
-
Mongoid::Search::Util.normalize_keywords("An amazing awesome runner running and eating").
|
63
|
+
expect(Mongoid::Search::Util.normalize_keywords("An amazing awesome runner running and eating")).to eq ["an", "runner", "run", "and", "eat"]
|
64
64
|
end
|
65
65
|
|
66
66
|
it "should ignore keywords with less than two words" do
|
67
|
-
Mongoid::Search::Util.normalize_keywords("A runner running").
|
67
|
+
expect(Mongoid::Search::Util.normalize_keywords("A runner running")).not_to include "a"
|
68
68
|
end
|
69
69
|
|
70
70
|
it "should not ignore numbers" do
|
71
|
-
Mongoid::Search::Util.normalize_keywords("Ford T 1908").
|
71
|
+
expect(Mongoid::Search::Util.normalize_keywords("Ford T 1908")).to include "1908"
|
72
72
|
end
|
73
73
|
end
|
metadata
CHANGED
@@ -1,94 +1,83 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid_search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 0.3.2
|
4
|
+
version: 0.3.3
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Mauricio Zaffari
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2017-11-03 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: mongoid
|
16
|
-
type: :runtime
|
17
15
|
requirement: !ruby/object:Gem::Requirement
|
18
|
-
none: false
|
19
16
|
requirements:
|
20
|
-
- -
|
17
|
+
- - ">="
|
21
18
|
- !ruby/object:Gem::Version
|
22
19
|
version: 3.0.0
|
20
|
+
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: 3.0.0
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: fast-stemmer
|
32
|
-
type: :runtime
|
33
29
|
requirement: !ruby/object:Gem::Requirement
|
34
|
-
none: false
|
35
30
|
requirements:
|
36
|
-
- - ~>
|
31
|
+
- - "~>"
|
37
32
|
- !ruby/object:Gem::Version
|
38
33
|
version: 1.0.0
|
34
|
+
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- - ~>
|
38
|
+
- - "~>"
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: 1.0.0
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: database_cleaner
|
48
|
-
type: :development
|
49
43
|
requirement: !ruby/object:Gem::Requirement
|
50
|
-
none: false
|
51
44
|
requirements:
|
52
|
-
- -
|
45
|
+
- - ">="
|
53
46
|
- !ruby/object:Gem::Version
|
54
47
|
version: 0.8.0
|
48
|
+
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - ">="
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: 0.8.0
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: rake
|
64
|
-
type: :development
|
65
57
|
requirement: !ruby/object:Gem::Requirement
|
66
|
-
none: false
|
67
58
|
requirements:
|
68
|
-
- -
|
59
|
+
- - "<"
|
69
60
|
- !ruby/object:Gem::Version
|
70
|
-
version: 0
|
61
|
+
version: '11.0'
|
62
|
+
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - "<"
|
76
67
|
- !ruby/object:Gem::Version
|
77
|
-
version: 0
|
68
|
+
version: '11.0'
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: rspec
|
80
|
-
type: :development
|
81
71
|
requirement: !ruby/object:Gem::Requirement
|
82
|
-
none: false
|
83
72
|
requirements:
|
84
|
-
- - ~>
|
73
|
+
- - "~>"
|
85
74
|
- !ruby/object:Gem::Version
|
86
75
|
version: '2.4'
|
76
|
+
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
|
-
- - ~>
|
80
|
+
- - "~>"
|
92
81
|
- !ruby/object:Gem::Version
|
93
82
|
version: '2.4'
|
94
83
|
description: Simple full text search implementation.
|
@@ -98,15 +87,16 @@ executables: []
|
|
98
87
|
extensions: []
|
99
88
|
extra_rdoc_files: []
|
100
89
|
files:
|
101
|
-
- lib/mongoid_search/log.rb
|
102
|
-
- lib/mongoid_search/mongoid_search.rb
|
103
|
-
- lib/mongoid_search/railtie.rb
|
104
|
-
- lib/mongoid_search/util.rb
|
105
|
-
- lib/mongoid_search.rb
|
106
90
|
- LICENSE
|
107
91
|
- README.md
|
108
92
|
- Rakefile
|
109
93
|
- VERSION
|
94
|
+
- lib/mongoid_search.rb
|
95
|
+
- lib/mongoid_search/log.rb
|
96
|
+
- lib/mongoid_search/mongoid_search.rb
|
97
|
+
- lib/mongoid_search/railtie.rb
|
98
|
+
- lib/mongoid_search/tasks/mongoid_search.rake
|
99
|
+
- lib/mongoid_search/util.rb
|
110
100
|
- spec/config/ignorelist.yml
|
111
101
|
- spec/models/category.rb
|
112
102
|
- spec/models/product.rb
|
@@ -117,36 +107,36 @@ files:
|
|
117
107
|
- spec/spec_helper.rb
|
118
108
|
- spec/util_spec.rb
|
119
109
|
homepage: http://www.papodenerd.net/mongoid-search-full-text-search-for-your-mongoid-models/
|
120
|
-
licenses:
|
110
|
+
licenses:
|
111
|
+
- MIT
|
112
|
+
metadata: {}
|
121
113
|
post_install_message:
|
122
114
|
rdoc_options: []
|
123
115
|
require_paths:
|
124
116
|
- lib
|
125
117
|
required_ruby_version: !ruby/object:Gem::Requirement
|
126
|
-
none: false
|
127
118
|
requirements:
|
128
|
-
- -
|
119
|
+
- - ">="
|
129
120
|
- !ruby/object:Gem::Version
|
130
121
|
version: '0'
|
131
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
|
-
none: false
|
133
123
|
requirements:
|
134
|
-
- -
|
124
|
+
- - ">="
|
135
125
|
- !ruby/object:Gem::Version
|
136
126
|
version: 1.3.6
|
137
127
|
requirements: []
|
138
128
|
rubyforge_project:
|
139
|
-
rubygems_version:
|
129
|
+
rubygems_version: 2.6.12
|
140
130
|
signing_key:
|
141
|
-
specification_version:
|
131
|
+
specification_version: 4
|
142
132
|
summary: Search implementation for Mongoid ORM
|
143
133
|
test_files:
|
144
|
-
- spec/
|
134
|
+
- spec/models/variant.rb
|
145
135
|
- spec/models/category.rb
|
146
136
|
- spec/models/product.rb
|
147
|
-
- spec/models/subproduct.rb
|
148
137
|
- spec/models/tag.rb
|
149
|
-
- spec/models/
|
150
|
-
- spec/
|
138
|
+
- spec/models/subproduct.rb
|
139
|
+
- spec/config/ignorelist.yml
|
151
140
|
- spec/spec_helper.rb
|
152
141
|
- spec/util_spec.rb
|
142
|
+
- spec/mongoid_search_spec.rb
|