redis-textsearch 0.1.0 → 0.1.1
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.
- data/lib/redis/text_search.rb +10 -4
- data/spec/redis_text_search_core_spec.rb +2 -2
- data/spec/redis_text_search_sqlite_spec.rb +214 -0
- metadata +3 -2
data/lib/redis/text_search.rb
CHANGED
@@ -62,20 +62,26 @@ class Redis
|
|
62
62
|
# how to retrieve records. You can override it by explicitly defining a
|
63
63
|
# +text_search_find+ class method that takes an array of IDs as an argument.
|
64
64
|
def guess_text_search_find
|
65
|
-
if defined?(ActiveRecord::Base) and
|
65
|
+
if defined?(ActiveRecord::Base) and ancestors.include?(ActiveRecord::Base)
|
66
66
|
instance_eval <<-EndMethod
|
67
67
|
def text_search_find(ids, options)
|
68
|
+
puts "IDS=\#{ids.inspect}"
|
68
69
|
all(options.merge(:conditions => {:#{primary_key} => ids}))
|
69
70
|
end
|
70
71
|
EndMethod
|
71
|
-
elsif defined?(MongoRecord::Base) and
|
72
|
+
elsif defined?(MongoRecord::Base) and ancestors.include?(MongoRecord::Base)
|
72
73
|
instance_eval <<-EndMethod
|
73
74
|
def text_search_find(ids, options)
|
74
75
|
all(options.merge(:conditions => {:#{primary_key} => ids}))
|
75
76
|
end
|
76
77
|
EndMethod
|
77
|
-
elsif
|
78
|
-
|
78
|
+
elsif defined?(Sequel::Model) and ancestors.include?(Sequel::Model)
|
79
|
+
instance_eval <<-EndMethod
|
80
|
+
def text_search_find(ids, options)
|
81
|
+
all(options.merge(:conditions => {:#{primary_key} => ids}))
|
82
|
+
end
|
83
|
+
EndMethod
|
84
|
+
elsif defined?(DataMapper::Resource) and included_modules.include?(DataMapper::Resource)
|
79
85
|
instance_eval <<-EndMethod
|
80
86
|
def text_search_find(ids, options)
|
81
87
|
get(ids, options)
|
@@ -41,9 +41,9 @@ TAGS = [
|
|
41
41
|
|
42
42
|
describe Redis::TextSearch do
|
43
43
|
before :all do
|
44
|
-
@post = Post.new(:title => TITLES[0], :tags => TAGS[0], :id => 1)
|
44
|
+
@post = Post.new(:title => TITLES[0], :tags => TAGS[0] * ' ', :id => 1)
|
45
45
|
@post2 = Post.new(:title => TITLES[1], :tags => TAGS[1], :id => 2)
|
46
|
-
@post3 = Post.new(:title => TITLES[2], :tags => TAGS[2], :id => 3)
|
46
|
+
@post3 = Post.new(:title => TITLES[2], :tags => TAGS[2] * ' ', :id => 3)
|
47
47
|
|
48
48
|
@post.delete_text_indexes
|
49
49
|
@post2.delete_text_indexes
|
@@ -0,0 +1,214 @@
|
|
1
|
+
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
3
|
+
|
4
|
+
require 'active_record'
|
5
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => 'test.db')
|
6
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
7
|
+
|
8
|
+
def check_result_ids(results, ids, sort=true)
|
9
|
+
results.length.should == ids.length
|
10
|
+
if results.length > 0
|
11
|
+
results.first.should be_kind_of(ActiveRecord::Base)
|
12
|
+
end
|
13
|
+
if sort
|
14
|
+
results.collect{|m| m.id}.sort.should == ids.sort
|
15
|
+
else
|
16
|
+
results.collect{|m| m.id}.should == ids
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Post < ActiveRecord::Base
|
21
|
+
include Redis::TextSearch
|
22
|
+
include Marshal
|
23
|
+
|
24
|
+
text_index :title
|
25
|
+
text_index :tags, :exact => true
|
26
|
+
end
|
27
|
+
|
28
|
+
class CreatePosts < ActiveRecord::Migration
|
29
|
+
def self.up
|
30
|
+
create_table :posts do |t|
|
31
|
+
t.string :title
|
32
|
+
t.string :tags
|
33
|
+
t.timestamps
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.down
|
38
|
+
drop_table :posts
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
TITLES = [
|
43
|
+
'Some plain text',
|
44
|
+
'More plain textstring comments',
|
45
|
+
'Come get somebody personal comments',
|
46
|
+
'*Welcome to Nate\'s new BLOG!!',
|
47
|
+
]
|
48
|
+
|
49
|
+
TAGS = [
|
50
|
+
['personal', 'nontechnical'],
|
51
|
+
['mysql', 'technical'],
|
52
|
+
['gaming','technical']
|
53
|
+
]
|
54
|
+
|
55
|
+
|
56
|
+
describe Redis::TextSearch do
|
57
|
+
before :all do
|
58
|
+
CreatePosts.up
|
59
|
+
|
60
|
+
@post = Post.new(:title => TITLES[0], :tags => TAGS[0] * ' ')
|
61
|
+
# @post.id = 1
|
62
|
+
@post.save!
|
63
|
+
# sleep 1 # sqlite timestamps
|
64
|
+
@post2 = Post.new(:title => TITLES[1], :tags => TAGS[1] * ' ')
|
65
|
+
# @post2.id = 2
|
66
|
+
@post2.save!
|
67
|
+
# sleep 1 # sqlite timestamps
|
68
|
+
@post3 = Post.new(:title => TITLES[2], :tags => TAGS[2] * ' ')
|
69
|
+
# @post3.id = 3
|
70
|
+
@post3.save!
|
71
|
+
# sleep 1 # sqlite timestamps
|
72
|
+
|
73
|
+
@post.delete_text_indexes
|
74
|
+
@post2.delete_text_indexes
|
75
|
+
Post.delete_text_indexes(3)
|
76
|
+
end
|
77
|
+
|
78
|
+
after :all do
|
79
|
+
CreatePosts.down
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should define text indexes in the class" do
|
83
|
+
Post.text_indexes[:title][:key].should == 'post:text_index:title'
|
84
|
+
Post.text_indexes[:tags][:key].should == 'post:text_index:tags'
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should update text indexes correctly" do
|
88
|
+
@post.update_text_indexes
|
89
|
+
@post2.update_text_indexes
|
90
|
+
|
91
|
+
Post.redis.set_members('post:text_index:title:so').should == ['1']
|
92
|
+
Post.redis.set_members('post:text_index:title:som').should == ['1']
|
93
|
+
Post.redis.set_members('post:text_index:title:some').should == ['1']
|
94
|
+
Post.redis.set_members('post:text_index:title:pl').sort.should == ['1','2']
|
95
|
+
Post.redis.set_members('post:text_index:title:pla').sort.should == ['1','2']
|
96
|
+
Post.redis.set_members('post:text_index:title:plai').sort.should == ['1','2']
|
97
|
+
Post.redis.set_members('post:text_index:title:plain').sort.should == ['1','2']
|
98
|
+
Post.redis.set_members('post:text_index:title:te').sort.should == ['1','2']
|
99
|
+
Post.redis.set_members('post:text_index:title:tex').sort.should == ['1','2']
|
100
|
+
Post.redis.set_members('post:text_index:title:text').sort.should == ['1','2']
|
101
|
+
Post.redis.set_members('post:text_index:title:texts').should == ['2']
|
102
|
+
Post.redis.set_members('post:text_index:title:textst').should == ['2']
|
103
|
+
Post.redis.set_members('post:text_index:title:textstr').should == ['2']
|
104
|
+
Post.redis.set_members('post:text_index:title:textstri').should == ['2']
|
105
|
+
Post.redis.set_members('post:text_index:title:textstrin').should == ['2']
|
106
|
+
Post.redis.set_members('post:text_index:title:textstring').should == ['2']
|
107
|
+
Post.redis.set_members('post:text_index:tags:pe').should == []
|
108
|
+
Post.redis.set_members('post:text_index:tags:per').should == []
|
109
|
+
Post.redis.set_members('post:text_index:tags:pers').should == []
|
110
|
+
Post.redis.set_members('post:text_index:tags:perso').should == []
|
111
|
+
Post.redis.set_members('post:text_index:tags:person').should == []
|
112
|
+
Post.redis.set_members('post:text_index:tags:persona').should == []
|
113
|
+
Post.redis.set_members('post:text_index:tags:personal').should == ['1']
|
114
|
+
Post.redis.set_members('post:text_index:tags:no').should == []
|
115
|
+
Post.redis.set_members('post:text_index:tags:non').should == []
|
116
|
+
Post.redis.set_members('post:text_index:tags:nont').should == []
|
117
|
+
Post.redis.set_members('post:text_index:tags:nonte').should == []
|
118
|
+
Post.redis.set_members('post:text_index:tags:nontec').should == []
|
119
|
+
Post.redis.set_members('post:text_index:tags:nontech').should == []
|
120
|
+
Post.redis.set_members('post:text_index:tags:nontechn').should == []
|
121
|
+
Post.redis.set_members('post:text_index:tags:nontechni').should == []
|
122
|
+
Post.redis.set_members('post:text_index:tags:nontechnic').should == []
|
123
|
+
Post.redis.set_members('post:text_index:tags:nontechnica').should == []
|
124
|
+
Post.redis.set_members('post:text_index:tags:nontechnical').should == ['1']
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should search text indexes and return records" do
|
128
|
+
check_result_ids Post.text_search('some'), [1]
|
129
|
+
@post3.update_text_indexes
|
130
|
+
check_result_ids Post.text_search('some'), [1,3]
|
131
|
+
|
132
|
+
check_result_ids Post.text_search('plain'), [1,2]
|
133
|
+
check_result_ids Post.text_search('plain','text'), [1,2]
|
134
|
+
check_result_ids Post.text_search('plain','textstr'), [2]
|
135
|
+
check_result_ids Post.text_search('some','TExt'), [1]
|
136
|
+
check_result_ids Post.text_search('techNIcal'), [2,3]
|
137
|
+
check_result_ids Post.text_search('nontechnical'), [1]
|
138
|
+
check_result_ids Post.text_search('personal'), [1,3]
|
139
|
+
check_result_ids Post.text_search('personAL', :fields => :tags), [1]
|
140
|
+
check_result_ids Post.text_search('PERsonal', :fields => [:tags]), [1]
|
141
|
+
check_result_ids Post.text_search('nontechnical', :fields => [:title]), []
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should pass options thru to find" do
|
145
|
+
check_result_ids Post.text_search('some', :order => 'id desc'), [3,1], false
|
146
|
+
res = Post.text_search('some', :select => 'id,title', :order => 'tags desc')
|
147
|
+
check_result_ids res, [1,3]
|
148
|
+
res.first.title.should == TITLES[0]
|
149
|
+
res.last.title.should == TITLES[2]
|
150
|
+
|
151
|
+
error = nil
|
152
|
+
begin
|
153
|
+
res.first.tags
|
154
|
+
rescue => error
|
155
|
+
end
|
156
|
+
error.should be_kind_of ActiveRecord::MissingAttributeError
|
157
|
+
|
158
|
+
error = nil
|
159
|
+
begin
|
160
|
+
res.first.updated_at
|
161
|
+
rescue => error
|
162
|
+
end
|
163
|
+
error.should be_kind_of ActiveRecord::MissingAttributeError
|
164
|
+
|
165
|
+
error = nil
|
166
|
+
begin
|
167
|
+
res.first.created_at
|
168
|
+
rescue => error
|
169
|
+
end
|
170
|
+
error.should be_kind_of ActiveRecord::MissingAttributeError
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should handle pagination" do
|
174
|
+
res = Post.text_search('some', :page => 1, :per_page => 1, :order => 'id desc')
|
175
|
+
check_result_ids res, [3]
|
176
|
+
res.total_entries.should == 2
|
177
|
+
res.total_pages.should == 2
|
178
|
+
res.per_page.should == 1
|
179
|
+
res.current_page.should == 1
|
180
|
+
|
181
|
+
res = Post.text_search('some', :page => 2, :per_page => 1, :order => 'id desc')
|
182
|
+
check_result_ids res, [1]
|
183
|
+
res.total_entries.should == 2
|
184
|
+
res.total_pages.should == 2
|
185
|
+
res.per_page.should == 1
|
186
|
+
res.current_page.should == 2
|
187
|
+
|
188
|
+
res = Post.text_search('some', :page => 2, :per_page => 5)
|
189
|
+
check_result_ids res, []
|
190
|
+
res.total_entries.should == 2
|
191
|
+
res.total_pages.should == 1
|
192
|
+
res.per_page.should == 5
|
193
|
+
res.current_page.should == 2
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should support a hash to the text_search method" do
|
197
|
+
check_result_ids Post.text_search(:tags => 'technical'), [2,3]
|
198
|
+
check_result_ids Post.text_search(:tags => 'nontechnical'), [1]
|
199
|
+
check_result_ids Post.text_search(:tags => 'technical', :title => 'plain'), [2]
|
200
|
+
check_result_ids Post.text_search(:tags => ['technical','MYsql'], :title => 'Mo'), [2]
|
201
|
+
check_result_ids Post.text_search(:tags => ['technical','MYsql'], :title => 'some'), []
|
202
|
+
check_result_ids Post.text_search(:tags => 'technical', :title => 'comments'), [2,3]
|
203
|
+
end
|
204
|
+
|
205
|
+
# MUST BE LAST!!!!!!
|
206
|
+
it "should delete text indexes" do
|
207
|
+
@post.delete_text_indexes
|
208
|
+
@post2.delete_text_indexes
|
209
|
+
Post.delete_text_indexes(3)
|
210
|
+
@post.text_indexes.should == []
|
211
|
+
@post2.text_indexes.should == []
|
212
|
+
@post3.text_indexes.should == []
|
213
|
+
end
|
214
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-textsearch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nate Wiger
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-12-
|
12
|
+
date: 2009-12-04 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -34,6 +34,7 @@ files:
|
|
34
34
|
- lib/redis/text_search/collection.rb
|
35
35
|
- lib/redis/text_search.rb
|
36
36
|
- spec/redis_text_search_core_spec.rb
|
37
|
+
- spec/redis_text_search_sqlite_spec.rb
|
37
38
|
- spec/spec_helper.rb
|
38
39
|
- README.rdoc
|
39
40
|
has_rdoc: true
|