pose 2.0.1 → 2.1.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/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> [](https://codeclimate.com/github/kevgo/pose) [](https://coveralls.io/r/kevgo/pose) [](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
|