scoped_from 1.0.1 → 1.0.2
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/VERSION +1 -1
- data/scoped_from.gemspec +3 -4
- metadata +5 -22
- data/.gitignore +0 -7
- data/.rspec +0 -2
- data/Gemfile +0 -3
- data/Rakefile +0 -10
- data/spec/mocks/comment.rb +0 -2
- data/spec/mocks/comment_query.rb +0 -2
- data/spec/mocks/post.rb +0 -2
- data/spec/mocks/user.rb +0 -8
- data/spec/mocks/user_query.rb +0 -2
- data/spec/mocks/vote.rb +0 -2
- data/spec/mocks/vote_query.rb +0 -2
- data/spec/scoped_from/active_record_spec.rb +0 -125
- data/spec/scoped_from/query_spec.rb +0 -490
- data/spec/scoped_from_spec.rb +0 -20
- data/spec/spec_helper.rb +0 -27
- data/spec/support/bootstrap/database.rb +0 -12
- data/spec/support/macros/user_macro.rb +0 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 91ae1b8a113e2c3b176c538a4d83870913cdb16c
|
|
4
|
+
data.tar.gz: e06f1e812ed6ed939eaa37b90dab44728225d2b7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e8c903abd9c23d0a66c4956119c810eef2523be47e7cec2772fe5afa3345e716516fd015d084da3d4cd27a1f5e5437054fe60005c0ca8ae3c66ceea96300f12d
|
|
7
|
+
data.tar.gz: 7eedfbdca7944970a41fffd50806c6788406bff4f37b9f1f533e3af4ef3ee03596340f79b57ce7e5c149e5507de2cd4432411d158f82d229cc11411af95e7722
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.2
|
data/scoped_from.gemspec
CHANGED
|
@@ -9,13 +9,12 @@ Gem::Specification.new do |s|
|
|
|
9
9
|
s.description = 'Provides a simple mapping between Active Record scopes and controller parameters for Ruby On Rails 4'
|
|
10
10
|
s.license = 'MIT'
|
|
11
11
|
|
|
12
|
-
s.
|
|
13
|
-
|
|
14
|
-
s.files = `git ls-files`.split("\n")
|
|
15
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
12
|
+
s.files = `git ls-files | grep -vE '^(spec/|test/|\\.|Gemfile|Rakefile)'`.split("\n")
|
|
16
13
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
17
14
|
s.require_paths = ['lib']
|
|
18
15
|
|
|
16
|
+
s.required_ruby_version = '>= 2.0.0'
|
|
17
|
+
|
|
19
18
|
s.add_dependency 'activerecord', '>= 5.0.0', '< 5.1.0'
|
|
20
19
|
s.add_dependency 'activesupport', '>= 5.0.0', '< 5.1.0'
|
|
21
20
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: scoped_from
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexis Toulotte
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2017-05-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -157,30 +157,13 @@ executables: []
|
|
|
157
157
|
extensions: []
|
|
158
158
|
extra_rdoc_files: []
|
|
159
159
|
files:
|
|
160
|
-
- ".gitignore"
|
|
161
|
-
- ".rspec"
|
|
162
|
-
- Gemfile
|
|
163
160
|
- MIT-LICENSE
|
|
164
161
|
- README.mdown
|
|
165
|
-
- Rakefile
|
|
166
162
|
- VERSION
|
|
167
163
|
- lib/scoped_from.rb
|
|
168
164
|
- lib/scoped_from/active_record.rb
|
|
169
165
|
- lib/scoped_from/query.rb
|
|
170
166
|
- scoped_from.gemspec
|
|
171
|
-
- spec/mocks/comment.rb
|
|
172
|
-
- spec/mocks/comment_query.rb
|
|
173
|
-
- spec/mocks/post.rb
|
|
174
|
-
- spec/mocks/user.rb
|
|
175
|
-
- spec/mocks/user_query.rb
|
|
176
|
-
- spec/mocks/vote.rb
|
|
177
|
-
- spec/mocks/vote_query.rb
|
|
178
|
-
- spec/scoped_from/active_record_spec.rb
|
|
179
|
-
- spec/scoped_from/query_spec.rb
|
|
180
|
-
- spec/scoped_from_spec.rb
|
|
181
|
-
- spec/spec_helper.rb
|
|
182
|
-
- spec/support/bootstrap/database.rb
|
|
183
|
-
- spec/support/macros/user_macro.rb
|
|
184
167
|
homepage: https://github.com/alexistoulotte/scoped_from
|
|
185
168
|
licenses:
|
|
186
169
|
- MIT
|
|
@@ -193,15 +176,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
193
176
|
requirements:
|
|
194
177
|
- - ">="
|
|
195
178
|
- !ruby/object:Gem::Version
|
|
196
|
-
version:
|
|
179
|
+
version: 2.0.0
|
|
197
180
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
198
181
|
requirements:
|
|
199
182
|
- - ">="
|
|
200
183
|
- !ruby/object:Gem::Version
|
|
201
184
|
version: '0'
|
|
202
185
|
requirements: []
|
|
203
|
-
rubyforge_project:
|
|
204
|
-
rubygems_version: 2.
|
|
186
|
+
rubyforge_project:
|
|
187
|
+
rubygems_version: 2.6.8
|
|
205
188
|
signing_key:
|
|
206
189
|
specification_version: 4
|
|
207
190
|
summary: Mapping between scopes and parameters for Rails
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/Gemfile
DELETED
data/Rakefile
DELETED
data/spec/mocks/comment.rb
DELETED
data/spec/mocks/comment_query.rb
DELETED
data/spec/mocks/post.rb
DELETED
data/spec/mocks/user.rb
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
class User < ActiveRecord::Base
|
|
2
|
-
|
|
3
|
-
scope :enabled, -> { where(enabled: true) }
|
|
4
|
-
scope :search, -> (pattern) { where('firstname LIKE ? OR lastname LIKE ?', "%#{pattern}%", "%#{pattern}%") }
|
|
5
|
-
scope :created_between, -> (after, before) { where('created_at >= ? AND created_at <= ?', after, before) }
|
|
6
|
-
scope :latest, -> { where('created_at >= ?', 1.week.ago) }
|
|
7
|
-
|
|
8
|
-
end
|
data/spec/mocks/user_query.rb
DELETED
data/spec/mocks/vote.rb
DELETED
data/spec/mocks/vote_query.rb
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe ScopedFrom::ActiveRecord do
|
|
4
|
-
|
|
5
|
-
describe '#scope_with_one_argument?' do
|
|
6
|
-
|
|
7
|
-
it 'is true if scope has one argument' do
|
|
8
|
-
expect(User.scope_with_one_argument?(:search)).to be(true)
|
|
9
|
-
expect(User.scope_with_one_argument?('search')).to be(true)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
it 'is false if scope has no argument' do
|
|
13
|
-
expect(User.scope_with_one_argument?(:latest)).to be(false)
|
|
14
|
-
expect(User.scope_with_one_argument?('latest')).to be(false)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
it 'is false if scope has more than one argument' do
|
|
18
|
-
expect(User.scope_with_one_argument?(:created_between)).to be(false)
|
|
19
|
-
expect(User.scope_with_one_argument?('created_between')).to be(false)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
it 'is false if scope is not a proc' do
|
|
23
|
-
expect(User.scope_with_one_argument?(:enabled)).to be(false)
|
|
24
|
-
expect(User.scope_with_one_argument?('enabled')).to be(false)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
it 'is false if scope does not exist' do
|
|
28
|
-
expect(User.scope_with_one_argument?(:foo)).to be(false)
|
|
29
|
-
expect(User.scope_with_one_argument?('foo')).to be(false)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
describe 'scope_without_argument?' do
|
|
35
|
-
|
|
36
|
-
it 'is true if scope has no argument' do
|
|
37
|
-
expect(User.scope_without_argument?(:latest)).to be(true)
|
|
38
|
-
expect(User.scope_without_argument?('latest')).to be(true)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
it 'is true if scope is not a proc' do
|
|
42
|
-
expect(User.scope_without_argument?(:enabled)).to be(true)
|
|
43
|
-
expect(User.scope_without_argument?('enabled')).to be(true)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
it 'is false if scope has one argument' do
|
|
47
|
-
expect(User.scope_without_argument?(:search)).to be(false)
|
|
48
|
-
expect(User.scope_without_argument?('search')).to be(false)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
it 'is false if scope has more than one argument' do
|
|
52
|
-
expect(User.scope_without_argument?(:created_between)).to be(false)
|
|
53
|
-
expect(User.scope_without_argument?('created_between')).to be(false)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
it 'is false if scope does not exist' do
|
|
57
|
-
expect(User.scope_without_argument?(:foo)).to be(false)
|
|
58
|
-
expect(User.scope_without_argument?('foo')).to be(false)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
describe '#scoped_from' do
|
|
64
|
-
|
|
65
|
-
it 'just build a new query and return its scope' do
|
|
66
|
-
query = double(:query)
|
|
67
|
-
expect(query).to receive(:relation).and_return(42)
|
|
68
|
-
expect(ScopedFrom::Query).to receive(:new).with(User, 'foo', except: 'bam').and_return(query)
|
|
69
|
-
expect(User.scoped_from('foo', except: 'bam')).to eq(42)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
it 'build scopes' do
|
|
73
|
-
expect(User.scoped_from(search: 'jane')).to eq([users(:jane)])
|
|
74
|
-
expect(User.scoped_from(search: 'john')).to eq([users(:john)])
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
it 'can be chained with other scopes' do
|
|
78
|
-
expect(User.scoped_from(search: 'jane')).to eq([users(:jane)])
|
|
79
|
-
expect(User.enabled.scoped_from(search: 'jane')).to eq([])
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
it 'can be used with order as parameter' do
|
|
83
|
-
expect(User.scoped_from(order: 'firstname').first).to eq(users(:jane))
|
|
84
|
-
expect(User.scoped_from(order: 'firstname.desc').first).to eq(users(:john))
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
it 'builds a ScopedFrom::Query' do
|
|
88
|
-
expect(User.scoped_from({}).query.class).to be(ScopedFrom::Query)
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
it 'builds a ScopedFrom::Query if #{RecordClassName}Query is not defined' do
|
|
92
|
-
expect(Post.scoped_from({}).query.class).to be(ScopedFrom::Query)
|
|
93
|
-
expect(Object.const_defined?('PostQuery')).to be(false)
|
|
94
|
-
expect {
|
|
95
|
-
PostQuery
|
|
96
|
-
}.to raise_error(NameError, 'uninitialized constant PostQuery')
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
it 'builds a #{Class}Query if #{RecordClassName}Query is defined and is a ScopedFrom::Query' do
|
|
100
|
-
expect(Comment.scoped_from({}).query.class).to be(CommentQuery)
|
|
101
|
-
expect(Comment.where(foo: 'bar').scoped_from({}).query.class).to be(CommentQuery)
|
|
102
|
-
expect(CommentQuery).to be_a(Class)
|
|
103
|
-
expect(CommentQuery.ancestors).to include(ScopedFrom::Query)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
it 'builds a ScopedFrom::Query if #{RecordClassName}Query is defined but not a subclass of ScopedFrom::Query' do
|
|
107
|
-
expect(User.scoped_from({}).query.class).to be(ScopedFrom::Query)
|
|
108
|
-
expect(Object.const_defined?('UserQuery')).to be(true)
|
|
109
|
-
expect(UserQuery).to be_a(Class)
|
|
110
|
-
expect(UserQuery.ancestors).not_to include(ScopedFrom::Query)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
it 'builds a ScopedFrom::Query if #{RecordClassName}Query is defined but is a module' do
|
|
114
|
-
expect(Vote.scoped_from({}).query.class).to be(ScopedFrom::Query)
|
|
115
|
-
expect(Object.const_defined?('VoteQuery')).to be(true)
|
|
116
|
-
expect(VoteQuery).to be_a(Module)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
it 'is accepts ActionController::Parameters' do
|
|
120
|
-
expect(User.scoped_from(ActionController::Parameters.new(search: 'jane'))).to eq([users(:jane)])
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
end
|
|
@@ -1,490 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe ScopedFrom::Query do
|
|
4
|
-
|
|
5
|
-
def query(relation = User, params = {}, options = {})
|
|
6
|
-
ScopedFrom::Query.new(relation, params, options)
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
describe '#false?' do
|
|
10
|
-
|
|
11
|
-
it 'is true if false is given' do
|
|
12
|
-
expect(query.send(:false?, false)).to be(true)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
it 'is true if "false" is given' do
|
|
16
|
-
expect(query.send(:false?, 'false')).to be(true)
|
|
17
|
-
expect(query.send(:false?, 'False')).to be(true)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
it 'is true if "0" is given' do
|
|
21
|
-
expect(query.send(:false?, '0')).to be(true)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
it 'is true if "off" is given' do
|
|
25
|
-
expect(query.send(:false?, 'off')).to be(true)
|
|
26
|
-
expect(query.send(:false?, 'OFF ')).to be(true)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
it 'is true if "no" is given' do
|
|
30
|
-
expect(query.send(:false?, 'no')).to be(true)
|
|
31
|
-
expect(query.send(:false?, ' No ')).to be(true)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it 'is true if "n" is given' do
|
|
35
|
-
expect(query.send(:false?, 'n')).to be(true)
|
|
36
|
-
expect(query.send(:false?, 'N ')).to be(true)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it 'is false if true is given' do
|
|
40
|
-
expect(query.send(:false?, true)).to be(false)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
it 'is false if "true" is given' do
|
|
44
|
-
expect(query.send(:false?, 'true')).to be(false)
|
|
45
|
-
expect(query.send(:false?, 'TrUe')).to be(false)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it 'is false if "1" is given' do
|
|
49
|
-
expect(query.send(:false?, '1')).to be(false)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
it 'is false if "on" is given' do
|
|
53
|
-
expect(query.send(:false?, "on")).to be(false)
|
|
54
|
-
expect(query.send(:false?, "On")).to be(false)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
it 'is false otherwise' do
|
|
58
|
-
expect(query.send(:false?, 42)).to be(false)
|
|
59
|
-
expect(query.send(:false?, 'bam')).to be(false)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
describe '#initialize' do
|
|
65
|
-
|
|
66
|
-
it 'invokes .all method on given class' do
|
|
67
|
-
expect(User).to receive(:all)
|
|
68
|
-
ScopedFrom::Query.new(User, {})
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
it 'does not invokes .all method on given relation' do
|
|
72
|
-
relation = User.all
|
|
73
|
-
expect(relation).not_to receive(:all)
|
|
74
|
-
ScopedFrom::Query.new(relation, {})
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
describe '#invoke_param' do
|
|
80
|
-
|
|
81
|
-
it 'returns given scope if it has no scope with specified name' do
|
|
82
|
-
expect(query.send(:invoke_param, User, :foo, true)).to eq(User)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
it 'returns given scope if scope takes more than 1 argument' do
|
|
86
|
-
expect(query.send(:invoke_param, User, :created_between, true)).to eq(User)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
it 'invokes scope without arguments if scope takes no arguments' do
|
|
90
|
-
expect(query.send(:invoke_param, User.all, :enabled, true)).to eq([users(:john)])
|
|
91
|
-
expect(query.send(:invoke_param, User.all, :enabled, ' 1 ')).to eq([users(:john)])
|
|
92
|
-
expect(query.send(:invoke_param, User.all, :enabled, 'off')).to eq([users(:john)])
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
it 'invokes scope with value has argument if scope takes one argument' do
|
|
96
|
-
expect(query.send(:invoke_param, User.all, :search, 'doe')).to eq([users(:john), users(:jane)])
|
|
97
|
-
expect(query.send(:invoke_param, User.all, :search, 'john')).to eq([users(:john)])
|
|
98
|
-
expect(query.send(:invoke_param, User.all, :search, 'jane')).to eq([users(:jane)])
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
it 'scope on column conditions' do
|
|
102
|
-
expect(query.send(:invoke_param, User.all, :firstname, 'Jane')).to eq([users(:jane)])
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
it 'invokes "order"' do
|
|
106
|
-
expect(query.send(:invoke_param, User.all, :order, 'firstname.asc')).to eq([users(:jane), users(:john)])
|
|
107
|
-
expect(query.send(:invoke_param, User.all, :order, 'firstname.desc')).to eq([users(:john), users(:jane)])
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
describe '#options' do
|
|
113
|
-
|
|
114
|
-
it 'is set at initialization' do
|
|
115
|
-
expect(ScopedFrom::Query.new(User, {}, bar: 'foo').instance_variable_get(:@options)).to eq(bar: 'foo')
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
it 'keys are symbolized' do
|
|
119
|
-
expect(ScopedFrom::Query.new(User, {}, 'bar' => 'foo').instance_variable_get(:@options)).to eq(bar: 'foo')
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
describe '#order_column' do
|
|
125
|
-
|
|
126
|
-
it 'is column specified into "order" parameter' do
|
|
127
|
-
expect(query(User, order: 'firstname').order_column).to eq('firstname')
|
|
128
|
-
expect(query(User, order: 'lastname.desc').order_column).to eq('lastname')
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
it 'is nil if column does not exist' do
|
|
132
|
-
expect(query(User, order: 'foo').order_column).to be_nil
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
it 'is nil if "order" param is not specified' do
|
|
136
|
-
expect(query(User, search: 'foo').order_column).to be_nil
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
describe '#order_direction' do
|
|
142
|
-
|
|
143
|
-
it 'is direction specified into "order" parameter' do
|
|
144
|
-
expect(query(User, order: 'firstname.asc').order_direction).to eq('asc')
|
|
145
|
-
expect(query(User, order: 'firstname.desc').order_direction).to eq('desc')
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
it 'is "asc" if direction is not specified' do
|
|
149
|
-
expect(query(User, order: 'firstname').order_direction).to eq('asc')
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
it 'is "asc" if direction is invalid' do
|
|
153
|
-
expect(query(User, order: 'firstname.foo').order_direction).to eq('asc')
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
it 'is direction even specified in another case' do
|
|
157
|
-
expect(query(User, order: 'firstname.ASc').order_direction).to eq('asc')
|
|
158
|
-
expect(query(User, order: 'firstname.DeSC').order_direction).to eq('desc')
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
it 'is nil if column does not exist' do
|
|
162
|
-
expect(query(User, order: 'foo.desc').order_direction).to be_nil
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
it 'is nil if "order" param is not specified' do
|
|
166
|
-
expect(query(User, search: 'foo').order_direction).to be_nil
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
describe '#params' do
|
|
172
|
-
|
|
173
|
-
it 'returns params specified at initialization' do
|
|
174
|
-
expect(query(User, search: 'foo', 'enabled' => true).params).to eq({ 'search' => 'foo', 'enabled' => true })
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
it 'returns an hash with indifferent access' do
|
|
178
|
-
expect(query(User, 'search' => 'bar').params).to be_a(ActiveSupport::HashWithIndifferentAccess)
|
|
179
|
-
expect(query(User, 'search' => 'bar').params[:search]).to eq('bar')
|
|
180
|
-
expect(query(User, search: 'bar').params['search']).to eq('bar')
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
it 'can be converted to query string' do
|
|
184
|
-
expect(query(User, search: ['foo', 'bar'], 'enabled' => '1').params.to_query).to eq('enabled=true&search%5B%5D=foo&search%5B%5D=bar')
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
describe '#params=' do
|
|
190
|
-
|
|
191
|
-
it 'does not fails if nil is given' do
|
|
192
|
-
expect(query(User, nil).params).to eq({})
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
it 'removes values that are not scopes' do
|
|
196
|
-
expect(query(User, foo: 'bar', 'search' => 'foo', enabled: true).params).to eq({ 'search' => 'foo', 'enabled' => true })
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
it 'is case sensitive' do
|
|
200
|
-
expect(query(User, 'Enabled' => true, "SEARCH" => 'bar').params).to be_empty
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
it 'parse query string' do
|
|
204
|
-
expect(query(User, 'search=foo%26baz&latest=true').params).to eq({ 'search' => 'foo&baz', 'latest' => true })
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
it 'removes blank values from query string' do
|
|
208
|
-
expect(query(User, 'search=baz&toto=&bar=%20').params).to eq({ 'search' => 'baz' })
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
it 'unescapes UTF-8 chars' do
|
|
212
|
-
expect(query(User, 'search=%C3%A9').params).to eq({ 'search' => 'é' })
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
it 'can have multiple values (from hash)' do
|
|
216
|
-
expect(query(User, search: ['bar', 'baz']).params).to eq({ 'search' => ['bar', 'baz'] })
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
it 'can have multiple values (from query string)' do
|
|
220
|
-
expect(query(User, 'search=bar&search=baz').params).to eq({ 'search' => ['bar', 'baz'] })
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
it 'converts value to true (or remove it) if scope takes no argument' do
|
|
224
|
-
expect(query(User, latest: 'y').params).to eq({ 'latest' => true })
|
|
225
|
-
expect(query(User, latest: 'no').params).to eq({})
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
it 'converts value to true (or false) if column is a boolean one' do
|
|
229
|
-
expect(query(User, admin: 'y').params).to eq({ 'admin' => true })
|
|
230
|
-
expect(query(User, admin: 'False').params).to eq({ 'admin' => false })
|
|
231
|
-
expect(query(User, admin: 'bar').params).to eq({})
|
|
232
|
-
expect(query(User, admin: ['y', false]).params).to eq({})
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
it 'converts array value to true (or remove it) if scope takes no argument' do
|
|
236
|
-
expect(query(User, latest: true).params).to eq({ 'latest' => true })
|
|
237
|
-
expect(query(User, latest: ['Yes']).params).to eq({ 'latest' => true })
|
|
238
|
-
expect(query(User, latest: ['no', 'yes']).params).to eq({})
|
|
239
|
-
expect(query(User, latest: ['no', nil]).params).to eq({})
|
|
240
|
-
expect(query(User, latest: ['fo']).params).to eq({})
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
it 'flats array' do
|
|
244
|
-
expect(query(User, search: [nil, ['bar', '', 'foo', ["\n ", 'baz']]]).params).to eq({ 'search' => [nil, 'bar', '', 'foo', "\n ", 'baz'] })
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
it 'change array with a single value in one value' do
|
|
248
|
-
expect(query(User, search: ['bar']).params).to eq({ 'search' => 'bar' })
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
it 'does not modify given hash' do
|
|
252
|
-
hash = { search: 'foo', enabled: '1', bar: 'foo' }
|
|
253
|
-
query(User, hash)
|
|
254
|
-
expect(hash).to eq({ search: 'foo', enabled: '1', bar: 'foo' })
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
it 'does not modify given array' do
|
|
258
|
-
items = ['bar', 'foo', nil]
|
|
259
|
-
query(User, search: items)
|
|
260
|
-
expect(items).to eq(['bar', 'foo', nil])
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
it 'accepts :only option' do
|
|
264
|
-
expect(query(User, { search: 'bar', enabled: 'true' }, only: [:search]).params).to eq({ 'search' => 'bar' })
|
|
265
|
-
expect(query(User, { search: 'bar', enabled: 'true' }, only: 'search').params).to eq({ 'search' => 'bar' })
|
|
266
|
-
expect(query(User, { search: 'bar', firstname: 'Jane', enabled: 'true' }, only: 'search').params).to eq({ 'search' => 'bar' })
|
|
267
|
-
expect(query(User, { search: 'bar', firstname: 'Jane', enabled: 'true' }, only: ['search', :firstname]).params).to eq({ 'search' => 'bar', 'firstname' => 'Jane' })
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
it 'accepts :except option' do
|
|
271
|
-
expect(query(User, { search: 'bar', enabled: true }, except: [:search]).params).to eq({ 'enabled' => true })
|
|
272
|
-
expect(query(User, { search: 'bar', enabled: true }, except: 'search').params).to eq({ 'enabled' => true })
|
|
273
|
-
expect(query(User, { search: 'bar', firstname: 'Jane', enabled: true }, except: 'search').params).to eq({ 'enabled' => true, 'firstname' => 'Jane' })
|
|
274
|
-
expect(query(User, { search: 'bar', firstname: 'Jane', enabled: true }, except: ['search', :firstname]).params).to eq({ 'enabled' => true })
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
it 'accepts a query instance' do
|
|
278
|
-
expect(query(User, query(User, search: 'toto')).params).to eq({ 'search' => 'toto' })
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
it 'preserve blank values' do
|
|
282
|
-
expect(query(User, { search: "\n ", 'enabled' => true }).params).to eq({ 'search' => "\n ", 'enabled' => true })
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
it 'preserve blank values from array' do
|
|
286
|
-
expect(query(User, { 'search' => ["\n ", 'toto', 'titi'] }).params).to eq({ 'search' => ["\n ", 'toto', 'titi'] })
|
|
287
|
-
expect(query(User, { 'search' => [] }).params).to eq({})
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
it 'also preserve blank on query string' do
|
|
291
|
-
expect(query(User, 'search=%20&enabled=true&search=foo').params).to eq({ 'search' => [' ', 'foo'], 'enabled' => true })
|
|
292
|
-
end
|
|
293
|
-
|
|
294
|
-
it 'includes column values' do
|
|
295
|
-
expect(query(User, 'firstname' => 'Jane', 'foo' => 'bar').params).to eq({ 'firstname' => 'Jane' })
|
|
296
|
-
expect(query(User, firstname: 'Jane', 'foo' => 'bar').params).to eq({ 'firstname' => 'Jane' })
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
it 'exclude column values if :exclude_columns option is specified' do
|
|
300
|
-
expect(query(User, { enabled: true, 'firstname' => 'Jane', 'foo' => 'bar' }, exclude_columns: true).params).to eq({ 'enabled' => true })
|
|
301
|
-
expect(query(User, { enabled: true, firstname: 'Jane', foo: 'bar' }, exclude_columns: true).params).to eq({ 'enabled' => true })
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
it 'scopes have priority on columns' do
|
|
305
|
-
expect(query(User, enabled: false).params).to eq({})
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
it 'maps an "order"' do
|
|
309
|
-
expect(query(User, { 'order' => 'firstname.asc' }).params).to eq({ 'order' => 'firstname.asc' })
|
|
310
|
-
end
|
|
311
|
-
|
|
312
|
-
it 'does not map "order" if column is invalid' do
|
|
313
|
-
expect(query(User, { 'order' => 'foo.asc' }).params).to eq({})
|
|
314
|
-
end
|
|
315
|
-
|
|
316
|
-
it 'use "asc" order direction by default' do
|
|
317
|
-
expect(query(User, { 'order' => 'firstname' }).params).to eq({ 'order' => 'firstname.asc' })
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
it 'use "asc" order direction if invalid' do
|
|
321
|
-
expect(query(User, { 'order' => 'firstname.bar' }).params).to eq({ 'order' => 'firstname.asc' })
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
it 'use "desc" order direction if specified' do
|
|
325
|
-
expect(query(User, { 'order' => 'firstname.desc' }).params).to eq({ 'order' => 'firstname.desc' })
|
|
326
|
-
end
|
|
327
|
-
|
|
328
|
-
it 'order direction is case insensitive' do
|
|
329
|
-
expect(query(User, { 'order' => 'firstname.Asc' }).params).to eq({ 'order' => 'firstname.asc' })
|
|
330
|
-
expect(query(User, { 'order' => 'firstname.DESC' }).params).to eq({ 'order' => 'firstname.desc' })
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
it 'order can be specified as symbol' do
|
|
334
|
-
expect(query(User, { order: 'firstname.desc' }).params).to eq({ 'order' => 'firstname.desc' })
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
it "order is case sensitive" do
|
|
338
|
-
expect(query(User, { 'Order' => 'firstname.desc' }).params).to eq({})
|
|
339
|
-
end
|
|
340
|
-
|
|
341
|
-
it 'many order can be specified' do
|
|
342
|
-
expect(query(User, { 'order' => ['firstname.Asc', 'lastname.DESC'] }).params).to eq({ 'order' => ['firstname.asc', 'lastname.desc'] })
|
|
343
|
-
expect(query(User, { 'order' => ['firstname.Asc', 'firstname.desc'] }).params).to eq({ 'order' => 'firstname.asc' })
|
|
344
|
-
expect(query(User, { 'order' => ['firstname.Asc', 'lastname.DESC', 'firstname.desc'] }).params).to eq({ 'order' => ['firstname.asc', 'lastname.desc'] })
|
|
345
|
-
expect(query(User, { 'order' => ['firstname.Asc', 'foo', 'lastname.DESC', 'firstname.desc'] }).params).to eq({ 'order' => ['firstname.asc', 'lastname.desc'] })
|
|
346
|
-
end
|
|
347
|
-
|
|
348
|
-
it 'order can be delimited by a space' do
|
|
349
|
-
expect(query(User, { 'order' => 'firstname ASC' }).params).to eq({ 'order' => 'firstname.asc' })
|
|
350
|
-
end
|
|
351
|
-
|
|
352
|
-
it 'order can be delimited by any white space' do
|
|
353
|
-
expect(query(User, { 'order' => "firstname\nASC" }).params).to eq({ 'order' => 'firstname.asc' })
|
|
354
|
-
expect(query(User, { 'order' => "firstname\t ASC" }).params).to eq({ 'order' => 'firstname.asc' })
|
|
355
|
-
end
|
|
356
|
-
|
|
357
|
-
it 'order can be delimited by a ":"' do
|
|
358
|
-
expect(query(User, { 'order' => "firstname:ASC" }).params).to eq({ 'order' => 'firstname.asc' })
|
|
359
|
-
end
|
|
360
|
-
|
|
361
|
-
it 'order can be delimited by more than one delimiter' do
|
|
362
|
-
expect(query(User, { 'order' => "firstname :. ASC" }).params).to eq({ 'order' => 'firstname.asc' })
|
|
363
|
-
end
|
|
364
|
-
|
|
365
|
-
end
|
|
366
|
-
|
|
367
|
-
describe '#relation' do
|
|
368
|
-
|
|
369
|
-
it 'does not execute any query' do
|
|
370
|
-
expect(User).not_to receive(:connection)
|
|
371
|
-
query(User, enabled: true).relation
|
|
372
|
-
end
|
|
373
|
-
|
|
374
|
-
it 'works with scopes with a lambda without arguments' do
|
|
375
|
-
users(:jane).update_attribute(:created_at, 10.days.ago)
|
|
376
|
-
expect(query(User, latest: true).relation).to eq([users(:john)])
|
|
377
|
-
expect(query(User, latest: false).relation).to eq([users(:john), users(:jane)])
|
|
378
|
-
end
|
|
379
|
-
|
|
380
|
-
it 'does not modify relation specified at initialization' do
|
|
381
|
-
relation = User.search('foo')
|
|
382
|
-
q = query(relation, enabled: true)
|
|
383
|
-
expect {
|
|
384
|
-
expect {
|
|
385
|
-
q.relation
|
|
386
|
-
}.not_to change { q.instance_variable_get('@relation') }
|
|
387
|
-
}.not_to change { relation }
|
|
388
|
-
end
|
|
389
|
-
|
|
390
|
-
it 'returns relation specified at construction if params are empty' do
|
|
391
|
-
expect(query.relation).not_to eq(User)
|
|
392
|
-
expect(query.relation).to eq(User.all)
|
|
393
|
-
end
|
|
394
|
-
|
|
395
|
-
it 'invokes many times relation if an array is given' do
|
|
396
|
-
expect(query(User, search: ['John', 'Doe']).relation).to eq([users(:john)])
|
|
397
|
-
expect(query(User, search: ['John', 'Done']).relation).to eq([])
|
|
398
|
-
expect(query(User, search: ['John', 'Doe']).params).to eq({ 'search' => ['John', 'Doe'] })
|
|
399
|
-
end
|
|
400
|
-
|
|
401
|
-
it 'invokes many times relation if given twice (as string & symbol)' do
|
|
402
|
-
expect(query(User, search: 'John', 'search' => 'Done').params['search']).to contain_exactly('John', 'Done')
|
|
403
|
-
expect(query(User, search: 'John', 'search' => ['Did', 'Done']).params['search']).to contain_exactly('John', 'Did', 'Done')
|
|
404
|
-
end
|
|
405
|
-
|
|
406
|
-
it 'invokes last order if an array is given' do
|
|
407
|
-
create_user(:jane2, firstname: 'Jane', lastname: 'Zoe')
|
|
408
|
-
|
|
409
|
-
expect(query(User, order: ['lastname', 'firstname']).relation).to eq([users(:jane), users(:john), users(:jane2)])
|
|
410
|
-
expect(query(User, order: ['lastname', 'firstname.desc']).relation).to eq([users(:john), users(:jane), users(:jane2)])
|
|
411
|
-
expect(query(User, order: ['firstname', 'lastname.desc']).relation).to eq([users(:jane2), users(:jane), users(:john)])
|
|
412
|
-
expect(query(User, order: ['firstname.desc', 'lastname']).relation.order_values.map(&:class)).to eq([Arel::Nodes::Descending, Arel::Nodes::Ascending])
|
|
413
|
-
expect(query(User, order: ['firstname.desc', 'lastname']).relation.order_values.map(&:expr).map(&:name)).to eq(['firstname', 'lastname'])
|
|
414
|
-
end
|
|
415
|
-
|
|
416
|
-
it 'defines #query method on returned relation' do
|
|
417
|
-
expect(query(User).relation).to respond_to(:query)
|
|
418
|
-
end
|
|
419
|
-
|
|
420
|
-
it 'does not define #query method for future relations' do
|
|
421
|
-
expect(query(User).relation.query).to be_present
|
|
422
|
-
expect(User).not_to respond_to(:query)
|
|
423
|
-
expect(User.all).not_to respond_to(:query)
|
|
424
|
-
expect(User.enabled).not_to respond_to(:query)
|
|
425
|
-
end
|
|
426
|
-
|
|
427
|
-
it 'defined #query method returns query' do
|
|
428
|
-
q = query(User)
|
|
429
|
-
expect(q.relation.query).to be_a(ScopedFrom::Query)
|
|
430
|
-
expect(q.relation.query).to be(q)
|
|
431
|
-
end
|
|
432
|
-
|
|
433
|
-
end
|
|
434
|
-
|
|
435
|
-
describe '#true?' do
|
|
436
|
-
|
|
437
|
-
it 'is true if true is given' do
|
|
438
|
-
expect(query.send(:true?, true)).to be(true)
|
|
439
|
-
end
|
|
440
|
-
|
|
441
|
-
it 'is true if "true" is given' do
|
|
442
|
-
expect(query.send(:true?, 'true')).to be(true)
|
|
443
|
-
expect(query.send(:true?, 'True')).to be(true)
|
|
444
|
-
end
|
|
445
|
-
|
|
446
|
-
it 'is true if "1" is given' do
|
|
447
|
-
expect(query.send(:true?, '1')).to be(true)
|
|
448
|
-
end
|
|
449
|
-
|
|
450
|
-
it 'is true if "on" is given' do
|
|
451
|
-
expect(query.send(:true?, 'on')).to be(true)
|
|
452
|
-
expect(query.send(:true?, 'ON ')).to be(true)
|
|
453
|
-
end
|
|
454
|
-
|
|
455
|
-
it 'is true if "yes" is given' do
|
|
456
|
-
expect(query.send(:true?, 'yes')).to be(true)
|
|
457
|
-
expect(query.send(:true?, ' Yes ')).to be(true)
|
|
458
|
-
end
|
|
459
|
-
|
|
460
|
-
it 'is true if "y" is given' do
|
|
461
|
-
expect(query.send(:true?, 'y')).to be(true)
|
|
462
|
-
expect(query.send(:true?, 'Y ')).to be(true)
|
|
463
|
-
end
|
|
464
|
-
|
|
465
|
-
it 'is false if false is given' do
|
|
466
|
-
expect(query.send(:true?, false)).to be(false)
|
|
467
|
-
end
|
|
468
|
-
|
|
469
|
-
it 'is false if "false" is given' do
|
|
470
|
-
expect(query.send(:true?, 'false')).to be(false)
|
|
471
|
-
expect(query.send(:true?, 'FsALSE')).to be(false)
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
it 'is false if "0" is given' do
|
|
475
|
-
expect(query.send(:true?, '0')).to be(false)
|
|
476
|
-
end
|
|
477
|
-
|
|
478
|
-
it 'is false if "off" is given' do
|
|
479
|
-
expect(query.send(:true?, "off")).to be(false)
|
|
480
|
-
expect(query.send(:true?, "Off")).to be(false)
|
|
481
|
-
end
|
|
482
|
-
|
|
483
|
-
it 'is false otherwise' do
|
|
484
|
-
expect(query.send(:true?, 42)).to be(false)
|
|
485
|
-
expect(query.send(:true?, 'bam')).to be(false)
|
|
486
|
-
end
|
|
487
|
-
|
|
488
|
-
end
|
|
489
|
-
|
|
490
|
-
end
|
data/spec/scoped_from_spec.rb
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe ScopedFrom do
|
|
4
|
-
|
|
5
|
-
describe '.version' do
|
|
6
|
-
|
|
7
|
-
subject { ScopedFrom.version }
|
|
8
|
-
|
|
9
|
-
it { should be_a(String) }
|
|
10
|
-
it { should match(/^\d+\.\d+(\.\d+)?/) }
|
|
11
|
-
|
|
12
|
-
it 'is freezed' do
|
|
13
|
-
expect {
|
|
14
|
-
ScopedFrom.version.gsub!('.', '#')
|
|
15
|
-
}.to raise_error(/can't modify frozen string/i)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
end
|
data/spec/spec_helper.rb
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
ENV["RAILS_ENV"] ||= 'test'
|
|
2
|
-
|
|
3
|
-
require File.expand_path("#{__dir__}/../lib/scoped_from")
|
|
4
|
-
require 'action_controller'
|
|
5
|
-
require 'byebug'
|
|
6
|
-
|
|
7
|
-
# Support
|
|
8
|
-
Dir["#{__dir__}/support/**/*.rb"].each { |f| require File.expand_path(f) }
|
|
9
|
-
|
|
10
|
-
# Mocks
|
|
11
|
-
ActiveSupport::Dependencies.autoload_paths << "#{__dir__}/mocks"
|
|
12
|
-
|
|
13
|
-
RSpec.configure do |config|
|
|
14
|
-
config.raise_errors_for_deprecations!
|
|
15
|
-
|
|
16
|
-
config.include(UserMacro)
|
|
17
|
-
|
|
18
|
-
config.before(:each) do
|
|
19
|
-
Comment.delete_all
|
|
20
|
-
Post.delete_all
|
|
21
|
-
User.delete_all
|
|
22
|
-
Vote.delete_all
|
|
23
|
-
|
|
24
|
-
create_user(:john, firstname: 'John', lastname: 'Doe', enabled: true, admin: true)
|
|
25
|
-
create_user(:jane, firstname: 'Jane', lastname: 'Doe', enabled: false, admin: false)
|
|
26
|
-
end
|
|
27
|
-
end
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: File.expand_path("#{__dir__}/../../test.sqlite3"), timeout: 5000)
|
|
2
|
-
|
|
3
|
-
ActiveRecord::Base.connection.create_table(:comments, force: true)
|
|
4
|
-
ActiveRecord::Base.connection.create_table(:posts, force: true)
|
|
5
|
-
ActiveRecord::Base.connection.create_table(:users, force: true) do |t|
|
|
6
|
-
t.string :firstname, null: false
|
|
7
|
-
t.string :lastname, null: false
|
|
8
|
-
t.boolean :enabled, null: false, default: false
|
|
9
|
-
t.boolean :admin, null: false, default: false
|
|
10
|
-
t.timestamps null: false
|
|
11
|
-
end
|
|
12
|
-
ActiveRecord::Base.connection.create_table(:votes, force: true)
|