searchlight 1.3.1 → 2.0.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 +4 -4
- data/.travis.yml +1 -6
- data/CHANGELOG.md +30 -0
- data/Gemfile +0 -2
- data/README.md +15 -29
- data/lib/searchlight.rb +0 -2
- data/lib/searchlight/adapters/action_view.rb +1 -1
- data/lib/searchlight/version.rb +1 -1
- data/searchlight.gemspec +10 -3
- data/spec/spec_helper.rb +0 -2
- metadata +68 -38
- data/lib/searchlight/adapters/active_record.rb +0 -96
- data/lib/searchlight/adapters/mongoid.rb +0 -60
- data/spec/searchlight/adapters/active_record_spec.rb +0 -107
- data/spec/searchlight/adapters/mongoid_spec.rb +0 -86
- data/spec/support/mock_models/active_record.rb +0 -23
- data/spec/support/mock_models/mongoid.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d87d47fdacfae5b1d8d87d2c34b6443610fb4f88
|
4
|
+
data.tar.gz: 639cb63efe19379336e0fbcd65b8d66f0d265f2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9785b92c697fb59b0ae3aebd88af3f1913c04df0ff99aed3b73923b13d2d313d9923f98b217a7646be742c163ab892d61ce3eb8cff77960da21a132979a1717d
|
7
|
+
data.tar.gz: 5438b35af95bcf804ff0898f8989f0d804f7bb1b46f9f74642e59d3a98c5a27ac70c681a988b8ffca545aa9253a9339b3f3efca9fe29e7beaca868b70b0d73df
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,36 @@
|
|
2
2
|
|
3
3
|
Searchlight does its best to use [semantic versioning](http://semver.org).
|
4
4
|
|
5
|
+
## v2.0.0
|
6
|
+
|
7
|
+
Now with fewer features! :D
|
8
|
+
|
9
|
+
### No more ORM adapters
|
10
|
+
|
11
|
+
ORM "adapters", which were never actually necessary, have been removed. They required lots of hackery, added test dependencies, and sometimes introduced [weird bugs](https://github.com/nathanl/searchlight/pull/15). All that just so that if you said your class `searches :first_name, :last_name`, we could save you from typing simple search methods like:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
def search_first_name
|
15
|
+
search.where(first_name: first_name)
|
16
|
+
end
|
17
|
+
```
|
18
|
+
|
19
|
+
You can easily save yourself this effort with something like:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
%w[name address pant_size].each do |attr|
|
23
|
+
define_method("search_#{attr}") do
|
24
|
+
search.where(:"#{attr}" => attr)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
...and you'll get much saner backtraces if anything goes wrong.
|
30
|
+
|
31
|
+
**ActiveRecord users**: note that with this change, you'll need to update your `search_on` calls to return an `ActiveRecord::Relation` so that, if no options are passed, you don't return the model class itself. Eg, instead of `search_on User`, do `search_on User.all` for Rails > 4 or `search_on User.scoped` for Rails < 4.
|
32
|
+
|
33
|
+
With this change, Searchlight no longer has any ties to any ORM, but can still work with any of them that use method chaining. Hooray!
|
34
|
+
|
5
35
|
## v1.3.1
|
6
36
|
|
7
37
|
Add license to gemspec, thanks to notice from Benjamin Fleischer - see [his blog post](http://www.benjaminfleischer.com/2013/07/12/make-the-world-a-better-place-put-a-license-in-your-gemspec/)
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# Searchlight
|
2
2
|
|
3
|
-
Searchlight
|
3
|
+
Searchlight is a low-magic way to build database searches using an ORM.
|
4
4
|
|
5
|
-
Searchlight can work with any ORM or object that can build a query using chained
|
5
|
+
Searchlight can work with **any** ORM or object that can build a query using **chained method calls** (eg, ActiveRecord's `.where(...).where(...).limit(...)`, or similar chains with [Sequel](https://rubygems.org/gems/sequel), [Mongoid](https://rubygems.org/gems/mongoid), etc).
|
6
6
|
|
7
7
|
[](https://rubygems.org/gems/searchlight)
|
8
8
|
[](https://codeclimate.com/github/nathanl/searchlight)
|
@@ -21,10 +21,12 @@ The basic idea of Searchlight is to build a search by chaining method calls that
|
|
21
21
|
For example, if you have a Searchlight search class called `YetiSearch`, and you instantiate it like this:
|
22
22
|
|
23
23
|
```ruby
|
24
|
-
search = YetiSearch.new(
|
24
|
+
search = YetiSearch.new(
|
25
|
+
active: true, name: 'Jimmy', location_in: %w[NY LA] # or params[:search]
|
26
|
+
)
|
25
27
|
```
|
26
28
|
|
27
|
-
... calling `results` on the instance will build a search by chaining calls to `search_active`, `search_name`, and `
|
29
|
+
... calling `results` on the instance will build a search by chaining calls to `search_active`, `search_name`, and `search_location_in`.
|
28
30
|
|
29
31
|
The `results` method will then return the return value of the last search method. If you're using ActiveRecord, this would be an `ActiveRecord::Relation`, and you can then call `each` to loop through the results, `to_sql` to get the generated query, etc.
|
30
32
|
|
@@ -38,7 +40,9 @@ A search class has three main parts: a target, options, and methods. For example
|
|
38
40
|
class PersonSearch < Searchlight::Search
|
39
41
|
|
40
42
|
# The search target; in this case, an ActiveRecord model.
|
41
|
-
|
43
|
+
# This is the starting point for any chaining we do, and it's what
|
44
|
+
# will be returned if no search options are passed.
|
45
|
+
search_on Person.all
|
42
46
|
|
43
47
|
# The options the search understands. Supply any combination of them to an instance.
|
44
48
|
searches :first_name, :last_name
|
@@ -120,7 +124,7 @@ search = MySearchClass.new(awesomeness: 'Xtreme')
|
|
120
124
|
|
121
125
|
... your search methods can use:
|
122
126
|
|
123
|
-
- `awesomeness` to
|
127
|
+
- `awesomeness` to retrieve the given value, `'Xtreme'`
|
124
128
|
- `awesomeness?` to get a boolean version: `true`
|
125
129
|
|
126
130
|
The boolean conversion is form-friendly, so that `0`, `'0'`, and `'false'` are considered `false`.
|
@@ -181,7 +185,7 @@ You can define defaults for boolean attributes if you treat them as "yes/no/eith
|
|
181
185
|
```ruby
|
182
186
|
class AnimalSearch < Searchlight::Search
|
183
187
|
|
184
|
-
search_on Animal
|
188
|
+
search_on Animal.all
|
185
189
|
|
186
190
|
searches :is_fictional
|
187
191
|
|
@@ -214,7 +218,7 @@ You can subclass an existing search class and support all the same options with
|
|
214
218
|
|
215
219
|
```ruby
|
216
220
|
class VillageSearch < CitySearch
|
217
|
-
search_on Village
|
221
|
+
search_on Village.all
|
218
222
|
end
|
219
223
|
```
|
220
224
|
|
@@ -286,27 +290,9 @@ class OrdersController < ApplicationController
|
|
286
290
|
end
|
287
291
|
end
|
288
292
|
```
|
289
|
-
##
|
293
|
+
## ActionView Adapter
|
290
294
|
|
291
|
-
|
292
|
-
|
293
|
-
### ActiveRecord and Mongoid
|
294
|
-
|
295
|
-
When you call `search_on` in your Searchlight class, Searchlight checks whether the search target comes from ActiveRecord or Mongoid, and, if so, mixes a module into your class.
|
296
|
-
|
297
|
-
For each of your search options, the module will have the simplest possible search method defined. For example, if your class `searches :name`, the ActiveRecord module will have this method:
|
298
|
-
|
299
|
-
```ruby
|
300
|
-
def search_name
|
301
|
-
search.where(name: name)
|
302
|
-
end
|
303
|
-
```
|
304
|
-
|
305
|
-
Since that method is in a parent module, you can easily override it by defining your own method. You can also call `super` in the method you define.
|
306
|
-
|
307
|
-
### ActionView
|
308
|
-
|
309
|
-
Similarly, Searchlight adds ActionView-friendly methods to your classes if it sees that `ActionView` is a defined constant. See the code for details, but the upshot is that you can use a search with `form_for`.
|
295
|
+
Searchlight's ActionView adapter adds ActionView-friendly methods to your classes if it sees that `ActionView` is a defined constant. See the code for details, but the upshot is that you can use a search with `form_for`.
|
310
296
|
|
311
297
|
## Compatibility
|
312
298
|
|
@@ -337,4 +323,4 @@ Or install it yourself as:
|
|
337
323
|
## Shout Outs
|
338
324
|
|
339
325
|
- The excellent [Mr. Adam Hunter](https://github.com/adamhunter), co-creator of Searchlight.
|
340
|
-
- [TMA](http://tma1.com) for supporting the development of Searchlight.
|
326
|
+
- [TMA](http://tma1.com) for supporting the initial development of Searchlight.
|
data/lib/searchlight.rb
CHANGED
@@ -7,6 +7,4 @@ end
|
|
7
7
|
|
8
8
|
require 'searchlight/dsl'
|
9
9
|
require 'searchlight/search'
|
10
|
-
require 'searchlight/adapters/active_record' if defined?(::ActiveRecord)
|
11
|
-
require 'searchlight/adapters/mongoid' if defined?(::Mongoid)
|
12
10
|
require 'searchlight/adapters/action_view' if defined?(::ActionView)
|
data/lib/searchlight/version.rb
CHANGED
data/searchlight.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.version = Searchlight::VERSION
|
10
10
|
spec.authors = ["Nathan Long", "Adam Hunter"]
|
11
11
|
spec.email = ["nathanmlong@gmail.com", "adamhunter@me.com"]
|
12
|
-
spec.
|
13
|
-
spec.
|
12
|
+
spec.summary = %q{Searchlight is a low-magic way to build database searches using an ORM.}
|
13
|
+
spec.description = %q{Searchlight is a low-magic way to build database searches using an ORM. It's compatible with ActiveRecord, Sequel, Mongoid, and any other ORM that can build queries by chaining method calls.}
|
14
14
|
spec.homepage = "https://github.com/nathanl/searchlight"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
@@ -21,9 +21,16 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.add_dependency "named", "~> 1.0"
|
23
23
|
|
24
|
-
spec.add_development_dependency "rspec", "~> 2.
|
24
|
+
spec.add_development_dependency "rspec", "~> 2.14"
|
25
25
|
spec.add_development_dependency "bundler", "~> 1.3"
|
26
26
|
spec.add_development_dependency "rake"
|
27
27
|
spec.add_development_dependency "capybara", "~> 2.0"
|
28
28
|
spec.add_development_dependency "simplecov", "~> 0.7"
|
29
|
+
|
30
|
+
# To test integration with actionview and activerecord
|
31
|
+
spec.add_development_dependency "actionview", "~> 4.1"
|
32
|
+
spec.add_development_dependency "activemodel", "~> 4.1"
|
33
|
+
|
34
|
+
# For coverage testing on Travis
|
35
|
+
spec.add_development_dependency "coveralls", "~> 0.7"
|
29
36
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: searchlight
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathan Long
|
@@ -9,96 +9,137 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-04-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: named
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - ~>
|
18
|
+
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: '1.0'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- - ~>
|
25
|
+
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '1.0'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: rspec
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - ~>
|
32
|
+
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: '2.
|
34
|
+
version: '2.14'
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- - ~>
|
39
|
+
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: '2.
|
41
|
+
version: '2.14'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: bundler
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- - ~>
|
46
|
+
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
48
|
version: '1.3'
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
|
-
- - ~>
|
53
|
+
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '1.3'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: rake
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
|
-
- -
|
60
|
+
- - ">="
|
61
61
|
- !ruby/object:Gem::Version
|
62
62
|
version: '0'
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
|
-
- -
|
67
|
+
- - ">="
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '0'
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: capybara
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
|
-
- - ~>
|
74
|
+
- - "~>"
|
75
75
|
- !ruby/object:Gem::Version
|
76
76
|
version: '2.0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- - ~>
|
81
|
+
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '2.0'
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
85
|
name: simplecov
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
|
-
- - ~>
|
88
|
+
- - "~>"
|
89
89
|
- !ruby/object:Gem::Version
|
90
90
|
version: '0.7'
|
91
91
|
type: :development
|
92
92
|
prerelease: false
|
93
93
|
version_requirements: !ruby/object:Gem::Requirement
|
94
94
|
requirements:
|
95
|
-
- - ~>
|
95
|
+
- - "~>"
|
96
96
|
- !ruby/object:Gem::Version
|
97
97
|
version: '0.7'
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: actionview
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - "~>"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '4.1'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - "~>"
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '4.1'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: activemodel
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - "~>"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '4.1'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - "~>"
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '4.1'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: coveralls
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - "~>"
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0.7'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - "~>"
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0.7'
|
140
|
+
description: Searchlight is a low-magic way to build database searches using an ORM.
|
141
|
+
It's compatible with ActiveRecord, Sequel, Mongoid, and any other ORM that can build
|
142
|
+
queries by chaining method calls.
|
102
143
|
email:
|
103
144
|
- nathanmlong@gmail.com
|
104
145
|
- adamhunter@me.com
|
@@ -106,9 +147,9 @@ executables: []
|
|
106
147
|
extensions: []
|
107
148
|
extra_rdoc_files: []
|
108
149
|
files:
|
109
|
-
- .gitignore
|
110
|
-
- .rspec
|
111
|
-
- .travis.yml
|
150
|
+
- ".gitignore"
|
151
|
+
- ".rspec"
|
152
|
+
- ".travis.yml"
|
112
153
|
- CHANGELOG.md
|
113
154
|
- Gemfile
|
114
155
|
- LICENSE.txt
|
@@ -119,22 +160,16 @@ files:
|
|
119
160
|
- gemfiles/Gemfile.rails-4.0.x
|
120
161
|
- lib/searchlight.rb
|
121
162
|
- lib/searchlight/adapters/action_view.rb
|
122
|
-
- lib/searchlight/adapters/active_record.rb
|
123
|
-
- lib/searchlight/adapters/mongoid.rb
|
124
163
|
- lib/searchlight/dsl.rb
|
125
164
|
- lib/searchlight/search.rb
|
126
165
|
- lib/searchlight/version.rb
|
127
166
|
- searchlight.gemspec
|
128
167
|
- spec/searchlight/adapters/action_view_spec.rb
|
129
|
-
- spec/searchlight/adapters/active_record_spec.rb
|
130
|
-
- spec/searchlight/adapters/mongoid_spec.rb
|
131
168
|
- spec/searchlight/search_spec.rb
|
132
169
|
- spec/searchlight_spec.rb
|
133
170
|
- spec/spec_helper.rb
|
134
171
|
- spec/support/account_search.rb
|
135
172
|
- spec/support/mock_model.rb
|
136
|
-
- spec/support/mock_models/active_record.rb
|
137
|
-
- spec/support/mock_models/mongoid.rb
|
138
173
|
- spec/support/spiffy_account_search.rb
|
139
174
|
homepage: https://github.com/nathanl/searchlight
|
140
175
|
licenses:
|
@@ -146,30 +181,25 @@ require_paths:
|
|
146
181
|
- lib
|
147
182
|
required_ruby_version: !ruby/object:Gem::Requirement
|
148
183
|
requirements:
|
149
|
-
- -
|
184
|
+
- - ">="
|
150
185
|
- !ruby/object:Gem::Version
|
151
186
|
version: '0'
|
152
187
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
188
|
requirements:
|
154
|
-
- -
|
189
|
+
- - ">="
|
155
190
|
- !ruby/object:Gem::Version
|
156
191
|
version: '0'
|
157
192
|
requirements: []
|
158
193
|
rubyforge_project:
|
159
|
-
rubygems_version: 2.0
|
194
|
+
rubygems_version: 2.2.0
|
160
195
|
signing_key:
|
161
196
|
specification_version: 4
|
162
|
-
summary: Searchlight
|
163
|
-
write.
|
197
|
+
summary: Searchlight is a low-magic way to build database searches using an ORM.
|
164
198
|
test_files:
|
165
199
|
- spec/searchlight/adapters/action_view_spec.rb
|
166
|
-
- spec/searchlight/adapters/active_record_spec.rb
|
167
|
-
- spec/searchlight/adapters/mongoid_spec.rb
|
168
200
|
- spec/searchlight/search_spec.rb
|
169
201
|
- spec/searchlight_spec.rb
|
170
202
|
- spec/spec_helper.rb
|
171
203
|
- spec/support/account_search.rb
|
172
204
|
- spec/support/mock_model.rb
|
173
|
-
- spec/support/mock_models/active_record.rb
|
174
|
-
- spec/support/mock_models/mongoid.rb
|
175
205
|
- spec/support/spiffy_account_search.rb
|
@@ -1,96 +0,0 @@
|
|
1
|
-
module Searchlight
|
2
|
-
module Adapters
|
3
|
-
module ActiveRecord
|
4
|
-
|
5
|
-
def search_on(target)
|
6
|
-
super
|
7
|
-
extend Search if is_active_record?(target)
|
8
|
-
convert_to_relation if is_active_record_class?(target)
|
9
|
-
end
|
10
|
-
|
11
|
-
module Search
|
12
|
-
def searches(*attribute_names)
|
13
|
-
super
|
14
|
-
|
15
|
-
# Ensure this class only adds one search module to the ancestors chain
|
16
|
-
if @ar_searches_module.nil?
|
17
|
-
@ar_searches_module = Named::Module.new("SearchlightActiveRecordSearches(#{self})")
|
18
|
-
include @ar_searches_module
|
19
|
-
end
|
20
|
-
|
21
|
-
eval_string = attribute_names.map { |attribute_name|
|
22
|
-
model_class = model_class_for(search_target)
|
23
|
-
if model_has_db_attribute?(attribute_name.to_s)
|
24
|
-
|
25
|
-
<<-UNICORN_BILE
|
26
|
-
def search_#{attribute_name}
|
27
|
-
search.where('#{attribute_name}' => public_send("#{attribute_name}"))
|
28
|
-
end
|
29
|
-
UNICORN_BILE
|
30
|
-
else
|
31
|
-
<<-MERMAID_TEARS
|
32
|
-
def search_#{attribute_name}
|
33
|
-
raise Searchlight::Adapters::ActiveRecord::UndefinedColumn,
|
34
|
-
"Class `#{model_class}` has no column `#{attribute_name}`; please define `search_#{attribute_name}` on `\#{self.class}` to clarify what you intend to search for"
|
35
|
-
end
|
36
|
-
MERMAID_TEARS
|
37
|
-
end
|
38
|
-
|
39
|
-
}.join
|
40
|
-
|
41
|
-
@ar_searches_module.module_eval(eval_string, __FILE__, __LINE__)
|
42
|
-
end
|
43
|
-
|
44
|
-
# The idea here is to provide a means to allow users to bypass the check if it causes problems (e.g. during
|
45
|
-
# `rake assets:precompile` if the DB has yet to be created). To bypass this, a user could monkey patch as
|
46
|
-
# follows:
|
47
|
-
#
|
48
|
-
# module Searchlight::Adapters::ActiveRecord::Search
|
49
|
-
# def model_has_db_attribute?(attribute_name)
|
50
|
-
# model_class_for(search_target).columns_hash.keys.include?(attribute_name)
|
51
|
-
# rescue StandardError
|
52
|
-
# true
|
53
|
-
# end
|
54
|
-
# end
|
55
|
-
#
|
56
|
-
# Alternatively, they could monkey-patch Searchlight::Adapters::ActiveRecord::Search::model_has_db_attribute
|
57
|
-
# to simply always return true, though they would then not get the benefit of the improved error messaging.
|
58
|
-
#
|
59
|
-
def model_has_db_attribute?(attribute_name)
|
60
|
-
model_class_for(search_target).columns_hash.keys.include?(attribute_name)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
protected
|
65
|
-
|
66
|
-
def is_active_record?(target)
|
67
|
-
is_active_record_class?(target) || is_active_record_relation?(target)
|
68
|
-
end
|
69
|
-
|
70
|
-
def is_active_record_class?(target)
|
71
|
-
target.is_a?(Class) && target.ancestors.include?(::ActiveRecord::Base)
|
72
|
-
end
|
73
|
-
|
74
|
-
def is_active_record_relation?(target)
|
75
|
-
target.is_a?(::ActiveRecord::Relation)
|
76
|
-
end
|
77
|
-
|
78
|
-
# Ensure that searches without options still return enumerable results
|
79
|
-
def convert_to_relation
|
80
|
-
self.search_target = (active_record_version >= 4) ? search_target.all : search_target.scoped
|
81
|
-
end
|
82
|
-
|
83
|
-
def model_class_for(target)
|
84
|
-
is_active_record_class?(target) ? target : target.engine
|
85
|
-
end
|
86
|
-
|
87
|
-
def active_record_version
|
88
|
-
::ActiveRecord::VERSION::MAJOR.to_i
|
89
|
-
end
|
90
|
-
|
91
|
-
UndefinedColumn = Class.new(StandardError)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
Searchlight::Search.extend(Searchlight::Adapters::ActiveRecord)
|
@@ -1,60 +0,0 @@
|
|
1
|
-
module Searchlight
|
2
|
-
module Adapters
|
3
|
-
module Mongoid
|
4
|
-
|
5
|
-
def search_on(target)
|
6
|
-
super
|
7
|
-
extend Search if mongoid?(target)
|
8
|
-
end
|
9
|
-
|
10
|
-
module Search
|
11
|
-
|
12
|
-
def searches(*attributes_names)
|
13
|
-
super
|
14
|
-
|
15
|
-
attributes_names.map do |attribute_name|
|
16
|
-
method_name = "search_#{attribute_name}"
|
17
|
-
if field?(attribute_name)
|
18
|
-
define_method method_name do
|
19
|
-
search.where(attribute_name.to_s => public_send(attribute_name))
|
20
|
-
end
|
21
|
-
else
|
22
|
-
define_method method_name do
|
23
|
-
raise Searchlight::Adapters::Mongoid::UndefinedColumn,
|
24
|
-
"Class `#{self.class.model_class}` has no field `#{attribute_name}`; please define `search_#{attribute_name}` on `#{self.class}` to clarify what you intend to search for"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def field?(attributes_name)
|
31
|
-
model_class.fields.has_key? attributes_name.to_s
|
32
|
-
end
|
33
|
-
|
34
|
-
def model_class
|
35
|
-
search_target.is_a?(::Mongoid::Criteria) ? search_target.klass : search_target
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
protected
|
41
|
-
|
42
|
-
def mongoid?(target)
|
43
|
-
mongoid_document?(target) || mongoid_criteria?(target)
|
44
|
-
end
|
45
|
-
|
46
|
-
def mongoid_document?(target)
|
47
|
-
defined?(::Mongoid::Document) && target.include?(::Mongoid::Document)
|
48
|
-
end
|
49
|
-
|
50
|
-
def mongoid_criteria?(target)
|
51
|
-
defined?(::Mongoid::Criteria) && target.is_a?(::Mongoid::Criteria)
|
52
|
-
end
|
53
|
-
|
54
|
-
UndefinedColumn = Class.new(StandardError)
|
55
|
-
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
Searchlight::Search.extend(Searchlight::Adapters::Mongoid)
|
@@ -1,107 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'Searchlight::Adapters::ActiveRecord', adapter: true do
|
4
|
-
|
5
|
-
before :all do
|
6
|
-
require 'searchlight/adapters/active_record'
|
7
|
-
require 'active_record'
|
8
|
-
end
|
9
|
-
|
10
|
-
let(:search_class) {
|
11
|
-
Named::Class.new('SearchClass', Searchlight::Search).tap { |klass|
|
12
|
-
klass.instance_eval(&ar_version_faker)
|
13
|
-
klass.search_on target
|
14
|
-
}
|
15
|
-
}
|
16
|
-
let(:ar_version_faker) { lambda {|klass| nil } } # no-op
|
17
|
-
let(:search_instance) { search_class.new(elephants: 'yes, please') }
|
18
|
-
|
19
|
-
shared_examples "search classes with an ActiveRecord target" do
|
20
|
-
|
21
|
-
context "when the base model has a column matching the search term" do
|
22
|
-
|
23
|
-
before :each do
|
24
|
-
MockActiveRecord.stub(:columns_hash).and_return({'elephants' => 'column info...'})
|
25
|
-
search_class.searches :elephants
|
26
|
-
end
|
27
|
-
|
28
|
-
it "adds search methods to the search class" do
|
29
|
-
expect(search_class.new).to respond_to(:search_elephants)
|
30
|
-
end
|
31
|
-
|
32
|
-
it "defines search methods that call `where` on the search target" do
|
33
|
-
search_instance.results
|
34
|
-
expect(search_instance.search.called_methods).to include(:where)
|
35
|
-
end
|
36
|
-
|
37
|
-
it "sets arguments properly in the defined method" do
|
38
|
-
search_instance.search.should_receive(:where).with('elephants' => 'yes, please')
|
39
|
-
search_instance.search_elephants
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
context "when the base model has no column matching the search term" do
|
45
|
-
|
46
|
-
before :each do
|
47
|
-
MockActiveRecord.stub(:columns_hash).and_return({})
|
48
|
-
search_class.searches :elephants
|
49
|
-
end
|
50
|
-
|
51
|
-
it "adds search methods to the search class" do
|
52
|
-
expect(search_class.new).to respond_to(:search_elephants)
|
53
|
-
end
|
54
|
-
|
55
|
-
it "defines search methods to raise an exception" do
|
56
|
-
expect { search_instance.results }.to raise_error(
|
57
|
-
Searchlight::Adapters::ActiveRecord::UndefinedColumn
|
58
|
-
)
|
59
|
-
end
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
context "when the search target is an ActiveRecord class" do
|
66
|
-
|
67
|
-
let(:target) { MockActiveRecord }
|
68
|
-
|
69
|
-
describe "converting to an ActiveRecord::Relation" do
|
70
|
-
|
71
|
-
context "for ActiveRecord <= 3" do
|
72
|
-
|
73
|
-
let(:ar_version_faker) { lambda { |klass| klass.stub(:active_record_version).and_return(3) } }
|
74
|
-
|
75
|
-
it "calls 'scoped'" do
|
76
|
-
target.should_receive(:scoped)
|
77
|
-
search_class
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
81
|
-
|
82
|
-
context "for ActiveRecord >= 4" do
|
83
|
-
|
84
|
-
let(:ar_version_faker) { lambda { |klass| klass.stub(:active_record_version).and_return(4) } }
|
85
|
-
|
86
|
-
it "calls 'all'" do
|
87
|
-
target.should_receive(:all)
|
88
|
-
search_class
|
89
|
-
end
|
90
|
-
|
91
|
-
end
|
92
|
-
|
93
|
-
end
|
94
|
-
|
95
|
-
it_behaves_like "search classes with an ActiveRecord target"
|
96
|
-
|
97
|
-
end
|
98
|
-
|
99
|
-
context "when the search target is an ActiveRecord relation" do
|
100
|
-
|
101
|
-
let(:target) { MockActiveRecord.joins(:dudes_named_milford).tap { |r| r.called_methods.clear } }
|
102
|
-
|
103
|
-
it_behaves_like "search classes with an ActiveRecord target"
|
104
|
-
|
105
|
-
end
|
106
|
-
|
107
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'Searchlight::Adapters::Mongoid', adapter: true do
|
4
|
-
|
5
|
-
before :all do
|
6
|
-
require 'mongoid'
|
7
|
-
require 'searchlight/adapters/mongoid'
|
8
|
-
end
|
9
|
-
|
10
|
-
after :all do
|
11
|
-
Object.send(:remove_const, :Mongoid)
|
12
|
-
end
|
13
|
-
|
14
|
-
let(:search_class) {
|
15
|
-
Named::Class.new('SearchClass', Searchlight::Search).tap { |klass| klass.search_on target }
|
16
|
-
}
|
17
|
-
|
18
|
-
let(:search_instance) { search_class.new(elephants: 'yes, please') }
|
19
|
-
|
20
|
-
shared_examples "search classes with an Mongoid target" do
|
21
|
-
|
22
|
-
context "when the base model has a field matching the search term" do
|
23
|
-
|
24
|
-
before do
|
25
|
-
MockMongoid.stub(:fields).and_return('elephants' => 'column info...')
|
26
|
-
search_class.searches :elephants
|
27
|
-
end
|
28
|
-
|
29
|
-
it "adds search methods to the search class" do
|
30
|
-
expect(search_class.new).to respond_to(:search_elephants)
|
31
|
-
end
|
32
|
-
|
33
|
-
it "defines search methods that call `where` on the search target" do
|
34
|
-
search_instance.results
|
35
|
-
expect(search_instance.search.called_methods).to include(:where)
|
36
|
-
end
|
37
|
-
|
38
|
-
it "sets arguments properly in the defined method" do
|
39
|
-
search_instance.search.should_receive(:where).with('elephants' => 'yes, please')
|
40
|
-
search_instance.search_elephants
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
|
-
context "when the base model has no field matching the search term" do
|
46
|
-
|
47
|
-
before do
|
48
|
-
MockMongoid.stub(fields: {})
|
49
|
-
search_class.searches :elephants
|
50
|
-
end
|
51
|
-
|
52
|
-
it "adds search methods to the search class" do
|
53
|
-
expect(search_class.new).to respond_to(:search_elephants)
|
54
|
-
end
|
55
|
-
|
56
|
-
it "defines search methods to raise an exception" do
|
57
|
-
expect { search_instance.results }.to raise_error(
|
58
|
-
Searchlight::Adapters::Mongoid::UndefinedColumn
|
59
|
-
)
|
60
|
-
end
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
context "when the search target is a class with Mongoid::Document module" do
|
67
|
-
|
68
|
-
let(:target) { MockMongoid }
|
69
|
-
|
70
|
-
it_behaves_like "search classes with an Mongoid target"
|
71
|
-
|
72
|
-
end
|
73
|
-
|
74
|
-
context "when the search target is Mongoid::Criteria class" do
|
75
|
-
|
76
|
-
let(:target) { MockMongoidCriteria.new([]) }
|
77
|
-
|
78
|
-
before do
|
79
|
-
target.stub(klass: MockMongoid)
|
80
|
-
end
|
81
|
-
|
82
|
-
it_behaves_like "search classes with an Mongoid target"
|
83
|
-
|
84
|
-
end
|
85
|
-
|
86
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
class MockActiveRecord < MockModel
|
2
|
-
|
3
|
-
def self.ancestors
|
4
|
-
super + [::ActiveRecord::Base]
|
5
|
-
end
|
6
|
-
|
7
|
-
def self.is_a?(thing)
|
8
|
-
thing == ::ActiveRecord::Base ? true : super
|
9
|
-
end
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
class MockActiveRecordRelation < MockRelation
|
14
|
-
|
15
|
-
def is_a?(thing)
|
16
|
-
thing == ::ActiveRecord::Relation ? true : super
|
17
|
-
end
|
18
|
-
|
19
|
-
def engine
|
20
|
-
MockActiveRecord
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
class MockMongoid < MockModel
|
2
|
-
|
3
|
-
def self.include?(thing)
|
4
|
-
thing == ::Mongoid::Document ? true : super
|
5
|
-
end
|
6
|
-
|
7
|
-
end
|
8
|
-
|
9
|
-
class MockMongoidCriteria < MockRelation
|
10
|
-
|
11
|
-
def is_a?(thing)
|
12
|
-
thing == ::Mongoid::Criteria ? true : super
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.include?(thing)
|
16
|
-
thing == ::Mongoid::Document ? false : super
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|