graphiti 1.0.alpha.5 → 1.0.alpha.6
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/lib/generators/graphiti/api_test_generator.rb +71 -0
- data/lib/generators/graphiti/generator_mixin.rb +45 -0
- data/lib/generators/graphiti/resource_generator.rb +99 -0
- data/lib/generators/graphiti/resource_test_generator.rb +57 -0
- data/lib/generators/{jsonapi → graphiti}/templates/application_resource.rb.erb +0 -0
- data/lib/generators/{jsonapi → graphiti}/templates/controller.rb.erb +0 -0
- data/lib/generators/{jsonapi → graphiti}/templates/create_request_spec.rb.erb +3 -3
- data/lib/generators/{jsonapi → graphiti}/templates/destroy_request_spec.rb.erb +5 -5
- data/lib/generators/graphiti/templates/index_request_spec.rb.erb +22 -0
- data/lib/generators/{jsonapi → graphiti}/templates/resource.rb.erb +0 -0
- data/lib/generators/{jsonapi → graphiti}/templates/resource_reads_spec.rb.erb +12 -12
- data/lib/generators/{jsonapi → graphiti}/templates/resource_writes_spec.rb.erb +12 -12
- data/lib/generators/graphiti/templates/show_request_spec.rb.erb +21 -0
- data/lib/generators/{jsonapi → graphiti}/templates/update_request_spec.rb.erb +5 -5
- data/lib/graphiti.rb +0 -6
- data/lib/graphiti/adapters/abstract.rb +0 -1
- data/lib/graphiti/adapters/active_record/inferrence.rb +8 -1
- data/lib/graphiti/base.rb +1 -1
- data/lib/graphiti/errors.rb +70 -5
- data/lib/graphiti/jsonapi_serializable_ext.rb +18 -6
- data/lib/graphiti/query.rb +28 -17
- data/lib/graphiti/resource.rb +14 -0
- data/lib/graphiti/resource/configuration.rb +22 -3
- data/lib/graphiti/resource/dsl.rb +17 -2
- data/lib/graphiti/resource/interface.rb +10 -8
- data/lib/graphiti/resource/links.rb +6 -3
- data/lib/graphiti/runner.rb +2 -1
- data/lib/graphiti/schema.rb +33 -5
- data/lib/graphiti/schema_diff.rb +71 -1
- data/lib/graphiti/scope.rb +4 -9
- data/lib/graphiti/scoping/base.rb +2 -2
- data/lib/graphiti/scoping/filter.rb +5 -0
- data/lib/graphiti/scoping/filterable.rb +21 -6
- data/lib/graphiti/scoping/paginate.rb +4 -4
- data/lib/graphiti/scoping/sort.rb +26 -5
- data/lib/graphiti/sideload.rb +13 -22
- data/lib/graphiti/sideload/belongs_to.rb +11 -2
- data/lib/graphiti/sideload/has_many.rb +1 -1
- data/lib/graphiti/sideload/polymorphic_belongs_to.rb +2 -3
- data/lib/graphiti/types.rb +1 -1
- data/lib/graphiti/util/class.rb +5 -2
- data/lib/graphiti/util/persistence.rb +1 -1
- data/lib/graphiti/version.rb +1 -1
- metadata +16 -13
- data/lib/generators/jsonapi/resource_generator.rb +0 -169
- data/lib/generators/jsonapi/templates/index_request_spec.rb.erb +0 -22
- data/lib/generators/jsonapi/templates/show_request_spec.rb.erb +0 -21
@@ -5,38 +5,40 @@ module Graphiti
|
|
5
5
|
|
6
6
|
class_methods do
|
7
7
|
def all(params = {}, base_scope = nil)
|
8
|
-
validate!
|
8
|
+
validate!(params)
|
9
9
|
_all(params, {}, base_scope)
|
10
10
|
end
|
11
11
|
|
12
12
|
# @api private
|
13
13
|
def _all(params, opts, base_scope)
|
14
|
-
runner = Runner.new(self, params)
|
14
|
+
runner = Runner.new(self, params, opts.delete(:query))
|
15
15
|
runner.proxy(base_scope, opts)
|
16
16
|
end
|
17
17
|
|
18
|
-
def find(params, base_scope = nil)
|
19
|
-
validate!
|
18
|
+
def find(params = {}, base_scope = nil)
|
19
|
+
validate!(params)
|
20
20
|
id = params[:data].try(:[], :id) || params.delete(:id)
|
21
21
|
params[:filter] ||= {}
|
22
|
-
params[:filter].merge!(id: id)
|
22
|
+
params[:filter].merge!(id: id) if id
|
23
23
|
|
24
24
|
runner = Runner.new(self, params)
|
25
25
|
runner.proxy(base_scope, single: true, raise_on_missing: true)
|
26
26
|
end
|
27
27
|
|
28
28
|
def build(params, base_scope = nil)
|
29
|
-
validate!
|
29
|
+
validate!(params)
|
30
30
|
runner = Runner.new(self, params)
|
31
31
|
runner.proxy(base_scope, single: true, raise_on_missing: true)
|
32
32
|
end
|
33
33
|
|
34
34
|
private
|
35
35
|
|
36
|
-
def validate!
|
36
|
+
def validate!(params)
|
37
|
+
return unless validate_endpoints?
|
38
|
+
|
37
39
|
if context && context.respond_to?(:request)
|
38
40
|
path = context.request.env['PATH_INFO']
|
39
|
-
unless allow_request?(path, context_namespace)
|
41
|
+
unless allow_request?(path, params, context_namespace)
|
40
42
|
raise Errors::InvalidEndpoint.new(self, path, context_namespace)
|
41
43
|
end
|
42
44
|
end
|
@@ -19,9 +19,11 @@ module Graphiti
|
|
19
19
|
:base_url,
|
20
20
|
:endpoint_namespace,
|
21
21
|
:secondary_endpoints,
|
22
|
-
:autolink
|
22
|
+
:autolink,
|
23
|
+
:validate_endpoints
|
23
24
|
self.secondary_endpoints = []
|
24
25
|
self.autolink = true
|
26
|
+
self.validate_endpoints = true
|
25
27
|
|
26
28
|
class << self
|
27
29
|
prepend Overrides
|
@@ -66,9 +68,10 @@ module Graphiti
|
|
66
68
|
([endpoint] + secondary_endpoints).compact
|
67
69
|
end
|
68
70
|
|
69
|
-
def allow_request?(path, action)
|
71
|
+
def allow_request?(path, params, action)
|
70
72
|
endpoints.any? do |e|
|
71
|
-
|
73
|
+
has_id = params[:id] || params[:data].try(:[], :id)
|
74
|
+
if [:update, :show, :destroy].include?(context_namespace) && has_id
|
72
75
|
path = path.split('/')
|
73
76
|
path.pop
|
74
77
|
path = path.join('/')
|
data/lib/graphiti/runner.rb
CHANGED
@@ -3,9 +3,10 @@ module Graphiti
|
|
3
3
|
attr_reader :params
|
4
4
|
include Graphiti::Base
|
5
5
|
|
6
|
-
def initialize(resource_class, params)
|
6
|
+
def initialize(resource_class, params, query = nil)
|
7
7
|
@resource_class = resource_class
|
8
8
|
@params = params
|
9
|
+
@query = query
|
9
10
|
end
|
10
11
|
|
11
12
|
def jsonapi_resource
|
data/lib/graphiti/schema.rb
CHANGED
@@ -84,10 +84,19 @@ module Graphiti
|
|
84
84
|
type: r.type.to_s,
|
85
85
|
attributes: attributes(r),
|
86
86
|
extra_attributes: extra_attributes(r),
|
87
|
+
sorts: sorts(r),
|
87
88
|
filters: filters(r),
|
88
89
|
relationships: relationships(r)
|
89
90
|
}
|
90
91
|
|
92
|
+
if r.default_sort
|
93
|
+
config[:default_sort] = r.default_sort
|
94
|
+
end
|
95
|
+
|
96
|
+
if r.default_page_size
|
97
|
+
config[:default_page_size] = r.default_page_size
|
98
|
+
end
|
99
|
+
|
91
100
|
if r.polymorphic?
|
92
101
|
config.merge!(polymorphic: true, children: r.children.map(&:name))
|
93
102
|
end
|
@@ -99,12 +108,11 @@ module Graphiti
|
|
99
108
|
def attributes(resource)
|
100
109
|
{}.tap do |attrs|
|
101
110
|
resource.attributes.each_pair do |name, config|
|
102
|
-
if config.values_at(:readable, :writable
|
111
|
+
if config.values_at(:readable, :writable).any?
|
103
112
|
attrs[name] = {
|
104
113
|
type: config[:type].to_s,
|
105
114
|
readable: flag(config[:readable]),
|
106
|
-
writable: flag(config[:writable])
|
107
|
-
sortable: flag(config[:sortable])
|
115
|
+
writable: flag(config[:writable])
|
108
116
|
}
|
109
117
|
end
|
110
118
|
end
|
@@ -130,6 +138,20 @@ module Graphiti
|
|
130
138
|
end
|
131
139
|
end
|
132
140
|
|
141
|
+
def sorts(resource)
|
142
|
+
{}.tap do |s|
|
143
|
+
resource.sorts.each_pair do |name, sort|
|
144
|
+
config = {}
|
145
|
+
config[:only] = sort[:only] if sort[:only]
|
146
|
+
attr = resource.attributes[name]
|
147
|
+
if attr[:sortable].is_a?(Symbol)
|
148
|
+
config[:guard] = true
|
149
|
+
end
|
150
|
+
s[name] = config
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
133
155
|
def filters(resource)
|
134
156
|
{}.tap do |f|
|
135
157
|
resource.filters.each_pair do |name, filter|
|
@@ -137,9 +159,11 @@ module Graphiti
|
|
137
159
|
type: filter[:type].to_s,
|
138
160
|
operators: filter[:operators].keys.map(&:to_s)
|
139
161
|
}
|
162
|
+
|
140
163
|
config[:single] = true if filter[:single]
|
141
|
-
config[:allow] = filter[:allow] if filter[:allow]
|
142
|
-
config[:reject] = filter[:reject] if filter[:reject]
|
164
|
+
config[:allow] = filter[:allow].map(&:to_s) if filter[:allow]
|
165
|
+
config[:reject] = filter[:reject].map(&:to_s) if filter[:reject]
|
166
|
+
config[:dependencies] = filter[:dependencies].map(&:to_s) if filter[:dependencies]
|
143
167
|
|
144
168
|
attr = resource.attributes[name]
|
145
169
|
if attr[:filterable].is_a?(Symbol)
|
@@ -165,6 +189,10 @@ module Graphiti
|
|
165
189
|
schema[:resource] = config.resource.class.name
|
166
190
|
end
|
167
191
|
|
192
|
+
if config.single?
|
193
|
+
schema[:single] = true
|
194
|
+
end
|
195
|
+
|
168
196
|
r[name] = schema
|
169
197
|
end
|
170
198
|
end
|
data/lib/graphiti/schema_diff.rb
CHANGED
@@ -24,7 +24,9 @@ module Graphiti
|
|
24
24
|
new_resource = @new[:resources].find { |n| n[:name] == r[:name] }
|
25
25
|
compare_resource(r, new_resource) do
|
26
26
|
compare_attributes(r, new_resource)
|
27
|
+
compare_defaults(r, new_resource)
|
27
28
|
compare_extra_attributes(r, new_resource)
|
29
|
+
compare_sorts(r, new_resource)
|
28
30
|
compare_filters(r, new_resource)
|
29
31
|
compare_relationships(r, new_resource)
|
30
32
|
end
|
@@ -54,6 +56,36 @@ module Graphiti
|
|
54
56
|
end
|
55
57
|
end
|
56
58
|
|
59
|
+
def compare_defaults(old_resource, new_resource)
|
60
|
+
if new_resource[:default_sort] && !old_resource[:default_sort]
|
61
|
+
@errors << "#{old_resource[:name]}: default sort added."
|
62
|
+
end
|
63
|
+
|
64
|
+
if old_resource[:default_sort] && !new_resource[:default_sort]
|
65
|
+
@errors << "#{old_resource[:name]}: default sort removed."
|
66
|
+
end
|
67
|
+
|
68
|
+
if new_resource[:default_sort] && old_resource[:default_sort]
|
69
|
+
if new_resource[:default_sort] != old_resource[:default_sort]
|
70
|
+
@errors << "#{old_resource[:name]}: default sort changed from #{old_resource[:default_sort].inspect} to #{new_resource[:default_sort].inspect}."
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
if new_resource[:default_page_size] && !old_resource[:default_page_size]
|
75
|
+
@errors << "#{old_resource[:name]}: default page size added."
|
76
|
+
end
|
77
|
+
|
78
|
+
if old_resource[:default_page_size] && !new_resource[:default_page_size]
|
79
|
+
@errors << "#{old_resource[:name]}: default page size removed."
|
80
|
+
end
|
81
|
+
|
82
|
+
if old_resource[:default_page_size] && new_resource[:default_page_size]
|
83
|
+
if old_resource[:default_page_size] != new_resource[:default_page_size]
|
84
|
+
@errors << "#{old_resource[:name]}: default page size changed from #{old_resource[:default_page_size]} to #{new_resource[:default_page_size]}."
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
57
89
|
def compare_relationships(old_resource, new_resource)
|
58
90
|
old_resource[:relationships].each_pair do |name, old_rel|
|
59
91
|
unless new_rel = new_resource[:relationships][name]
|
@@ -61,6 +93,11 @@ module Graphiti
|
|
61
93
|
next
|
62
94
|
end
|
63
95
|
|
96
|
+
if new_rel[:single] && !old_rel[:single]
|
97
|
+
@errors << "#{old_resource[:name]}: relationship #{name.inspect} became single: true."
|
98
|
+
next
|
99
|
+
end
|
100
|
+
|
64
101
|
if new_rel[:resource] != old_rel[:resource]
|
65
102
|
@errors << "#{old_resource[:name]}: relationship #{name.inspect} changed resource from #{old_rel[:resource]} to #{new_rel[:resource]}."
|
66
103
|
end
|
@@ -82,6 +119,29 @@ module Graphiti
|
|
82
119
|
end
|
83
120
|
end
|
84
121
|
|
122
|
+
def compare_sorts(old_resource, new_resource)
|
123
|
+
old_resource[:sorts].each_pair do |name, old_sort|
|
124
|
+
unless new_sort = new_resource[:sorts][name]
|
125
|
+
@errors << "#{old_resource[:name]}: sort #{name.inspect} was removed."
|
126
|
+
next
|
127
|
+
end
|
128
|
+
|
129
|
+
if new_sort[:guard] && !old_sort[:guard]
|
130
|
+
@errors << "#{old_resource[:name]}: sort #{name.inspect} became guarded."
|
131
|
+
end
|
132
|
+
|
133
|
+
if new_sort[:only] && !old_sort[:only]
|
134
|
+
@errors << "#{old_resource[:name]}: sort #{name.inspect} now limited to only #{new_sort[:only].inspect}."
|
135
|
+
end
|
136
|
+
|
137
|
+
if new_sort[:only] && old_sort[:only]
|
138
|
+
if new_sort[:only] != old_sort[:only]
|
139
|
+
@errors << "#{old_resource[:name]}: sort #{name.inspect} was limited to only #{old_sort[:only].inspect}, now limited to only #{new_sort[:only].inspect}."
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
85
145
|
def compare_filters(old_resource, new_resource)
|
86
146
|
old_resource[:filters].each_pair do |name, old_filter|
|
87
147
|
unless new_filter = new_resource[:filters][name]
|
@@ -98,6 +158,16 @@ module Graphiti
|
|
98
158
|
@errors << "#{old_resource[:name]}: filter #{name.inspect} became singular."
|
99
159
|
end
|
100
160
|
|
161
|
+
if new_filter[:dependencies] && !old_filter[:dependencies]
|
162
|
+
@errors << "#{old_resource[:name]}: filter #{name.inspect} added dependencies #{new_filter[:dependencies].inspect}."
|
163
|
+
end
|
164
|
+
|
165
|
+
if new_filter[:dependencies] && old_filter[:dependencies]
|
166
|
+
if new_filter[:dependencies] != old_filter[:dependenices]
|
167
|
+
@errors << "#{old_resource[:name]}: filter #{name.inspect} changed dependencies from #{old_filter[:dependencies].inspect} to #{new_filter[:dependencies].inspect}."
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
101
171
|
if new_filter[:allow] != old_filter[:allow]
|
102
172
|
new = new_filter[:allow] || []
|
103
173
|
old = old_filter[:allow] || []
|
@@ -182,7 +252,7 @@ module Graphiti
|
|
182
252
|
@errors << "#{resource_name}: #{prefix} #{att_name.inspect} changed type from #{old_att[:type].inspect} to #{new_att[:type].inspect}."
|
183
253
|
end
|
184
254
|
|
185
|
-
[:readable, :writable
|
255
|
+
[:readable, :writable].each do |flag|
|
186
256
|
if [true, 'guarded'].include?(old_att[flag]) && new_att[flag] == false
|
187
257
|
@errors << "#{resource_name}: #{prefix} #{att_name.inspect} changed flag #{flag.inspect} from #{old_att[flag].inspect} to #{new_att[flag].inspect}."
|
188
258
|
end
|
data/lib/graphiti/scope.rb
CHANGED
@@ -8,13 +8,13 @@ module Graphiti
|
|
8
8
|
@query = query
|
9
9
|
@opts = opts
|
10
10
|
|
11
|
-
@object = @resource.around_scoping(@object,
|
11
|
+
@object = @resource.around_scoping(@object, @query.hash) do |scope|
|
12
12
|
apply_scoping(scope, opts)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
16
|
def resolve_stats
|
17
|
-
if
|
17
|
+
if @query.hash[:stats]
|
18
18
|
Stats::Payload.new(@resource, @query, @unpaginated_object).generate
|
19
19
|
else
|
20
20
|
{}
|
@@ -36,18 +36,13 @@ module Graphiti
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
def query_hash
|
40
|
-
@query_hash ||= @query.to_hash
|
41
|
-
end
|
42
|
-
|
43
39
|
private
|
44
40
|
|
45
41
|
# Used to ensure the resource's serializer is used
|
46
42
|
# Not one derived through the usual jsonapi-rb logic
|
47
43
|
def assign_serializer(records)
|
48
44
|
records.each do |r|
|
49
|
-
|
50
|
-
r.instance_variable_set(:@__serializer_klass, serializer)
|
45
|
+
@resource.decorate_record(r)
|
51
46
|
end
|
52
47
|
end
|
53
48
|
|
@@ -91,7 +86,7 @@ module Graphiti
|
|
91
86
|
end
|
92
87
|
|
93
88
|
def add_scoping(key, scoping_class, opts, default = {})
|
94
|
-
@object = scoping_class.new(@resource,
|
89
|
+
@object = scoping_class.new(@resource, @query.hash, @object, opts).apply
|
95
90
|
@unpaginated_object = @object unless key == :paginate
|
96
91
|
end
|
97
92
|
end
|
@@ -6,7 +6,7 @@ module Graphiti
|
|
6
6
|
# a default if not part of the user request.
|
7
7
|
#
|
8
8
|
# @attr_reader [Resource] resource The corresponding Resource instance
|
9
|
-
# @attr_reader [Hash] query_hash the Query#
|
9
|
+
# @attr_reader [Hash] query_hash the Query#hash node relevant to the current resource
|
10
10
|
#
|
11
11
|
# @see Scoping::DefaultFilter
|
12
12
|
# @see Scoping::ExtraFields
|
@@ -15,7 +15,7 @@ module Graphiti
|
|
15
15
|
# @see Scoping::Sort
|
16
16
|
# @see Scope#initialize
|
17
17
|
# @see Scope#query_hash
|
18
|
-
# @see Query#
|
18
|
+
# @see Query#hash
|
19
19
|
class Base
|
20
20
|
attr_reader :resource, :query_hash
|
21
21
|
|
@@ -32,6 +32,11 @@ module Graphiti
|
|
32
32
|
raise Errors::RequiredFilter.new(resource, missing_required_filters)
|
33
33
|
end
|
34
34
|
|
35
|
+
if missing_dependent_filters.any?
|
36
|
+
raise Errors::MissingDependentFilter.new \
|
37
|
+
resource, missing_dependent_filters
|
38
|
+
end
|
39
|
+
|
35
40
|
each_filter do |filter, operator, value|
|
36
41
|
@scope = filter_scope(filter, operator, value)
|
37
42
|
end
|
@@ -20,17 +20,32 @@ module Graphiti
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def missing_required_filters
|
23
|
-
|
23
|
+
required_filters - filter_param.keys
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
resource.
|
28
|
-
k if v[:
|
26
|
+
def required_filters
|
27
|
+
resource.filters.map do |k, v|
|
28
|
+
k if v[:required]
|
29
29
|
end.compact
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
33
|
-
|
32
|
+
def missing_dependent_filters
|
33
|
+
[].tap do |arr|
|
34
|
+
filter_param.each_pair do |key, value|
|
35
|
+
if df = dependent_filters[key]
|
36
|
+
missing = df[:dependencies] - filter_param.keys
|
37
|
+
unless missing.length.zero?
|
38
|
+
arr << { filter: df, missing: missing }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def dependent_filters
|
46
|
+
resource.filters.select do |k, v|
|
47
|
+
v[:dependencies].present?
|
48
|
+
end
|
34
49
|
end
|
35
50
|
end
|
36
51
|
end
|
@@ -23,14 +23,14 @@ module Graphiti
|
|
23
23
|
# We should use the default unless the user has customized.
|
24
24
|
# @see Resource.paginate
|
25
25
|
class Scoping::Paginate < Scoping::Base
|
26
|
-
|
26
|
+
DEFAULT_PAGE_SIZE = 20
|
27
27
|
|
28
28
|
# Apply the pagination logic. Raise error if over the max page size.
|
29
29
|
# @return the scope object we are chaining/modifying
|
30
30
|
def apply
|
31
|
-
if size >
|
31
|
+
if size > resource.max_page_size
|
32
32
|
raise Graphiti::Errors::UnsupportedPageSize
|
33
|
-
.new(size,
|
33
|
+
.new(size, resource.max_page_size)
|
34
34
|
elsif requested? && @opts[:sideload_parent_length].to_i > 1
|
35
35
|
raise Graphiti::Errors::UnsupportedPagination
|
36
36
|
else
|
@@ -81,7 +81,7 @@ module Graphiti
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def size
|
84
|
-
(page_param[:size] || resource.default_page_size).to_i
|
84
|
+
(page_param[:size] || resource.default_page_size || DEFAULT_PAGE_SIZE).to_i
|
85
85
|
end
|
86
86
|
end
|
87
87
|
end
|
@@ -22,10 +22,16 @@ module Graphiti
|
|
22
22
|
# @return the scope we are chaining/modifying
|
23
23
|
def apply_standard_scope
|
24
24
|
each_sort do |attribute, direction|
|
25
|
-
|
26
|
-
|
25
|
+
sort = resource.sorts[attribute]
|
26
|
+
if sort[:only] && sort[:only] != direction
|
27
|
+
raise Errors::UnsupportedSort.new resource,
|
28
|
+
attribute, sort[:only], direction
|
27
29
|
else
|
28
|
-
|
30
|
+
if sort[:proc]
|
31
|
+
@scope = sort[:proc].call(@scope, direction)
|
32
|
+
else
|
33
|
+
@scope = resource.adapter.order(@scope, attribute, direction)
|
34
|
+
end
|
29
35
|
end
|
30
36
|
end
|
31
37
|
@scope
|
@@ -54,11 +60,26 @@ module Graphiti
|
|
54
60
|
def sort_param
|
55
61
|
@sort_param ||= begin
|
56
62
|
if query_hash[:sort].blank?
|
57
|
-
resource.default_sort
|
63
|
+
resource.default_sort || []
|
58
64
|
else
|
59
|
-
query_hash[:sort]
|
65
|
+
normalize(query_hash[:sort])
|
60
66
|
end
|
61
67
|
end
|
62
68
|
end
|
69
|
+
|
70
|
+
def normalize(sort)
|
71
|
+
return sort if sort.is_a?(Array)
|
72
|
+
sorts = sort.split(',')
|
73
|
+
sorts.map do |s|
|
74
|
+
sort_hash(s)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def sort_hash(attr)
|
79
|
+
value = attr[0] == '-' ? :desc : :asc
|
80
|
+
key = attr.sub('-', '').to_sym
|
81
|
+
|
82
|
+
{ key => value }
|
83
|
+
end
|
63
84
|
end
|
64
85
|
end
|