restful_query 0.3.3 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +6 -0
- data/lib/restful_query.rb +1 -1
- data/lib/restful_query/parser.rb +25 -23
- data/lib/restful_query/sort.rb +41 -21
- data/restful_query.gemspec +3 -4
- data/test/test_restful_query_parser.rb +61 -46
- data/test/test_restful_query_sort.rb +40 -13
- metadata +45 -70
data/History.txt
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
== 0.3.4 2011-08-15
|
2
|
+
|
3
|
+
* Added support for extra options to sort. Specifically this allows you to do NULLS FIRST/LAST
|
4
|
+
* You can supply :sort_options => to the restful query parser that will get added to all sorts
|
5
|
+
* Changed single_sort => true to the default
|
6
|
+
|
1
7
|
== 0.3.3 2011-05-15
|
2
8
|
|
3
9
|
* Added 'restful_query/rails' for bundler requires
|
data/lib/restful_query.rb
CHANGED
data/lib/restful_query/parser.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
module RestfulQuery
|
2
2
|
class Parser
|
3
|
-
attr_reader :query, :exclude_columns, :map_columns, :integer_columns, :options
|
3
|
+
attr_reader :query, :exclude_columns, :map_columns, :integer_columns, :options, :default_sort_options
|
4
4
|
|
5
5
|
def initialize(query, options = {})
|
6
6
|
@options = options || {}
|
7
7
|
@exclude_columns = columns_from_options(:exclude, options)
|
8
8
|
@integer_columns = columns_from_options(:integer, options)
|
9
9
|
@map_columns = options[:map_columns] || {}
|
10
|
-
@
|
11
|
-
@
|
10
|
+
@single_sort = options[:single_sort] || true
|
11
|
+
@default_sort_options = options[:sort_options] || {}
|
12
12
|
@query = (query || {}).dup
|
13
|
+
@query['_sort'] ||= options[:default_sort] if options[:default_sort]
|
13
14
|
@default_join = @query.delete(:join) || :and
|
14
15
|
extract_sorts_from_conditions
|
15
16
|
map_conditions
|
@@ -18,7 +19,7 @@ module RestfulQuery
|
|
18
19
|
def conditions
|
19
20
|
conditions_hash.values.flatten
|
20
21
|
end
|
21
|
-
|
22
|
+
|
22
23
|
def has_conditions?
|
23
24
|
!conditions.empty?
|
24
25
|
end
|
@@ -32,46 +33,46 @@ module RestfulQuery
|
|
32
33
|
join_string = (join == :or) ? ' OR ' : ' AND '
|
33
34
|
conditions_string = []
|
34
35
|
conditions_values = []
|
35
|
-
conditions.each do |c|
|
36
|
+
conditions.each do |c|
|
36
37
|
ca = c.to_condition_array
|
37
38
|
conditions_string << ca[0]
|
38
39
|
conditions_values << ca[1]
|
39
40
|
end
|
40
41
|
conditions_values.unshift(conditions_string.join(join_string))
|
41
42
|
end
|
42
|
-
|
43
|
+
|
43
44
|
def to_query_hash
|
44
45
|
hash = @query
|
45
46
|
hash['_sort'] = sorts.collect {|s| s.to_s } unless sorts.empty?
|
46
47
|
hash
|
47
48
|
end
|
48
|
-
|
49
|
+
|
49
50
|
def sort_sql
|
50
51
|
@sorts.collect {|s| s.to_sql }.join(', ')
|
51
52
|
end
|
52
|
-
|
53
|
+
|
53
54
|
def has_sort?
|
54
55
|
!sorts.empty?
|
55
56
|
end
|
56
|
-
|
57
|
+
|
57
58
|
def sorts
|
58
59
|
@sorts ||= []
|
59
60
|
end
|
60
|
-
|
61
|
+
|
61
62
|
def sorted_columns
|
62
63
|
sorts.collect {|s| s.column }
|
63
64
|
end
|
64
|
-
|
65
|
+
|
65
66
|
def sorted_by?(column_name)
|
66
67
|
column = map_column(column_name)
|
67
68
|
sorted_columns.include?(column.to_s)
|
68
69
|
end
|
69
|
-
|
70
|
+
|
70
71
|
def sort(column_name)
|
71
72
|
column = map_column(column_name)
|
72
73
|
sorts.detect {|s| s && s.column == column }
|
73
74
|
end
|
74
|
-
|
75
|
+
|
75
76
|
def set_sort(column_name, direction)
|
76
77
|
column = map_column(column_name)
|
77
78
|
if new_sort = self.sort(column_name)
|
@@ -86,7 +87,7 @@ module RestfulQuery
|
|
86
87
|
end
|
87
88
|
new_sort
|
88
89
|
end
|
89
|
-
|
90
|
+
|
90
91
|
def clear_default_sort!
|
91
92
|
@sorts.reject! {|s| s == @default_sort.first }
|
92
93
|
end
|
@@ -108,7 +109,7 @@ module RestfulQuery
|
|
108
109
|
[]
|
109
110
|
end
|
110
111
|
end
|
111
|
-
|
112
|
+
|
112
113
|
def extract_sorts_from_conditions
|
113
114
|
@sorts = sorts_from_hash(@query.delete('_sort'))
|
114
115
|
@sorts = @default_sort if @sorts.empty?
|
@@ -142,25 +143,26 @@ module RestfulQuery
|
|
142
143
|
end
|
143
144
|
end
|
144
145
|
end
|
145
|
-
|
146
|
+
|
146
147
|
def sorts_from_hash(sorts)
|
147
148
|
sort_conditions = [sorts].flatten.compact
|
148
|
-
sort_conditions.collect do |c|
|
149
|
+
sort_conditions.collect do |c|
|
149
150
|
s = Sort.parse(c)
|
150
151
|
s.column = map_column(s.column)
|
152
|
+
s.options = default_sort_options
|
151
153
|
s
|
152
154
|
end
|
153
|
-
end
|
154
|
-
|
155
|
+
end
|
156
|
+
|
155
157
|
def columns_from_options(column_type, options)
|
156
158
|
option = "#{column_type}_columns".to_sym
|
157
159
|
options[option] ? [options.delete(option)].flatten.collect {|c| c.to_s } : []
|
158
160
|
end
|
159
|
-
|
161
|
+
|
160
162
|
def map_column(column_name)
|
161
163
|
map_columns[column_name.to_s] || column_name.to_s
|
162
164
|
end
|
163
|
-
|
164
|
-
|
165
|
+
|
166
|
+
|
165
167
|
end
|
166
|
-
end
|
168
|
+
end
|
data/lib/restful_query/sort.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
module RestfulQuery
|
2
2
|
class InvalidDirection < Error; end
|
3
|
-
|
3
|
+
|
4
4
|
class Sort
|
5
5
|
include Comparable
|
6
|
-
|
7
|
-
attr_reader :column, :direction
|
8
|
-
|
6
|
+
|
7
|
+
attr_reader :column, :direction, :options
|
8
|
+
|
9
9
|
DIRECTIONS = {
|
10
10
|
'up' => 'ASC',
|
11
11
|
'asc' => 'ASC',
|
@@ -14,37 +14,51 @@ module RestfulQuery
|
|
14
14
|
'desc' => 'DESC',
|
15
15
|
'DESC' => 'DESC'
|
16
16
|
}.freeze
|
17
|
-
|
18
|
-
|
19
|
-
def initialize(column, direction)
|
17
|
+
|
18
|
+
|
19
|
+
def initialize(column, direction, options = {})
|
20
20
|
self.column = column
|
21
21
|
self.direction = direction
|
22
|
+
self.options = options
|
22
23
|
end
|
23
|
-
|
24
|
+
|
24
25
|
def self.parse(sort_string, split_on = /\-|\ /)
|
25
26
|
return unless sort_string
|
26
|
-
column, direction = sort_string.split(split_on)
|
27
|
-
new(column, direction)
|
27
|
+
column, direction, options = sort_string.split(split_on, 3)
|
28
|
+
new(column, direction, options)
|
28
29
|
end
|
29
|
-
|
30
|
+
|
30
31
|
def column=(column)
|
31
32
|
@column = column.to_s
|
32
33
|
end
|
33
|
-
|
34
|
+
|
34
35
|
def direction=(direction)
|
35
36
|
@direction = DIRECTIONS[direction.to_s]
|
36
37
|
raise(InvalidDirection, "'#{direction}' is not a valid order direction") unless @direction
|
37
38
|
end
|
38
|
-
|
39
|
+
|
40
|
+
def options=(options)
|
41
|
+
@options = if options.is_a?(String)
|
42
|
+
opts = {}
|
43
|
+
options.split(/ /).each_slice(2) do |k|
|
44
|
+
k.map! {|v| v.to_s.downcase.to_sym }
|
45
|
+
opts[k[0]] = k[1]
|
46
|
+
end
|
47
|
+
opts
|
48
|
+
else
|
49
|
+
options || {}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
39
53
|
def reverse_direction
|
40
54
|
direction == 'ASC' ? 'DESC' : 'ASC'
|
41
55
|
end
|
42
|
-
|
56
|
+
|
43
57
|
def ==(other)
|
44
58
|
return false unless other.is_a?(Sort)
|
45
59
|
column == other.column && direction == other.direction
|
46
60
|
end
|
47
|
-
|
61
|
+
|
48
62
|
# Makes a roundabout for directions nil -> desc -> asc -> nil
|
49
63
|
def self.next_direction(current_direction)
|
50
64
|
case current_direction.to_s.downcase
|
@@ -56,17 +70,23 @@ module RestfulQuery
|
|
56
70
|
'desc'
|
57
71
|
end
|
58
72
|
end
|
59
|
-
|
73
|
+
|
60
74
|
def next_direction
|
61
75
|
self.class.next_direction(direction)
|
62
76
|
end
|
63
|
-
|
77
|
+
|
64
78
|
def to_s(join = '-')
|
65
|
-
"#{column}#{join}#{direction.downcase}"
|
79
|
+
s = "#{column}#{join}#{direction.downcase}"
|
80
|
+
s << " #{options.inspect}" unless options.empty?
|
81
|
+
s
|
66
82
|
end
|
67
|
-
|
83
|
+
|
68
84
|
def to_sql
|
69
|
-
"#{column} #{direction}"
|
85
|
+
sql = "#{column} #{direction}"
|
86
|
+
unless options.empty?
|
87
|
+
sql << ' ' << options.to_a.flatten.collect {|k| k.to_s.upcase }.join(' ')
|
88
|
+
end
|
89
|
+
sql
|
70
90
|
end
|
71
91
|
end
|
72
|
-
end
|
92
|
+
end
|
data/restful_query.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{restful_query}
|
8
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.4"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Aaron Quint"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-08-15}
|
13
13
|
s.description = %q{RestfulQuery provides a simple interface in front of a complex parser to parse specially formatted query hashes into complex SQL queries. It includes ActiveRecord and Sequel extensions.}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"LICENSE",
|
@@ -39,11 +39,10 @@ Gem::Specification.new do |s|
|
|
39
39
|
]
|
40
40
|
s.require_paths = ["lib"]
|
41
41
|
s.rubyforge_project = %q{quirkey}
|
42
|
-
s.rubygems_version = %q{1.
|
42
|
+
s.rubygems_version = %q{1.6.2}
|
43
43
|
s.summary = %q{Simple ActiveRecord and Sequel queries from a RESTful and safe interface}
|
44
44
|
|
45
45
|
if s.respond_to? :specification_version then
|
46
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
47
46
|
s.specification_version = 3
|
48
47
|
|
49
48
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
@@ -100,7 +100,7 @@ class RestfulQueryParserTest < Test::Unit::TestCase
|
|
100
100
|
assert_not_equal Chronic.parse('1 day ago').to_s, @parser.conditions_for(:updated_at).first.value.to_s
|
101
101
|
end
|
102
102
|
end
|
103
|
-
|
103
|
+
|
104
104
|
context "with blank values" do
|
105
105
|
setup do
|
106
106
|
new_parser_from_hash({'isblank' => ''})
|
@@ -115,7 +115,7 @@ class RestfulQueryParserTest < Test::Unit::TestCase
|
|
115
115
|
assert_nil @parser.conditions_for('isblank')
|
116
116
|
end
|
117
117
|
end
|
118
|
-
|
118
|
+
|
119
119
|
context "with map_columns" do
|
120
120
|
setup do
|
121
121
|
new_parser_from_hash({'section' => 4, '_sort' => 'category-up'}, {:map_columns => {
|
@@ -123,22 +123,22 @@ class RestfulQueryParserTest < Test::Unit::TestCase
|
|
123
123
|
'category' => 'category_id'
|
124
124
|
}})
|
125
125
|
end
|
126
|
-
|
126
|
+
|
127
127
|
should "return parser object" do
|
128
128
|
assert @parser.is_a?(RestfulQuery::Parser)
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
should "set the map_columns attribute" do
|
132
132
|
assert @parser.map_columns.is_a?(Hash)
|
133
133
|
end
|
134
|
-
|
134
|
+
|
135
135
|
should "map condition column" do
|
136
136
|
assert @parser.conditions_for('section')
|
137
137
|
assert_equal 'section_id', @parser.conditions_for('section').first.column
|
138
138
|
end
|
139
|
-
|
139
|
+
|
140
140
|
should "map sort column" do
|
141
|
-
@sort = @parser.sorts.first
|
141
|
+
@sort = @parser.sorts.first
|
142
142
|
assert @sort.is_a?(RestfulQuery::Sort)
|
143
143
|
assert_equal 'ASC', @sort.direction
|
144
144
|
assert_equal 'category_id', @sort.column
|
@@ -155,7 +155,7 @@ class RestfulQueryParserTest < Test::Unit::TestCase
|
|
155
155
|
end
|
156
156
|
|
157
157
|
should "parse sort string" do
|
158
|
-
@sort = @parser.sorts.first
|
158
|
+
@sort = @parser.sorts.first
|
159
159
|
assert @sort.is_a?(RestfulQuery::Sort)
|
160
160
|
assert_equal 'ASC', @sort.direction
|
161
161
|
assert_equal 'created_at', @sort.column
|
@@ -184,26 +184,41 @@ class RestfulQueryParserTest < Test::Unit::TestCase
|
|
184
184
|
assert sort.is_a?(RestfulQuery::Sort)
|
185
185
|
end
|
186
186
|
end
|
187
|
+
end
|
187
188
|
|
189
|
+
context "with sort options" do
|
190
|
+
setup do
|
191
|
+
new_parser_from_hash({'_sort' => ['created_at-up']}, :sort_options => {:nulls => :first})
|
192
|
+
end
|
193
|
+
|
194
|
+
should "return parser object" do
|
195
|
+
assert @parser.is_a?(RestfulQuery::Parser)
|
196
|
+
end
|
197
|
+
|
198
|
+
should "add sorts to sorts" do
|
199
|
+
assert @parser.sorts
|
200
|
+
assert_equal 1, @parser.sorts.length
|
201
|
+
assert_equal 'created_at ASC NULLS FIRST', @parser.sort_sql
|
202
|
+
end
|
188
203
|
end
|
189
|
-
|
204
|
+
|
190
205
|
context "with a default_sort" do
|
191
206
|
context "with no sorts defined in the query hash" do
|
192
207
|
setup do
|
193
208
|
new_parser_from_hash({}, {:default_sort => 'created_at DESC'})
|
194
209
|
end
|
195
|
-
|
210
|
+
|
196
211
|
should "return parser object" do
|
197
212
|
assert @parser.is_a?(RestfulQuery::Parser)
|
198
213
|
end
|
199
|
-
|
214
|
+
|
200
215
|
should "have default sort in sorts" do
|
201
216
|
assert @parser.sorts
|
202
217
|
assert_equal 1, @parser.sorts.length
|
203
218
|
assert_equal 'created_at DESC', @parser.sort_sql
|
204
219
|
end
|
205
220
|
end
|
206
|
-
|
221
|
+
|
207
222
|
context "with sorts defined in the query hash" do
|
208
223
|
setup do
|
209
224
|
new_parser_from_hash({'_sort' => 'created_at-up'})
|
@@ -212,7 +227,7 @@ class RestfulQueryParserTest < Test::Unit::TestCase
|
|
212
227
|
should "return parser object" do
|
213
228
|
assert @parser.is_a?(RestfulQuery::Parser)
|
214
229
|
end
|
215
|
-
|
230
|
+
|
216
231
|
should "have query hash sorts in sorts and not default sort" do
|
217
232
|
assert @parser.sorts
|
218
233
|
assert_equal 1, @parser.sorts.length
|
@@ -221,20 +236,20 @@ class RestfulQueryParserTest < Test::Unit::TestCase
|
|
221
236
|
end
|
222
237
|
end
|
223
238
|
end
|
224
|
-
|
239
|
+
|
225
240
|
context "from an array of conditions" do
|
226
241
|
setup do
|
227
242
|
@array_of_conditions = [
|
228
|
-
{'column' => 'created_at', 'operator' => 'gt', 'value' => '1 week ago'},
|
229
|
-
{'column' => 'created_at', 'operator' => 'lt', 'value' => '1 hour ago'},
|
230
|
-
{'column' => 'updated_at', 'operator' => 'lt', 'value' => '1 day ago'},
|
231
|
-
{'column' => 'title', 'operator' => 'eq', 'value' => 'Test'},
|
243
|
+
{'column' => 'created_at', 'operator' => 'gt', 'value' => '1 week ago'},
|
244
|
+
{'column' => 'created_at', 'operator' => 'lt', 'value' => '1 hour ago'},
|
245
|
+
{'column' => 'updated_at', 'operator' => 'lt', 'value' => '1 day ago'},
|
246
|
+
{'column' => 'title', 'operator' => 'eq', 'value' => 'Test'},
|
232
247
|
{'column' => 'other_time', 'operator' => 'gt', 'value' => 'oct 1'},
|
233
248
|
{'column' => 'name', 'value' => 'Aaron'}
|
234
249
|
]
|
235
250
|
@parser = RestfulQuery::Parser.new(:conditions => @array_of_conditions)
|
236
251
|
end
|
237
|
-
|
252
|
+
|
238
253
|
should "return parser object" do
|
239
254
|
assert @parser.is_a?(RestfulQuery::Parser)
|
240
255
|
end
|
@@ -250,7 +265,7 @@ class RestfulQueryParserTest < Test::Unit::TestCase
|
|
250
265
|
assert @parser.conditions_for(:name).first.is_a?(RestfulQuery::Condition)
|
251
266
|
assert_equal '=', @parser.conditions_for(:name).first.operator
|
252
267
|
end
|
253
|
-
|
268
|
+
|
254
269
|
end
|
255
270
|
|
256
271
|
context "a loaded parser" do
|
@@ -327,45 +342,45 @@ class RestfulQueryParserTest < Test::Unit::TestCase
|
|
327
342
|
assert_match(/(([a-z_]) (\<|\>|\=|\<\=|\>\=) \? OR)+/,@conditions[0])
|
328
343
|
end
|
329
344
|
end
|
330
|
-
|
345
|
+
|
331
346
|
context "to_query_hash" do
|
332
347
|
context "with no altering" do
|
333
348
|
setup do
|
334
349
|
@query_hash = @parser.to_query_hash
|
335
350
|
end
|
336
|
-
|
351
|
+
|
337
352
|
should "return hash" do
|
338
353
|
assert @query_hash.is_a?(Hash)
|
339
354
|
end
|
340
|
-
|
355
|
+
|
341
356
|
should "return initial query hash" do
|
342
357
|
assert_equal({'gt' => '1 week ago', 'lt' => '1 hour ago'}, @query_hash['created_at'])
|
343
358
|
end
|
344
359
|
end
|
345
|
-
|
360
|
+
|
346
361
|
context "with altered sorts" do
|
347
362
|
setup do
|
348
363
|
@parser.set_sort('title', 'up')
|
349
364
|
@parser.set_sort('created_at', 'down')
|
350
365
|
@query_hash = @parser.to_query_hash
|
351
366
|
end
|
352
|
-
|
367
|
+
|
353
368
|
should "include unaltered sort conditions" do
|
354
369
|
assert_equal({'gt' => '1 week ago', 'lt' => '1 hour ago'}, @query_hash['created_at'])
|
355
370
|
end
|
356
|
-
|
371
|
+
|
357
372
|
should "include altered sorts" do
|
358
373
|
assert_equal(['title-asc','created_at-desc'], @query_hash['_sort'])
|
359
374
|
end
|
360
375
|
end
|
361
376
|
end
|
362
|
-
|
377
|
+
|
363
378
|
context "sorts" do
|
364
379
|
setup do
|
365
380
|
new_parser_from_hash({'_sort' => ['title-down', 'updated_at-asc']})
|
366
|
-
@sorts = @parser.sorts
|
381
|
+
@sorts = @parser.sorts
|
367
382
|
end
|
368
|
-
|
383
|
+
|
369
384
|
should "return an array of sort objects" do
|
370
385
|
assert @sorts
|
371
386
|
assert_equal 2, @sorts.length
|
@@ -373,7 +388,7 @@ class RestfulQueryParserTest < Test::Unit::TestCase
|
|
373
388
|
assert sort.is_a?(RestfulQuery::Sort)
|
374
389
|
end
|
375
390
|
end
|
376
|
-
|
391
|
+
|
377
392
|
context "sorted_columns" do
|
378
393
|
should "return an array of columns" do
|
379
394
|
@sorted_columns = @parser.sorted_columns
|
@@ -381,73 +396,73 @@ class RestfulQueryParserTest < Test::Unit::TestCase
|
|
381
396
|
assert @sorted_columns.include?('title')
|
382
397
|
end
|
383
398
|
end
|
384
|
-
|
399
|
+
|
385
400
|
context "sorted_by?" do
|
386
401
|
should "return true if column is sorted" do
|
387
402
|
assert @parser.sorted_by?('title')
|
388
403
|
end
|
389
|
-
|
404
|
+
|
390
405
|
should "return false if column is not sorted" do
|
391
406
|
assert !@parser.sorted_by?('created_at')
|
392
407
|
end
|
393
408
|
end
|
394
|
-
|
409
|
+
|
395
410
|
context "sort()" do
|
396
411
|
should "return Sort object if column is sorted" do
|
397
412
|
sort = @parser.sort('title')
|
398
413
|
assert sort.is_a?(RestfulQuery::Sort)
|
399
414
|
assert_equal 'title', sort.column
|
400
415
|
end
|
401
|
-
|
416
|
+
|
402
417
|
should "return nil if col" do
|
403
418
|
assert_nil @parser.sort('created_at')
|
404
419
|
end
|
405
420
|
end
|
406
|
-
|
421
|
+
|
407
422
|
context "set_sort" do
|
408
|
-
context "with an existing sort" do
|
423
|
+
context "with an existing sort" do
|
409
424
|
setup do
|
410
425
|
@parser.set_sort('title','up')
|
411
426
|
end
|
412
|
-
|
427
|
+
|
413
428
|
should "not add new sort" do
|
414
429
|
assert_equal 2, @parser.sorts.length
|
415
430
|
end
|
416
|
-
|
431
|
+
|
417
432
|
should "update sort direction" do
|
418
433
|
assert_equal 'ASC', @parser.sort('title').direction
|
419
434
|
end
|
420
435
|
end
|
421
|
-
|
436
|
+
|
422
437
|
context "with direction: nil" do
|
423
438
|
setup do
|
424
439
|
@parser.set_sort('title', nil)
|
425
440
|
end
|
426
|
-
|
441
|
+
|
427
442
|
should "remove sort" do
|
428
443
|
assert_equal 1, @parser.sorts.length
|
429
444
|
assert !@parser.sorted_by?('title')
|
430
445
|
end
|
431
446
|
end
|
432
|
-
|
447
|
+
|
433
448
|
context "with a new sort" do
|
434
449
|
setup do
|
435
450
|
@parser.set_sort('name', 'down')
|
436
451
|
end
|
437
|
-
|
452
|
+
|
438
453
|
should "add sort to sorts" do
|
439
454
|
assert_equal 3, @parser.sorts.length
|
440
455
|
end
|
441
|
-
|
456
|
+
|
442
457
|
should "set sort direction" do
|
443
458
|
assert_equal 'DESC', @parser.sort('name').direction
|
444
459
|
end
|
445
460
|
end
|
446
|
-
|
461
|
+
|
447
462
|
end
|
448
|
-
|
463
|
+
|
449
464
|
end
|
450
|
-
|
465
|
+
|
451
466
|
|
452
467
|
context "sort_sql" do
|
453
468
|
should "join order with ," do
|
@@ -8,16 +8,34 @@ class RestfulQuerySortTest < Test::Unit::TestCase
|
|
8
8
|
setup do
|
9
9
|
@sort = RestfulQuery::Sort.new(:attribute, 'up')
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
should "save column name as string" do
|
13
13
|
assert_equal 'attribute', @sort.column
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
should "interpret direction" do
|
17
17
|
assert_equal 'ASC', @sort.direction
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
|
+
context "with extra options" do
|
22
|
+
setup do
|
23
|
+
@sort = RestfulQuery::Sort.new(:attribute, 'up', :nulls => :first)
|
24
|
+
end
|
25
|
+
|
26
|
+
should "save column name as string" do
|
27
|
+
assert_equal 'attribute', @sort.column
|
28
|
+
end
|
29
|
+
|
30
|
+
should "interpret direction" do
|
31
|
+
assert_equal 'ASC', @sort.direction
|
32
|
+
end
|
33
|
+
|
34
|
+
should "add nulls option" do
|
35
|
+
assert_equal :first, @sort.options[:nulls]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
21
39
|
context "with an invalid direction" do
|
22
40
|
should "raise error" do
|
23
41
|
assert_raise(RestfulQuery::InvalidDirection) do
|
@@ -25,28 +43,28 @@ class RestfulQuerySortTest < Test::Unit::TestCase
|
|
25
43
|
end
|
26
44
|
end
|
27
45
|
end
|
28
|
-
|
46
|
+
|
29
47
|
end
|
30
|
-
|
48
|
+
|
31
49
|
context "parse" do
|
32
50
|
context "with a query hash like condition" do
|
33
51
|
setup do
|
34
52
|
@sort = RestfulQuery::Sort.parse('long_name_attribute-down')
|
35
53
|
end
|
36
|
-
|
54
|
+
|
37
55
|
should "return sort object" do
|
38
56
|
assert @sort.is_a?(RestfulQuery::Sort)
|
39
57
|
end
|
40
|
-
|
58
|
+
|
41
59
|
should "set column and direction" do
|
42
60
|
assert_equal 'long_name_attribute', @sort.column
|
43
61
|
assert_equal 'DESC', @sort.direction
|
44
62
|
end
|
45
63
|
end
|
46
|
-
|
64
|
+
|
47
65
|
context "with a standard SQL like condition" do
|
48
66
|
setup do
|
49
|
-
@sort = RestfulQuery::Sort.parse('long_name_attribute DESC')
|
67
|
+
@sort = RestfulQuery::Sort.parse('long_name_attribute DESC NULLS LAST')
|
50
68
|
end
|
51
69
|
|
52
70
|
should "return sort object" do
|
@@ -57,16 +75,25 @@ class RestfulQuerySortTest < Test::Unit::TestCase
|
|
57
75
|
assert_equal 'long_name_attribute', @sort.column
|
58
76
|
assert_equal 'DESC', @sort.direction
|
59
77
|
end
|
78
|
+
|
79
|
+
should "set other options" do
|
80
|
+
assert_equal :last, @sort.options[:nulls]
|
81
|
+
end
|
60
82
|
end
|
61
83
|
end
|
62
|
-
|
84
|
+
|
63
85
|
context "to_sql" do
|
64
86
|
should "join the column and attribute" do
|
65
87
|
@sort = RestfulQuery::Sort.new(:attribute, 'down')
|
66
88
|
assert_equal 'attribute DESC', @sort.to_sql
|
67
89
|
end
|
90
|
+
|
91
|
+
should "parse null option" do
|
92
|
+
@sort = RestfulQuery::Sort.new(:attribute, 'down', :nulls => :last)
|
93
|
+
assert_equal 'attribute DESC NULLS LAST', @sort.to_sql
|
94
|
+
end
|
68
95
|
end
|
69
|
-
|
96
|
+
|
70
97
|
end
|
71
|
-
|
72
|
-
end
|
98
|
+
|
99
|
+
end
|
metadata
CHANGED
@@ -1,77 +1,60 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: restful_query
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 3
|
8
|
-
- 3
|
9
|
-
version: 0.3.3
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.4
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Aaron Quint
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
date: 2011-05-17 00:00:00 -07:00
|
12
|
+
date: 2011-08-15 00:00:00.000000000 -04:00
|
18
13
|
default_executable:
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
21
16
|
name: activesupport
|
22
|
-
|
23
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
17
|
+
requirement: &2152029040 !ruby/object:Gem::Requirement
|
24
18
|
none: false
|
25
|
-
requirements:
|
26
|
-
- -
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
segments:
|
29
|
-
- 2
|
30
|
-
- 2
|
31
|
-
- 0
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
32
22
|
version: 2.2.0
|
33
23
|
type: :runtime
|
34
|
-
version_requirements: *id001
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: chronic
|
37
24
|
prerelease: false
|
38
|
-
|
25
|
+
version_requirements: *2152029040
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: chronic
|
28
|
+
requirement: &2152028020 !ruby/object:Gem::Requirement
|
39
29
|
none: false
|
40
|
-
requirements:
|
41
|
-
- -
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
segments:
|
44
|
-
- 0
|
45
|
-
- 2
|
46
|
-
- 3
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
47
33
|
version: 0.2.3
|
48
34
|
type: :runtime
|
49
|
-
version_requirements: *id002
|
50
|
-
- !ruby/object:Gem::Dependency
|
51
|
-
name: Shoulda
|
52
35
|
prerelease: false
|
53
|
-
|
36
|
+
version_requirements: *2152028020
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: Shoulda
|
39
|
+
requirement: &2152027080 !ruby/object:Gem::Requirement
|
54
40
|
none: false
|
55
|
-
requirements:
|
56
|
-
- -
|
57
|
-
- !ruby/object:Gem::Version
|
58
|
-
segments:
|
59
|
-
- 1
|
60
|
-
- 2
|
61
|
-
- 0
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
62
44
|
version: 1.2.0
|
63
45
|
type: :development
|
64
|
-
|
65
|
-
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *2152027080
|
48
|
+
description: RestfulQuery provides a simple interface in front of a complex parser
|
49
|
+
to parse specially formatted query hashes into complex SQL queries. It includes
|
50
|
+
ActiveRecord and Sequel extensions.
|
66
51
|
email:
|
67
52
|
executables: []
|
68
|
-
|
69
53
|
extensions: []
|
70
|
-
|
71
|
-
extra_rdoc_files:
|
54
|
+
extra_rdoc_files:
|
72
55
|
- LICENSE
|
73
56
|
- README.rdoc
|
74
|
-
files:
|
57
|
+
files:
|
75
58
|
- History.txt
|
76
59
|
- LICENSE
|
77
60
|
- README.rdoc
|
@@ -95,34 +78,26 @@ files:
|
|
95
78
|
has_rdoc: true
|
96
79
|
homepage:
|
97
80
|
licenses: []
|
98
|
-
|
99
81
|
post_install_message:
|
100
82
|
rdoc_options: []
|
101
|
-
|
102
|
-
require_paths:
|
83
|
+
require_paths:
|
103
84
|
- lib
|
104
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
86
|
none: false
|
106
|
-
requirements:
|
107
|
-
- -
|
108
|
-
- !ruby/object:Gem::Version
|
109
|
-
|
110
|
-
|
111
|
-
version: "0"
|
112
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
92
|
none: false
|
114
|
-
requirements:
|
115
|
-
- -
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
|
118
|
-
- 0
|
119
|
-
version: "0"
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
120
97
|
requirements: []
|
121
|
-
|
122
98
|
rubyforge_project: quirkey
|
123
|
-
rubygems_version: 1.
|
99
|
+
rubygems_version: 1.6.2
|
124
100
|
signing_key:
|
125
101
|
specification_version: 3
|
126
102
|
summary: Simple ActiveRecord and Sequel queries from a RESTful and safe interface
|
127
103
|
test_files: []
|
128
|
-
|