ransack 1.2.3 → 1.3.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 +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
|