ransack 1.2.3 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -4
- data/CONTRIBUTING.md +12 -4
- data/Gemfile +4 -5
- data/README.md +160 -55
- data/lib/ransack.rb +1 -1
- data/lib/ransack/adapters/active_record/3.0/context.rb +16 -0
- data/lib/ransack/adapters/active_record/3.1/context.rb +24 -0
- data/lib/ransack/adapters/active_record/base.rb +6 -0
- data/lib/ransack/adapters/active_record/context.rb +49 -1
- data/lib/ransack/configuration.rb +23 -6
- data/lib/ransack/constants.rb +46 -45
- data/lib/ransack/context.rb +19 -2
- data/lib/ransack/helpers/form_builder.rb +5 -4
- data/lib/ransack/helpers/form_helper.rb +34 -14
- data/lib/ransack/locale/hu.yml +70 -0
- data/lib/ransack/locale/nl.yml +70 -0
- data/lib/ransack/nodes/attribute.rb +2 -2
- data/lib/ransack/nodes/condition.rb +29 -12
- data/lib/ransack/nodes/grouping.rb +6 -6
- data/lib/ransack/nodes/node.rb +1 -1
- data/lib/ransack/nodes/value.rb +1 -1
- data/lib/ransack/predicate.rb +4 -5
- data/lib/ransack/ransacker.rb +1 -1
- data/lib/ransack/search.rb +39 -13
- data/lib/ransack/translate.rb +7 -8
- data/lib/ransack/version.rb +1 -1
- data/ransack.gemspec +5 -5
- data/spec/ransack/adapters/active_record/base_spec.rb +78 -35
- data/spec/ransack/adapters/active_record/context_spec.rb +58 -15
- data/spec/ransack/configuration_spec.rb +18 -18
- data/spec/ransack/dependencies_spec.rb +1 -1
- data/spec/ransack/helpers/form_builder_spec.rb +29 -29
- data/spec/ransack/helpers/form_helper_spec.rb +14 -1
- data/spec/ransack/nodes/condition_spec.rb +21 -2
- data/spec/ransack/predicate_spec.rb +49 -9
- data/spec/ransack/search_spec.rb +178 -143
- data/spec/ransack/translate_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/support/schema.rb +26 -21
- metadata +15 -11
@@ -46,7 +46,7 @@ module Ransack
|
|
46
46
|
should match /sort_link desc/
|
47
47
|
}
|
48
48
|
it {
|
49
|
-
should match /Full Name
|
49
|
+
should match /Full Name ▼/
|
50
50
|
}
|
51
51
|
end
|
52
52
|
|
@@ -71,6 +71,19 @@ module Ransack
|
|
71
71
|
}
|
72
72
|
end
|
73
73
|
|
74
|
+
describe '#sort_link works even if search params are a blank string' do
|
75
|
+
before { @controller.view_context.params[:q] = '' }
|
76
|
+
specify {
|
77
|
+
expect {
|
78
|
+
@controller.view_context.sort_link(
|
79
|
+
Person.search(@controller.view_context.params[:q]),
|
80
|
+
:name,
|
81
|
+
:controller => 'people'
|
82
|
+
)
|
83
|
+
}.not_to raise_error
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
74
87
|
describe '#sort_link with default search_key defined as string' do
|
75
88
|
subject {
|
76
89
|
@controller.view_context.sort_link(
|
@@ -7,9 +7,28 @@ module Ransack
|
|
7
7
|
context 'with multiple values and an _any predicate' do
|
8
8
|
subject { Condition.extract(Context.for(Person), 'name_eq_any', Person.first(2).map(&:name)) }
|
9
9
|
|
10
|
-
specify { subject.values.
|
10
|
+
specify { expect(subject.values.size).to eq(2) }
|
11
11
|
end
|
12
12
|
|
13
|
+
context 'with an invalid predicate' do
|
14
|
+
subject { Condition.extract(Context.for(Person), 'name_invalid', Person.first.name) }
|
15
|
+
|
16
|
+
context "when ignore_unknown_conditions is false" do
|
17
|
+
before do
|
18
|
+
Ransack.configure { |config| config.ignore_unknown_conditions = false }
|
19
|
+
end
|
20
|
+
|
21
|
+
specify { expect { subject }.to raise_error ArgumentError }
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when ignore_unknown_conditions is true" do
|
25
|
+
before do
|
26
|
+
Ransack.configure { |config| config.ignore_unknown_conditions = true }
|
27
|
+
end
|
28
|
+
|
29
|
+
specify { subject.should be_nil }
|
30
|
+
end
|
31
|
+
end
|
13
32
|
end
|
14
33
|
end
|
15
|
-
end
|
34
|
+
end
|
@@ -15,7 +15,7 @@ module Ransack
|
|
15
15
|
|
16
16
|
it "escapes '%', '.' and '\\\\' in value" do
|
17
17
|
subject.send(:"#{method}=", '%._\\')
|
18
|
-
subject.result.to_sql.
|
18
|
+
expect(subject.result.to_sql).to match(regexp)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -24,25 +24,25 @@ module Ransack
|
|
24
24
|
@s.awesome_eq = true
|
25
25
|
field = "#{quote_table_name("people")}.#{
|
26
26
|
quote_column_name("awesome")}"
|
27
|
-
@s.result.to_sql.
|
27
|
+
expect(@s.result.to_sql).to match /#{field} = #{
|
28
28
|
ActiveRecord::Base.connection.quoted_true}/
|
29
29
|
end
|
30
30
|
|
31
31
|
it 'generates an equality condition for boolean false' do
|
32
32
|
@s.awesome_eq = false
|
33
33
|
field = "#{quote_table_name("people")}.#{quote_column_name("awesome")}"
|
34
|
-
@s.result.to_sql.
|
34
|
+
expect(@s.result.to_sql).to match /#{field} = #{
|
35
35
|
ActiveRecord::Base.connection.quoted_false}/
|
36
36
|
end
|
37
37
|
|
38
38
|
it 'does not generate a condition for nil' do
|
39
39
|
@s.awesome_eq = nil
|
40
|
-
@s.result.to_sql.
|
40
|
+
expect(@s.result.to_sql).not_to match /WHERE/
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
44
|
describe 'cont' do
|
45
|
-
|
45
|
+
|
46
46
|
it_has_behavior 'wildcard escaping', :name_cont,
|
47
47
|
(if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
|
48
48
|
/"people"."name" ILIKE '%\\%\\._\\\\%'/
|
@@ -57,7 +57,7 @@ module Ransack
|
|
57
57
|
it 'generates a LIKE query with value surrounded by %' do
|
58
58
|
@s.name_cont = 'ric'
|
59
59
|
field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
|
60
|
-
@s.result.to_sql.
|
60
|
+
expect(@s.result.to_sql).to match /#{field} I?LIKE '%ric%'/
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
@@ -76,7 +76,7 @@ module Ransack
|
|
76
76
|
it 'generates a NOT LIKE query with value surrounded by %' do
|
77
77
|
@s.name_not_cont = 'ric'
|
78
78
|
field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
|
79
|
-
@s.result.to_sql.
|
79
|
+
expect(@s.result.to_sql).to match /#{field} NOT I?LIKE '%ric%'/
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
@@ -84,7 +84,13 @@ module Ransack
|
|
84
84
|
it 'generates a value IS NULL query' do
|
85
85
|
@s.name_null = true
|
86
86
|
field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
|
87
|
-
@s.result.to_sql.
|
87
|
+
expect(@s.result.to_sql).to match /#{field} IS NULL/
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'generates a value IS NOT NULL query when assigned false' do
|
91
|
+
@s.name_null = false
|
92
|
+
field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
|
93
|
+
expect(@s.result.to_sql).to match /#{field} IS NOT NULL/
|
88
94
|
end
|
89
95
|
end
|
90
96
|
|
@@ -92,7 +98,41 @@ module Ransack
|
|
92
98
|
it 'generates a value IS NOT NULL query' do
|
93
99
|
@s.name_not_null = true
|
94
100
|
field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
|
95
|
-
@s.result.to_sql.
|
101
|
+
expect(@s.result.to_sql).to match /#{field} IS NOT NULL/
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'generates a value IS NULL query when assigned false' do
|
105
|
+
@s.name_not_null = false
|
106
|
+
field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
|
107
|
+
expect(@s.result.to_sql).to match /#{field} IS NULL/
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'present' do
|
112
|
+
it %q[generates a value IS NOT NULL AND value != '' query] do
|
113
|
+
@s.name_present = true
|
114
|
+
field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
|
115
|
+
expect(@s.result.to_sql).to match /#{field} IS NOT NULL AND #{field} != ''/
|
116
|
+
end
|
117
|
+
|
118
|
+
it %q[generates a value IS NULL OR value = '' query when assigned false] do
|
119
|
+
@s.name_present = false
|
120
|
+
field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
|
121
|
+
expect(@s.result.to_sql).to match /#{field} IS NULL OR #{field} = ''/
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe 'blank' do
|
126
|
+
it %q[generates a value IS NULL OR value = '' query] do
|
127
|
+
@s.name_blank = true
|
128
|
+
field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
|
129
|
+
expect(@s.result.to_sql).to match /#{field} IS NULL OR #{field} = ''/
|
130
|
+
end
|
131
|
+
|
132
|
+
it %q[generates a value IS NOT NULL AND value != '' query when assigned false] do
|
133
|
+
@s.name_blank = false
|
134
|
+
field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
|
135
|
+
expect(@s.result.to_sql).to match /#{field} IS NOT NULL AND #{field} != ''/
|
96
136
|
end
|
97
137
|
end
|
98
138
|
end
|
data/spec/ransack/search_spec.rb
CHANGED
@@ -4,104 +4,116 @@ module Ransack
|
|
4
4
|
describe Search do
|
5
5
|
describe '#initialize' do
|
6
6
|
it "removes empty conditions before building" do
|
7
|
-
Search.
|
7
|
+
expect_any_instance_of(Search).to receive(:build).with({})
|
8
8
|
Search.new(Person, :name_eq => '')
|
9
9
|
end
|
10
10
|
|
11
11
|
it "keeps conditions with a false value before building" do
|
12
|
-
Search.
|
12
|
+
expect_any_instance_of(Search).to receive(:build)
|
13
|
+
.with({ "name_eq" => false })
|
13
14
|
Search.new(Person, :name_eq => false)
|
14
15
|
end
|
15
16
|
|
16
17
|
it "keeps conditions with a value before building" do
|
17
|
-
Search.
|
18
|
+
expect_any_instance_of(Search).to receive(:build)
|
19
|
+
.with({ "name_eq" => 'foobar' })
|
18
20
|
Search.new(Person, :name_eq => 'foobar')
|
19
21
|
end
|
20
22
|
|
21
23
|
it "removes empty suffixed conditions before building" do
|
22
|
-
Search.
|
24
|
+
expect_any_instance_of(Search).to receive(:build).with({})
|
23
25
|
Search.new(Person, :name_eq_any => [''])
|
24
26
|
end
|
25
27
|
|
26
28
|
it "keeps suffixed conditions with a false value before building" do
|
27
|
-
Search.
|
29
|
+
expect_any_instance_of(Search).to receive(:build)
|
30
|
+
.with({ "name_eq_any" => [false] })
|
28
31
|
Search.new(Person, :name_eq_any => [false])
|
29
32
|
end
|
30
33
|
|
31
34
|
it "keeps suffixed conditions with a value before building" do
|
32
|
-
Search.
|
35
|
+
expect_any_instance_of(Search).to receive(:build)
|
36
|
+
.with({ "name_eq_any" => ['foobar'] })
|
33
37
|
Search.new(Person, :name_eq_any => ['foobar'])
|
34
38
|
end
|
35
39
|
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
describe '#initialize' do
|
40
40
|
it 'does not raise exception for string :params argument' do
|
41
|
-
|
41
|
+
expect { Search.new(Person, '') }.not_to raise_error
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'accepts a context option' do
|
45
|
+
shared_context = Context.for(Person)
|
46
|
+
search1 = Search.new(Person, {"name_eq" => "A"}, context: shared_context)
|
47
|
+
search2 = Search.new(Person, {"name_eq" => "B"}, context: shared_context)
|
48
|
+
expect(search1.context).to be search2.context
|
42
49
|
end
|
43
50
|
end
|
44
51
|
|
45
52
|
describe '#build' do
|
46
53
|
it 'creates conditions for top-level attributes' do
|
47
|
-
search = Search.new(Person, name_eq
|
54
|
+
search = Search.new(Person, :name_eq => 'Ernie')
|
48
55
|
condition = search.base[:name_eq]
|
49
|
-
condition.
|
50
|
-
condition.predicate.name.
|
51
|
-
condition.attributes.first.name.
|
52
|
-
condition.value.
|
56
|
+
expect(condition).to be_a Nodes::Condition
|
57
|
+
expect(condition.predicate.name).to eq 'eq'
|
58
|
+
expect(condition.attributes.first.name).to eq 'name'
|
59
|
+
expect(condition.value).to eq 'Ernie'
|
53
60
|
end
|
54
61
|
|
55
62
|
it 'creates conditions for association attributes' do
|
56
|
-
search = Search.new(Person, children_name_eq
|
63
|
+
search = Search.new(Person, :children_name_eq => 'Ernie')
|
57
64
|
condition = search.base[:children_name_eq]
|
58
|
-
condition.
|
59
|
-
condition.predicate.name.
|
60
|
-
condition.attributes.first.name.
|
61
|
-
condition.value.
|
65
|
+
expect(condition).to be_a Nodes::Condition
|
66
|
+
expect(condition.predicate.name).to eq 'eq'
|
67
|
+
expect(condition.attributes.first.name).to eq 'children_name'
|
68
|
+
expect(condition.value).to eq 'Ernie'
|
62
69
|
end
|
63
70
|
|
64
71
|
it 'creates conditions for polymorphic belongs_to association attributes' do
|
65
|
-
search = Search.new(Note, notable_of_Person_type_name_eq
|
72
|
+
search = Search.new(Note, :notable_of_Person_type_name_eq => 'Ernie')
|
66
73
|
condition = search.base[:notable_of_Person_type_name_eq]
|
67
|
-
condition.
|
68
|
-
condition.predicate.name.
|
69
|
-
condition.attributes.first.name.
|
70
|
-
condition.value.
|
74
|
+
expect(condition).to be_a Nodes::Condition
|
75
|
+
expect(condition.predicate.name).to eq 'eq'
|
76
|
+
expect(condition.attributes.first.name).to eq 'notable_of_Person_type_name'
|
77
|
+
expect(condition.value).to eq 'Ernie'
|
71
78
|
end
|
72
79
|
|
73
80
|
it 'creates conditions for multiple polymorphic belongs_to association attributes' do
|
74
81
|
search = Search.new(Note,
|
75
|
-
notable_of_Person_type_name_or_notable_of_Article_type_title_eq
|
82
|
+
:notable_of_Person_type_name_or_notable_of_Article_type_title_eq => 'Ernie')
|
76
83
|
condition = search.
|
77
84
|
base[:notable_of_Person_type_name_or_notable_of_Article_type_title_eq]
|
78
|
-
condition.
|
79
|
-
condition.predicate.name.
|
80
|
-
condition.attributes.first.name.
|
81
|
-
condition.attributes.last.name.
|
82
|
-
condition.value.
|
85
|
+
expect(condition).to be_a Nodes::Condition
|
86
|
+
expect(condition.predicate.name).to eq 'eq'
|
87
|
+
expect(condition.attributes.first.name).to eq 'notable_of_Person_type_name'
|
88
|
+
expect(condition.attributes.last.name).to eq 'notable_of_Article_type_title'
|
89
|
+
expect(condition.value).to eq 'Ernie'
|
83
90
|
end
|
84
91
|
|
85
92
|
it 'discards empty conditions' do
|
86
|
-
search = Search.new(Person, children_name_eq
|
93
|
+
search = Search.new(Person, :children_name_eq => '')
|
87
94
|
condition = search.base[:children_name_eq]
|
88
|
-
condition.
|
95
|
+
expect(condition).to be_nil
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'accepts base grouping condition as an option' do
|
99
|
+
expect(Nodes::Grouping).to receive(:new).with(kind_of(Context), 'or')
|
100
|
+
Search.new(Person, {}, { grouping: 'or' })
|
89
101
|
end
|
90
102
|
|
91
103
|
it 'accepts arrays of groupings' do
|
92
104
|
search = Search.new(Person,
|
93
105
|
g: [
|
94
|
-
{ m
|
95
|
-
{ m
|
106
|
+
{ :m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie' },
|
107
|
+
{ :m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert' },
|
96
108
|
]
|
97
109
|
)
|
98
110
|
ors = search.groupings
|
99
|
-
ors.
|
111
|
+
expect(ors.size).to eq(2)
|
100
112
|
or1, or2 = ors
|
101
|
-
or1.
|
102
|
-
or1.combinator.
|
103
|
-
or2.
|
104
|
-
or2.combinator.
|
113
|
+
expect(or1).to be_a Nodes::Grouping
|
114
|
+
expect(or1.combinator).to eq 'or'
|
115
|
+
expect(or2).to be_a Nodes::Grouping
|
116
|
+
expect(or2.combinator).to eq 'or'
|
105
117
|
end
|
106
118
|
|
107
119
|
it 'accepts "attributes" hashes for groupings' do
|
@@ -112,12 +124,12 @@ module Ransack
|
|
112
124
|
}
|
113
125
|
)
|
114
126
|
ors = search.groupings
|
115
|
-
ors.
|
127
|
+
expect(ors.size).to eq(2)
|
116
128
|
or1, or2 = ors
|
117
|
-
or1.
|
118
|
-
or1.combinator.
|
119
|
-
or2.
|
120
|
-
or2.combinator.
|
129
|
+
expect(or1).to be_a Nodes::Grouping
|
130
|
+
expect(or1.combinator).to eq 'or'
|
131
|
+
expect(or2).to be_a Nodes::Grouping
|
132
|
+
expect(or2.combinator).to eq 'or'
|
121
133
|
end
|
122
134
|
|
123
135
|
it 'accepts "attributes" hashes for conditions' do
|
@@ -129,9 +141,9 @@ module Ransack
|
|
129
141
|
}
|
130
142
|
)
|
131
143
|
conditions = search.base.conditions
|
132
|
-
conditions.
|
133
|
-
conditions.map { |c| c.class }
|
134
|
-
.
|
144
|
+
expect(conditions.size).to eq(2)
|
145
|
+
expect(conditions.map { |c| c.class })
|
146
|
+
.to eq [Nodes::Condition, Nodes::Condition]
|
135
147
|
end
|
136
148
|
|
137
149
|
it 'creates conditions for custom predicates that take arrays' do
|
@@ -139,17 +151,37 @@ module Ransack
|
|
139
151
|
config.add_predicate 'ary_pred', :wants_array => true
|
140
152
|
end
|
141
153
|
|
142
|
-
search = Search.new(Person, name_ary_pred
|
154
|
+
search = Search.new(Person, :name_ary_pred => ['Ernie', 'Bert'])
|
143
155
|
condition = search.base[:name_ary_pred]
|
144
|
-
condition.
|
145
|
-
condition.predicate.name.
|
146
|
-
condition.attributes.first.name.
|
147
|
-
condition.value.
|
156
|
+
expect(condition).to be_a Nodes::Condition
|
157
|
+
expect(condition.predicate.name).to eq 'ary_pred'
|
158
|
+
expect(condition.attributes.first.name).to eq 'name'
|
159
|
+
expect(condition.value).to eq ['Ernie', 'Bert']
|
148
160
|
end
|
149
161
|
|
150
162
|
it 'does not evaluate the query on #inspect' do
|
151
|
-
search = Search.new(Person, children_id_in
|
152
|
-
search.inspect.
|
163
|
+
search = Search.new(Person, :children_id_in => [1, 2, 3])
|
164
|
+
expect(search.inspect).not_to match /ActiveRecord/
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'with an invalid condition' do
|
168
|
+
subject { Search.new(Person, :unknown_attr_eq => 'Ernie') }
|
169
|
+
|
170
|
+
context "when ignore_unknown_conditions is false" do
|
171
|
+
before do
|
172
|
+
Ransack.configure { |config| config.ignore_unknown_conditions = false }
|
173
|
+
end
|
174
|
+
|
175
|
+
specify { expect { subject }.to raise_error ArgumentError }
|
176
|
+
end
|
177
|
+
|
178
|
+
context "when ignore_unknown_conditions is true" do
|
179
|
+
before do
|
180
|
+
Ransack.configure { |config| config.ignore_unknown_conditions = true }
|
181
|
+
end
|
182
|
+
|
183
|
+
specify { expect { subject }.not_to raise_error }
|
184
|
+
end
|
153
185
|
end
|
154
186
|
end
|
155
187
|
|
@@ -161,56 +193,59 @@ module Ransack
|
|
161
193
|
"#{quote_table_name("children_people")}.#{quote_column_name("name")}"
|
162
194
|
}
|
163
195
|
it 'evaluates conditions contextually' do
|
164
|
-
search = Search.new(Person, children_name_eq
|
165
|
-
search.result.
|
196
|
+
search = Search.new(Person, :children_name_eq => 'Ernie')
|
197
|
+
expect(search.result).to be_an ActiveRecord::Relation
|
166
198
|
where = search.result.where_values.first
|
167
|
-
where.to_sql.
|
199
|
+
expect(where.to_sql).to match /#{children_people_name_field} = 'Ernie'/
|
168
200
|
end
|
169
201
|
|
170
202
|
it 'evaluates compound conditions contextually' do
|
171
|
-
search = Search.new(Person, children_name_or_name_eq
|
172
|
-
search.result.
|
203
|
+
search = Search.new(Person, :children_name_or_name_eq => 'Ernie')
|
204
|
+
expect(search.result).to be_an ActiveRecord::Relation
|
173
205
|
where = search.result.where_values.first
|
174
|
-
where.to_sql.
|
206
|
+
expect(where.to_sql).to match /#{children_people_name_field
|
175
207
|
} = 'Ernie' OR #{people_name_field} = 'Ernie'/
|
176
208
|
end
|
177
209
|
|
178
210
|
it 'evaluates polymorphic belongs_to association conditions contextually' do
|
179
|
-
search = Search.new(Note, notable_of_Person_type_name_eq
|
180
|
-
search.result.
|
211
|
+
search = Search.new(Note, :notable_of_Person_type_name_eq => 'Ernie')
|
212
|
+
expect(search.result).to be_an ActiveRecord::Relation
|
181
213
|
where = search.result.where_values.first
|
182
|
-
where.to_sql.
|
214
|
+
expect(where.to_sql).to match /#{people_name_field} = 'Ernie'/
|
183
215
|
end
|
184
216
|
|
185
217
|
it 'evaluates nested conditions' do
|
186
|
-
search = Search.new(Person, children_name_eq
|
187
|
-
g
|
188
|
-
{ m
|
218
|
+
search = Search.new(Person, :children_name_eq => 'Ernie',
|
219
|
+
:g => [
|
220
|
+
{ :m => 'or',
|
221
|
+
:name_eq => 'Ernie',
|
222
|
+
:children_children_name_eq => 'Ernie'
|
223
|
+
}
|
189
224
|
]
|
190
225
|
)
|
191
|
-
search.result.
|
226
|
+
expect(search.result).to be_an ActiveRecord::Relation
|
192
227
|
where = search.result.where_values.first
|
193
|
-
where.to_sql.
|
194
|
-
where.to_sql.
|
195
|
-
where.to_sql.
|
228
|
+
expect(where.to_sql).to match /#{children_people_name_field} = 'Ernie'/
|
229
|
+
expect(where.to_sql).to match /#{people_name_field} = 'Ernie'/
|
230
|
+
expect(where.to_sql).to match /#{quote_table_name("children_people_2")
|
196
231
|
}.#{quote_column_name("name")} = 'Ernie'/
|
197
232
|
end
|
198
233
|
|
199
234
|
it 'evaluates arrays of groupings' do
|
200
235
|
search = Search.new(Person,
|
201
|
-
g
|
202
|
-
{ m
|
203
|
-
{ m
|
236
|
+
:g => [
|
237
|
+
{ :m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie' },
|
238
|
+
{ :m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert' }
|
204
239
|
]
|
205
240
|
)
|
206
|
-
search.result.
|
241
|
+
expect(search.result).to be_an ActiveRecord::Relation
|
207
242
|
where = search.result.where_values.first
|
208
243
|
sql = where.to_sql
|
209
244
|
first, second = sql.split(/ AND /)
|
210
|
-
first.
|
211
|
-
first.
|
212
|
-
second.
|
213
|
-
second.
|
245
|
+
expect(first).to match /#{people_name_field} = 'Ernie'/
|
246
|
+
expect(first).to match /#{children_people_name_field} = 'Ernie'/
|
247
|
+
expect(second).to match /#{people_name_field} = 'Bert'/
|
248
|
+
expect(second).to match /#{children_people_name_field} = 'Bert'/
|
214
249
|
end
|
215
250
|
|
216
251
|
it 'returns distinct records when passed :distinct => true' do
|
@@ -227,12 +262,12 @@ module Ransack
|
|
227
262
|
else
|
228
263
|
all_or_load, uniq_or_distinct = :load, :distinct
|
229
264
|
end
|
230
|
-
search.result.send(all_or_load).
|
231
|
-
|
232
|
-
search.result(:distinct => true).
|
233
|
-
|
234
|
-
search.result.send(all_or_load).send(uniq_or_distinct)
|
235
|
-
|
265
|
+
expect(search.result.send(all_or_load).size)
|
266
|
+
.to eq(9000)
|
267
|
+
expect(search.result(:distinct => true).size)
|
268
|
+
.to eq(10)
|
269
|
+
expect(search.result.send(all_or_load).send(uniq_or_distinct))
|
270
|
+
.to eq search.result(:distinct => true).send(all_or_load)
|
236
271
|
end
|
237
272
|
end
|
238
273
|
|
@@ -243,109 +278,109 @@ module Ransack
|
|
243
278
|
|
244
279
|
it 'creates sorts based on a single attribute/direction' do
|
245
280
|
@s.sorts = 'id desc'
|
246
|
-
@s.sorts.
|
281
|
+
expect(@s.sorts.size).to eq(1)
|
247
282
|
sort = @s.sorts.first
|
248
|
-
sort.
|
249
|
-
sort.name.
|
250
|
-
sort.dir.
|
283
|
+
expect(sort).to be_a Nodes::Sort
|
284
|
+
expect(sort.name).to eq 'id'
|
285
|
+
expect(sort.dir).to eq 'desc'
|
251
286
|
end
|
252
287
|
|
253
288
|
it 'creates sorts based on a single attribute and uppercase direction' do
|
254
289
|
@s.sorts = 'id DESC'
|
255
|
-
@s.sorts.
|
290
|
+
expect(@s.sorts.size).to eq(1)
|
256
291
|
sort = @s.sorts.first
|
257
|
-
sort.
|
258
|
-
sort.name.
|
259
|
-
sort.dir.
|
292
|
+
expect(sort).to be_a Nodes::Sort
|
293
|
+
expect(sort.name).to eq 'id'
|
294
|
+
expect(sort.dir).to eq 'desc'
|
260
295
|
end
|
261
296
|
|
262
297
|
it 'creates sorts based on a single attribute and without direction' do
|
263
298
|
@s.sorts = 'id'
|
264
|
-
@s.sorts.
|
299
|
+
expect(@s.sorts.size).to eq(1)
|
265
300
|
sort = @s.sorts.first
|
266
|
-
sort.
|
267
|
-
sort.name.
|
268
|
-
sort.dir.
|
301
|
+
expect(sort).to be_a Nodes::Sort
|
302
|
+
expect(sort.name).to eq 'id'
|
303
|
+
expect(sort.dir).to eq 'asc'
|
269
304
|
end
|
270
305
|
|
271
306
|
it 'creates sorts based on multiple attributes/directions in array format' do
|
272
|
-
@s.sorts = ['id desc', { name
|
273
|
-
@s.sorts.
|
307
|
+
@s.sorts = ['id desc', { :name => 'name', :dir => 'asc' }]
|
308
|
+
expect(@s.sorts.size).to eq(2)
|
274
309
|
sort1, sort2 = @s.sorts
|
275
|
-
sort1.
|
276
|
-
sort1.name.
|
277
|
-
sort1.dir.
|
278
|
-
sort2.
|
279
|
-
sort2.name.
|
280
|
-
sort2.dir.
|
310
|
+
expect(sort1).to be_a Nodes::Sort
|
311
|
+
expect(sort1.name).to eq 'id'
|
312
|
+
expect(sort1.dir).to eq 'desc'
|
313
|
+
expect(sort2).to be_a Nodes::Sort
|
314
|
+
expect(sort2.name).to eq 'name'
|
315
|
+
expect(sort2.dir).to eq 'asc'
|
281
316
|
end
|
282
317
|
|
283
318
|
it 'creates sorts based on multiple attributes and uppercase directions in array format' do
|
284
|
-
@s.sorts = ['id DESC', { name
|
285
|
-
@s.sorts.
|
319
|
+
@s.sorts = ['id DESC', { :name => 'name', :dir => 'ASC' }]
|
320
|
+
expect(@s.sorts.size).to eq(2)
|
286
321
|
sort1, sort2 = @s.sorts
|
287
|
-
sort1.
|
288
|
-
sort1.name.
|
289
|
-
sort1.dir.
|
290
|
-
sort2.
|
291
|
-
sort2.name.
|
292
|
-
sort2.dir.
|
322
|
+
expect(sort1).to be_a Nodes::Sort
|
323
|
+
expect(sort1.name).to eq 'id'
|
324
|
+
expect(sort1.dir).to eq 'desc'
|
325
|
+
expect(sort2).to be_a Nodes::Sort
|
326
|
+
expect(sort2.name).to eq 'name'
|
327
|
+
expect(sort2.dir).to eq 'asc'
|
293
328
|
end
|
294
329
|
|
295
330
|
it 'creates sorts based on multiple attributes and different directions in array format' do
|
296
331
|
@s.sorts = ['id DESC', { name: 'name', dir: nil }]
|
297
|
-
@s.sorts.
|
332
|
+
expect(@s.sorts.size).to eq(2)
|
298
333
|
sort1, sort2 = @s.sorts
|
299
|
-
sort1.
|
300
|
-
sort1.name.
|
301
|
-
sort1.dir.
|
302
|
-
sort2.
|
303
|
-
sort2.name.
|
304
|
-
sort2.dir.
|
334
|
+
expect(sort1).to be_a Nodes::Sort
|
335
|
+
expect(sort1.name).to eq 'id'
|
336
|
+
expect(sort1.dir).to eq 'desc'
|
337
|
+
expect(sort2).to be_a Nodes::Sort
|
338
|
+
expect(sort2.name).to eq 'name'
|
339
|
+
expect(sort2.dir).to eq 'asc'
|
305
340
|
end
|
306
341
|
|
307
342
|
it 'creates sorts based on multiple attributes/directions in hash format' do
|
308
343
|
@s.sorts = {
|
309
|
-
'0' => { name
|
310
|
-
'1' => { name
|
344
|
+
'0' => { :name => 'id', :dir => 'desc' },
|
345
|
+
'1' => { :name => 'name', :dir => 'asc' }
|
311
346
|
}
|
312
|
-
@s.sorts.
|
313
|
-
@s.sorts.
|
347
|
+
expect(@s.sorts.size).to eq(2)
|
348
|
+
expect(@s.sorts).to be_all { |s| Nodes::Sort === s }
|
314
349
|
id_sort = @s.sorts.detect { |s| s.name == 'id' }
|
315
350
|
name_sort = @s.sorts.detect { |s| s.name == 'name' }
|
316
|
-
id_sort.dir.
|
317
|
-
name_sort.dir.
|
351
|
+
expect(id_sort.dir).to eq 'desc'
|
352
|
+
expect(name_sort.dir).to eq 'asc'
|
318
353
|
end
|
319
354
|
|
320
355
|
it 'creates sorts based on multiple attributes and uppercase directions in hash format' do
|
321
356
|
@s.sorts = {
|
322
|
-
|
323
|
-
|
357
|
+
'0' => { :name => 'id', :dir => 'DESC' },
|
358
|
+
'1' => { :name => 'name', :dir => 'ASC' }
|
324
359
|
}
|
325
|
-
@s.sorts.
|
326
|
-
@s.sorts.
|
360
|
+
expect(@s.sorts.size).to eq(2)
|
361
|
+
expect(@s.sorts).to be_all { |s| Nodes::Sort === s }
|
327
362
|
id_sort = @s.sorts.detect { |s| s.name == 'id' }
|
328
363
|
name_sort = @s.sorts.detect { |s| s.name == 'name' }
|
329
|
-
id_sort.dir.
|
330
|
-
name_sort.dir.
|
364
|
+
expect(id_sort.dir).to eq 'desc'
|
365
|
+
expect(name_sort.dir).to eq 'asc'
|
331
366
|
end
|
332
367
|
|
333
368
|
it 'creates sorts based on multiple attributes and different directions in hash format' do
|
334
369
|
@s.sorts = {
|
335
|
-
|
336
|
-
|
370
|
+
'0' => { :name => 'id', :dir => 'DESC' },
|
371
|
+
'1' => { :name => 'name', :dir => nil }
|
337
372
|
}
|
338
|
-
@s.sorts.
|
339
|
-
@s.sorts.
|
373
|
+
expect(@s.sorts.size).to eq(2)
|
374
|
+
expect(@s.sorts).to be_all { |s| Nodes::Sort === s }
|
340
375
|
id_sort = @s.sorts.detect { |s| s.name == 'id' }
|
341
376
|
name_sort = @s.sorts.detect { |s| s.name == 'name' }
|
342
|
-
id_sort.dir.
|
343
|
-
name_sort.dir.
|
377
|
+
expect(id_sort.dir).to eq 'desc'
|
378
|
+
expect(name_sort.dir).to eq 'asc'
|
344
379
|
end
|
345
380
|
|
346
381
|
it 'overrides existing sort' do
|
347
382
|
@s.sorts = 'id asc'
|
348
|
-
@s.result.first.id.
|
383
|
+
expect(@s.result.first.id).to eq 1
|
349
384
|
end
|
350
385
|
end
|
351
386
|
|
@@ -360,14 +395,14 @@ module Ransack
|
|
360
395
|
|
361
396
|
it 'sets condition attributes when sent valid attributes' do
|
362
397
|
@s.name_eq = 'Ernie'
|
363
|
-
@s.name_eq.
|
398
|
+
expect(@s.name_eq).to eq 'Ernie'
|
364
399
|
end
|
365
400
|
|
366
401
|
it 'allows chaining to access nested conditions' do
|
367
402
|
@s.groupings = [
|
368
|
-
{ m
|
403
|
+
{ :m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie' }
|
369
404
|
]
|
370
|
-
@s.groupings.first.children_name_eq.
|
405
|
+
expect(@s.groupings.first.children_name_eq).to eq 'Ernie'
|
371
406
|
end
|
372
407
|
end
|
373
408
|
end
|