pose 2.0.1 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +44 -28
- data/lib/generators/pose/install/install_generator.rb +56 -0
- data/lib/generators/pose/install/templates/install_migration.rb +24 -0
- data/lib/pose.rb +3 -1
- data/lib/pose/{internal_helpers.rb → helpers.rb} +5 -29
- data/lib/pose/model_class_additions.rb +1 -1
- data/lib/pose/query.rb +85 -0
- data/lib/pose/search.rb +135 -0
- data/lib/pose/static_api.rb +4 -55
- data/lib/pose/version.rb +1 -1
- data/spec/dummy/app/models/posable_one.rb +2 -0
- data/spec/dummy/app/models/posable_two.rb +2 -0
- data/spec/dummy/app/models/user.rb +6 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20130308054001_create_posable_one.rb +1 -0
- data/spec/dummy/db/migrate/20130308054142_create_posable_two.rb +1 -0
- data/spec/dummy/db/migrate/20130708084009_create_users.rb +7 -0
- data/spec/dummy/db/schema.rb +8 -2
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +190 -147
- data/spec/dummy/log/test.log +85538 -30538
- data/spec/factories/posable_two.rb +5 -0
- data/spec/factories/user.rb +6 -0
- data/spec/lib/pose/helpers_spec.rb +147 -0
- data/spec/lib/pose/query_spec.rb +107 -0
- data/spec/lib/pose/search_spec.rb +360 -0
- data/spec/models/assignment_spec.rb +2 -2
- data/spec/models/word_spec.rb +1 -1
- data/spec/pose_api_spec.rb +58 -17
- data/spec/spec_helper.rb +5 -0
- metadata +63 -39
- data/spec/internal_helpers_spec.rb +0 -176
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a28304ad3e5a60d843f3df073cc68a0842b3a157
|
4
|
+
data.tar.gz: 8e1bb1ea33bcc319b84c06e8cd13a2332453bbfb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0c8b59c95e6a5cc7d1abf04743ece0b64882080c23a8e1dc96966ab2550ca6e858899ac2ef3d05f6d997df01d324c98598ba158dadede884d7fbf1dd77d23ed0
|
7
|
+
data.tar.gz: a628c6936417db7d987fb88a84b60149364507be84c4b3ad4808366e28885013f7867c8c99bf5d81853bec730ea423c94cd2d00170c39d581b5fb8eb1306201a
|
data/README.md
CHANGED
@@ -1,14 +1,13 @@
|
|
1
|
-
#
|
1
|
+
# POlymorphic SEarch <a href="http://travis-ci.org/#!/kevgo/pose" target="_blank"><img src="https://secure.travis-ci.org/kevgo/pose.png" alt="Build status"></a> [![Code Climate](https://codeclimate.com/github/kevgo/pose.png)](https://codeclimate.com/github/kevgo/pose) [![Coverage Status](https://coveralls.io/repos/kevgo/pose/badge.png?branch=master)](https://coveralls.io/r/kevgo/pose) [![Dependency Status](https://gemnasium.com/kevgo/pose.png)](https://gemnasium.com/kevgo/pose)
|
2
2
|
|
3
|
-
|
3
|
+
A database agnostic fulltext search engine for ActiveRecord objects in Ruby on Rails.
|
4
4
|
|
5
5
|
* Searches over several classes at once.
|
6
6
|
* The searchable content of each class and document can be freely customized.
|
7
|
-
* Uses the main Rails database
|
8
|
-
* Does not pollute the searchable classes
|
9
|
-
*
|
10
|
-
*
|
11
|
-
* The search is very fast, doing only simple queries over fully indexed columns.
|
7
|
+
* Uses the main Rails database - no separate servers, databases, or search engines required.
|
8
|
+
* Does not pollute the searchable classes nor their database tables.
|
9
|
+
* Very fast search, doing only simple queries over fully indexed columns.
|
10
|
+
* Allows to augment the fulltext search query with your own joins and where clauses.
|
12
11
|
|
13
12
|
|
14
13
|
## Installation
|
@@ -40,7 +39,7 @@ Pose creates two tables in your database. These tables are automatically populat
|
|
40
39
|
class MyClass < ActiveRecord::Base
|
41
40
|
|
42
41
|
# This line makes your class searchable.
|
43
|
-
# The given block must return the
|
42
|
+
# The given block must return the searchable content as a string.
|
44
43
|
posify do
|
45
44
|
|
46
45
|
# Only active instances should show up in search results.
|
@@ -65,12 +64,12 @@ Now that this class is posified, any `create`, `update`, or `delete` operation o
|
|
65
64
|
Data that existed in your database before adding Pose isn't automatically included in the search index.
|
66
65
|
You have to index those records manually once. Future updates will happen automatically.
|
67
66
|
|
68
|
-
To index all entries of `MyClass`, run `rake pose:reindex_all[MyClass]` on the command line.
|
67
|
+
To index all entries of `MyClass`, run `rake 'pose:reindex_all[MyClass]'` on the command line.
|
69
68
|
|
70
69
|
At this point, you are all set up. Let's perform a search!
|
71
70
|
|
72
71
|
|
73
|
-
|
72
|
+
### Upgrading from version 1.x
|
74
73
|
|
75
74
|
Version 2 is a proper Rails engine, and comes with a slightly different database table schema.
|
76
75
|
Upgrading is as simple as
|
@@ -108,7 +107,13 @@ search options.
|
|
108
107
|
|
109
108
|
### Configure the searched classes
|
110
109
|
|
111
|
-
Pose accepts an array of classes to search over.
|
110
|
+
Pose accepts an array of classes to search over.
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
result = Pose.search 'search text', [MyClass, MyOtherClass]
|
114
|
+
```
|
115
|
+
|
116
|
+
When searching a single class, it can be provided directly, i.e. not as an array.
|
112
117
|
|
113
118
|
```ruby
|
114
119
|
result = Pose.search 'foo', MyClass
|
@@ -117,34 +122,42 @@ result = Pose.search 'foo', MyClass
|
|
117
122
|
|
118
123
|
### Configure the result data
|
119
124
|
|
120
|
-
|
125
|
+
Search results are the instances of the objects matching the search query.
|
121
126
|
If you want to just get the ids of the search results, and not the full instances, use the parameter `:result_type`.
|
122
127
|
|
123
128
|
```ruby
|
124
|
-
|
129
|
+
# Returns ids instead of object instances.
|
130
|
+
result = Pose.search 'foo', MyClass, result_type: :ids
|
125
131
|
```
|
126
132
|
|
127
133
|
|
128
134
|
### Limit the amount of search results
|
129
135
|
|
130
|
-
By default, Pose returns all matching items.
|
136
|
+
By default, Pose returns all matching items.
|
131
137
|
To limit the result set, use the `:limit` search parameter.
|
132
138
|
|
133
139
|
```ruby
|
134
|
-
|
140
|
+
# Returns only 20 search results.
|
141
|
+
result = Pose.search 'foo', MyClass, limit: 20
|
135
142
|
```
|
136
143
|
|
137
144
|
|
138
145
|
### Combine fulltext search with structured data search
|
139
146
|
|
140
|
-
You can add your own ActiveRecord query clauses to a fulltext search operation.
|
147
|
+
You can add your own ActiveRecord query clauses (JOINs and WHEREs) to a fulltext search operation.
|
141
148
|
For example, given a class `Note` that belongs to a `User` class and has a boolean attribute `public`,
|
142
149
|
finding all public notes from other users containing "foo" is as easy as:
|
143
150
|
|
144
151
|
```ruby
|
145
|
-
result = Pose.search 'foo',
|
152
|
+
result = Pose.search 'foo',
|
153
|
+
Note,
|
154
|
+
joins: Note,
|
155
|
+
where: [ ['notes.public = ?', true],
|
156
|
+
['user_id <> ?', @current_user.id] ] ]
|
146
157
|
```
|
147
158
|
|
159
|
+
Combining ActiveRecord query clauses with fulltext search only works when searching over a single class.
|
160
|
+
|
148
161
|
|
149
162
|
## Maintenance
|
150
163
|
|
@@ -154,8 +167,8 @@ The search index is automatically updated when objects are created, updated, or
|
|
154
167
|
|
155
168
|
### Optimizing the search index
|
156
169
|
|
157
|
-
|
158
|
-
After deleting or changing a large number of objects, you can shrink the
|
170
|
+
The search index keeps all the words that were ever used around.
|
171
|
+
After deleting or changing a large number of objects, you can shrink the database storage consumption of Pose's search index by
|
159
172
|
removing no longer used search terms from it.
|
160
173
|
|
161
174
|
```bash
|
@@ -164,7 +177,7 @@ $ rake pose:index:vacuum
|
|
164
177
|
|
165
178
|
|
166
179
|
### Recreating the search index from scratch
|
167
|
-
To index existing data in your database, or after loading
|
180
|
+
To index existing data in your database, or after buld-loading data outside of ActiveRecord into your database,
|
168
181
|
you should recreate the search index from scratch.
|
169
182
|
|
170
183
|
```bash
|
@@ -180,14 +193,14 @@ To remove all traces of Pose from your database, run:
|
|
180
193
|
rails generate pose:remove
|
181
194
|
```
|
182
195
|
|
183
|
-
Also don't forget to remove the `posify` block from your models as well as the gem
|
196
|
+
Also don't forget to remove the `posify` block from your models as well as the _pose_ gem from your Gemfile.
|
184
197
|
|
185
198
|
|
186
199
|
## Use Pose in your tests
|
187
200
|
|
188
201
|
Pose can slow down your tests, because it updates the search index on every `:create`, `:update`, and `:delete`
|
189
202
|
operation in the database.
|
190
|
-
|
203
|
+
To avoid that in your not search-related tests, you can disable Pose in your `test` environments,
|
191
204
|
and only enable it for the tests that actually need search functionality.
|
192
205
|
|
193
206
|
To disable Pose for tests, add this line to `config/environments/test.rb`
|
@@ -196,7 +209,8 @@ To disable Pose for tests, add this line to `config/environments/test.rb`
|
|
196
209
|
Pose::CONFIGURATION[:perform_search] = false
|
197
210
|
```
|
198
211
|
|
199
|
-
Now, with search disabled in the test environment, enable Pose in some of your tests
|
212
|
+
Now, with search disabled in the test environment, enable Pose in some of your tests
|
213
|
+
by setting the same value to `true` inside the tests:
|
200
214
|
|
201
215
|
```ruby
|
202
216
|
|
@@ -221,27 +235,29 @@ end
|
|
221
235
|
|
222
236
|
If you find a bug, have a question, or a better idea, please open an issue on the
|
223
237
|
<a href="https://github.com/kevgo/pose/issues">Pose issue tracker</a>.
|
224
|
-
Or, clone the repository, make your changes, and submit a pull request
|
238
|
+
Or, clone the repository, make your changes, and submit a unit-tested pull request!
|
225
239
|
|
226
240
|
### Run the unit tests for the Pose Gem
|
227
241
|
|
228
|
-
|
242
|
+
Pose uses Sqlite3 for tests.
|
229
243
|
To run tests, first create a test database.
|
230
244
|
|
231
245
|
```bash
|
232
|
-
|
246
|
+
bundle
|
247
|
+
rake app:db:create
|
248
|
+
rake app:db:migrate
|
249
|
+
rake app:db:test:prepare
|
233
250
|
```
|
234
251
|
|
235
252
|
Then run the tests.
|
236
253
|
|
237
254
|
```bash
|
238
|
-
|
255
|
+
rake
|
239
256
|
```
|
240
257
|
|
241
258
|
|
242
259
|
### Road Map
|
243
260
|
|
244
|
-
* add `join` to search parameters
|
245
261
|
* pagination of search results
|
246
262
|
* ordering
|
247
263
|
* weighting search results
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
|
4
|
+
module Pose
|
5
|
+
module Generators
|
6
|
+
|
7
|
+
class InstallGenerator < Rails::Generators::Base
|
8
|
+
include Rails::Generators::Migration
|
9
|
+
source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
|
10
|
+
|
11
|
+
def create_migration_file
|
12
|
+
say ''
|
13
|
+
say ' Creating database migration for the Pose tables.'
|
14
|
+
say ''
|
15
|
+
migration_template 'install_migration.rb', 'db/migrate/install_pose.rb'
|
16
|
+
say ''
|
17
|
+
end
|
18
|
+
|
19
|
+
def installation_instructions
|
20
|
+
say ''
|
21
|
+
say ' All done! You need to do two things now:'
|
22
|
+
say ''
|
23
|
+
say ' 1. Run the database migration'
|
24
|
+
say ''
|
25
|
+
say ' rake db:migrate', Thor::Shell::Color::BOLD
|
26
|
+
say ''
|
27
|
+
say ''
|
28
|
+
say ' 2. Add a posify block to all your models.'
|
29
|
+
say ' Here is an example:'
|
30
|
+
say ''
|
31
|
+
say ' class MyClass < ActiveRecord::Base'
|
32
|
+
say ' ...'
|
33
|
+
say ''
|
34
|
+
say ' posify do', Thor::Shell::Color::BOLD
|
35
|
+
say ' # return searchable text as a string here', Thor::Shell::Color::BOLD
|
36
|
+
say ' end', Thor::Shell::Color::BOLD
|
37
|
+
say ''
|
38
|
+
say ' ...'
|
39
|
+
say ' end'
|
40
|
+
say ''
|
41
|
+
say ''
|
42
|
+
say ' Happy searching! :)'
|
43
|
+
say ''
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# Helper method for creating the migration.
|
50
|
+
def self.next_migration_number(path)
|
51
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class InstallPose < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table "pose_assignments" do |t|
|
5
|
+
t.integer "word_id", null: false
|
6
|
+
t.integer "posable_id", null: false
|
7
|
+
t.string "posable_type", limit: 40, null: false
|
8
|
+
end
|
9
|
+
|
10
|
+
add_index "pose_assignments", :word_id
|
11
|
+
add_index "pose_assignments", :posable_id
|
12
|
+
|
13
|
+
create_table "pose_words" do |t|
|
14
|
+
t.string "text", limit: 80, null: false
|
15
|
+
end
|
16
|
+
|
17
|
+
add_index "pose_words", :text
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.down
|
21
|
+
drop_table 'pose_assignments'
|
22
|
+
drop_table 'pose_words'
|
23
|
+
end
|
24
|
+
end
|
data/lib/pose.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require "pose/engine"
|
2
|
+
require 'pose/query'
|
3
|
+
require 'pose/search'
|
2
4
|
require 'pose/static_api'
|
3
|
-
require 'pose/
|
5
|
+
require 'pose/helpers'
|
4
6
|
require 'pose/activerecord_base_additions'
|
5
7
|
require 'pose/model_class_additions'
|
6
8
|
require 'pose/railtie' if defined? Rails
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# Internal helper methods for the Pose module.
|
2
|
+
# TODO: remove
|
2
3
|
module Pose
|
3
4
|
module Helpers
|
4
5
|
class <<self
|
@@ -41,33 +42,13 @@ module Pose
|
|
41
42
|
#
|
42
43
|
# @return [Boolean]
|
43
44
|
def is_url? word
|
44
|
-
|
45
|
-
rescue URI::InvalidURIError
|
46
|
-
false
|
45
|
+
/https?:\/\/(\w)+\.(\w+)/ =~ word
|
47
46
|
end
|
48
47
|
|
49
48
|
|
50
|
-
#
|
51
|
-
def
|
52
|
-
|
53
|
-
result[class_name] = result[class_name] & ids
|
54
|
-
else
|
55
|
-
result[class_name] = ids
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
|
60
|
-
# Returns a hash mapping classes to ids for the a single given word.
|
61
|
-
def search_classes_and_ids_for_word word, class_names
|
62
|
-
result = {}.tap { |hash| class_names.each { |class_name| hash[class_name] = [] }}
|
63
|
-
query = Pose::Assignment.joins(:word) \
|
64
|
-
.select('pose_assignments.posable_id, pose_assignments.posable_type') \
|
65
|
-
.where('pose_words.text LIKE ?', "#{word}%") \
|
66
|
-
.where('posable_type IN (?)', class_names)
|
67
|
-
Pose::Assignment.connection.select_all(query.to_sql).each do |pose_assignment|
|
68
|
-
result[pose_assignment['posable_type']] << pose_assignment['posable_id'].to_i
|
69
|
-
end
|
70
|
-
result
|
49
|
+
# Makes the given input an array.
|
50
|
+
def make_array input
|
51
|
+
[input].flatten
|
71
52
|
end
|
72
53
|
|
73
54
|
|
@@ -77,11 +58,6 @@ module Pose
|
|
77
58
|
end
|
78
59
|
|
79
60
|
|
80
|
-
# Returns the search terms that are contained in the given query.
|
81
|
-
def query_terms query
|
82
|
-
query.split(' ').map{|query_word| Helpers.root_word query_word}.flatten.uniq
|
83
|
-
end
|
84
|
-
|
85
61
|
# Simplifies the given word to a generic search form.
|
86
62
|
#
|
87
63
|
# @param [String] raw_word The word to make searchable.
|
@@ -29,7 +29,7 @@ module Pose
|
|
29
29
|
|
30
30
|
# Step 1: get an array of all words for the current object.
|
31
31
|
search_text = instance_eval &(self.class.pose_content)
|
32
|
-
new_words =
|
32
|
+
new_words = Query.new([], search_text.to_s).query_words
|
33
33
|
|
34
34
|
# Step 2: Add new words to the search index.
|
35
35
|
Helpers.get_words_to_add(self.pose_words, new_words).each do |word_to_add|
|
data/lib/pose/query.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
module Pose
|
2
|
+
# Represents a search query.
|
3
|
+
#
|
4
|
+
# Provides convenient access to all elements of the search query:
|
5
|
+
# * fulltext
|
6
|
+
# * classes to search in
|
7
|
+
# * additional JOINs
|
8
|
+
# * additional WHEREs
|
9
|
+
class Query
|
10
|
+
|
11
|
+
attr_reader :classes, :text, :options
|
12
|
+
|
13
|
+
|
14
|
+
def initialize classes, text, options = {}
|
15
|
+
@classes = [classes].flatten
|
16
|
+
@text = text
|
17
|
+
@options = options
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
# The names of the classes to search in.
|
22
|
+
# @return [Array<String>]
|
23
|
+
def class_names
|
24
|
+
classes.map &:name
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
# Returns whether this query contains custom JOIN expressions.
|
29
|
+
def has_joins?
|
30
|
+
!@options[:joins].blank?
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# Returns whether the query defines a limit on the number of results.
|
35
|
+
def has_limit?
|
36
|
+
!@options[:limit].blank?
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# Returns whether this query contains WHERE clauses.
|
41
|
+
def has_where?
|
42
|
+
!@options[:where].blank?
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# Returns whether only result ids are requested,
|
47
|
+
# opposed to full objects.
|
48
|
+
def ids_requested?
|
49
|
+
@options[:result_type] == :ids
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
# Returns the custom JOIN expressions of this query.
|
54
|
+
def joins
|
55
|
+
@joins ||= [@options[:joins]].flatten.compact
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
# Returns the limitation on the number of results.
|
60
|
+
def limit
|
61
|
+
@options[:limit]
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
# Returns the search terms that are contained in the given query.
|
66
|
+
def query_words
|
67
|
+
@query_words ||= Query.query_words @text
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
def self.query_words query_string
|
72
|
+
query_string.split(' ').map{|query_word| Helpers.root_word query_word}.flatten.uniq
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# Returns the WHERE clause of this query.
|
77
|
+
def where
|
78
|
+
return [] unless has_where?
|
79
|
+
if @options[:where].size == 2 and @options[:where][0].class == String
|
80
|
+
return [ @options[:where] ]
|
81
|
+
end
|
82
|
+
@options[:where]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/pose/search.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
module Pose
|
2
|
+
|
3
|
+
# A search operation.
|
4
|
+
#
|
5
|
+
# Is given a query and search options, and returns the search results.
|
6
|
+
class Search
|
7
|
+
|
8
|
+
# @param [Array<Class>] classes The classes to search over.
|
9
|
+
# @param [String] query_string The full-text part of the search query.
|
10
|
+
# @param options Additional search options:
|
11
|
+
# * where: additional where clauses
|
12
|
+
# * join: additional join clauses
|
13
|
+
def initialize classes, query_string, options = {}
|
14
|
+
@query = Query.new classes, query_string, options
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
# Adds the given join expression to the given arel query.
|
19
|
+
def add_join arel, join_expression
|
20
|
+
case join_expression.class.name
|
21
|
+
when 'Class'
|
22
|
+
table_name = join_expression.name.tableize
|
23
|
+
return arel.joins "INNER JOIN #{table_name} ON pose_assignments.posable_id=#{table_name}.id AND pose_assignments.posable_type='#{join_expression.name}'"
|
24
|
+
when 'String', 'Symbol'
|
25
|
+
return arel.joins join_expression
|
26
|
+
else
|
27
|
+
raise "Unknown join expression: #{join_expression}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
# Creates a JOIN to the given expression.
|
33
|
+
def add_joins arel
|
34
|
+
@query.joins.inject(arel) do |memo, join_data|
|
35
|
+
add_join memo, join_data
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# Adds the WHERE clauses from the given query to the given arel construct.
|
41
|
+
def add_wheres arel
|
42
|
+
@query.where.inject(arel) { |memo, where| memo.where where }
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# Returns an empty result structure.
|
47
|
+
def empty_result
|
48
|
+
{}.tap do |result|
|
49
|
+
@query.class_names.each do |class_name|
|
50
|
+
result[class_name] = []
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
# Truncates the result set based on the :limit parameter in the query.
|
57
|
+
def limit_ids result
|
58
|
+
return unless @query.has_limit?
|
59
|
+
result.each do |clazz, ids|
|
60
|
+
result[clazz] = ids.slice 0, @query.limit
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
# Converts the ids to classes, if the user wants classes.
|
66
|
+
def load_classes result
|
67
|
+
return if @query.ids_requested?
|
68
|
+
result.each do |clazz, ids|
|
69
|
+
if ids.size > 0
|
70
|
+
result[clazz] = clazz.where(id: ids)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# Merges the given posable object ids for a single query word into the given search result.
|
77
|
+
# Helper method for :search_words.
|
78
|
+
def merge_search_result_word_matches result, class_name, ids
|
79
|
+
if result.has_key? class_name
|
80
|
+
result[class_name] = result[class_name] & ids
|
81
|
+
else
|
82
|
+
result[class_name] = ids
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
# Returns the search results cached.
|
88
|
+
# Use this method to access the results of the search.
|
89
|
+
def results
|
90
|
+
@results ||= search
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
# Performs a complete search.
|
95
|
+
# Clients should use :results to perform a search,
|
96
|
+
# since it caches the results.
|
97
|
+
def search
|
98
|
+
{}.tap do |result|
|
99
|
+
search_words.each do |class_name, ids|
|
100
|
+
result[class_name.constantize] = ids
|
101
|
+
end
|
102
|
+
limit_ids result
|
103
|
+
load_classes result
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
# Finds all matching ids for a single word of the search query.
|
109
|
+
def search_word word
|
110
|
+
empty_result.tap do |result|
|
111
|
+
data = Pose::Assignment.joins(:word) \
|
112
|
+
.select('pose_assignments.posable_id, pose_assignments.posable_type') \
|
113
|
+
.where('pose_words.text LIKE ?', "#{word}%") \
|
114
|
+
.where('pose_assignments.posable_type IN (?)', @query.class_names)
|
115
|
+
data = add_joins data
|
116
|
+
data = add_wheres data
|
117
|
+
Pose::Assignment.connection.select_all(data.to_sql).each do |pose_assignment|
|
118
|
+
result[pose_assignment['posable_type']] << pose_assignment['posable_id'].to_i
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
# Returns all matching ids for all words of the search query.
|
125
|
+
def search_words
|
126
|
+
{}.tap do |result|
|
127
|
+
@query.query_words.each do |query_word|
|
128
|
+
search_word(query_word).each do |class_name, ids|
|
129
|
+
merge_search_result_word_matches result, class_name, ids
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|