jsonapi-resources 0.4.0 → 0.4.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 57590c2f9544bd54d43d1a024ae878bae321f87f
4
- data.tar.gz: 102b9414a9ebddd19b249daa2684f9460083c670
3
+ metadata.gz: ccc95678a9008bcac7b1b375cd19e684c626effb
4
+ data.tar.gz: e7b641e7055f1a88f9673082617812ffe4b8ae25
5
5
  SHA512:
6
- metadata.gz: 7b139efb93f753f5a20e314e02e4ae3cc33bed69d7c9303ebf4bf838c9013ea5a8ef625f4720f70114b3ff6b219788e4b7303e7f55723829980fb1ac729d8d9a
7
- data.tar.gz: d7580a2b8e21f6813b2a6e2c7d59f8b8f6230e2834c1e9a16c10215d40ebe3e479e451f8d4fad3a811d301e0abed030a66b27d2c3ce9b37553278d6c44bc5a77
6
+ metadata.gz: 77b1fa60f243eb0fe5d62d9a28f6336d613def402e5d933a3e5157be520eb789c8f073630dbe69982c7e2bc8a1f1203a500c74764c46e0c37ce963ef5e86897c
7
+ data.tar.gz: af564dac990b904cc6bb4ad8b38fe928043c988d6d7d83619a1f538be8522fa1d72b4c7e2aa4ab01e34e96d3742174c8c70495ef054315b51d195fffab369b42
data/README.md CHANGED
@@ -50,8 +50,6 @@ Resources must be derived from `JSONAPI::Resource`, or a class that is itself de
50
50
  For example:
51
51
 
52
52
  ```ruby
53
- require 'jsonapi/resource'
54
-
55
53
  class ContactResource < JSONAPI::Resource
56
54
  end
57
55
  ```
@@ -64,8 +62,6 @@ the `attribute` method, and multiple attributes can be declared with the `attrib
64
62
  For example:
65
63
 
66
64
  ```ruby
67
- require 'jsonapi/resource'
68
-
69
65
  class ContactResource < JSONAPI::Resource
70
66
  attribute :name_first
71
67
  attributes :name_last, :email, :twitter
@@ -81,8 +77,6 @@ This allows a resource's methods to access the underlying model.
81
77
  For example, a computed attribute for `full_name` could be defined as such:
82
78
 
83
79
  ```ruby
84
- require 'jsonapi/resource'
85
-
86
80
  class ContactResource < JSONAPI::Resource
87
81
  attributes :name_first, :name_last, :email, :twitter
88
82
  attribute :full_name
@@ -127,8 +121,6 @@ the `update` or `create` methods, override the `self.updatable_fields` and `self
127
121
  This example prevents `full_name` from being set:
128
122
 
129
123
  ```ruby
130
- require 'jsonapi/resource'
131
-
132
124
  class ContactResource < JSONAPI::Resource
133
125
  attributes :name_first, :name_last, :full_name
134
126
 
@@ -280,8 +272,6 @@ declared using the `filter` method, and multiple filters can be declared with th
280
272
  For example:
281
273
 
282
274
  ```ruby
283
- require 'jsonapi/resource'
284
-
285
275
  class ContactResource < JSONAPI::Resource
286
276
  attributes :name_first, :name_last, :email, :twitter
287
277
 
@@ -290,6 +280,25 @@ class ContactResource < JSONAPI::Resource
290
280
  end
291
281
  ```
292
282
 
283
+ ##### Default Filters
284
+
285
+ A default filter may be defined for a resource using the `default` option on the `filter` method. This default is used
286
+ unless the request overrides this value.
287
+
288
+ For example:
289
+
290
+ ```ruby
291
+ class CommentResource < JSONAPI::Resource
292
+ attributes :body, :status
293
+ has_one :post
294
+ has_one :author
295
+
296
+ filter :status, default: 'published,pending'
297
+ end
298
+ ```
299
+
300
+ The default value is used as if it came from the request.
301
+
293
302
  ##### Finders
294
303
 
295
304
  Basic finding by filters is supported by resources. This is implemented in the `find` and `find_by_key` finder methods.
@@ -534,23 +543,22 @@ Callbacks can also be defined for `JSONAPI::OperationsProcessor` events:
534
543
  - `:remove_has_many_association_operation`: A `remove_has_many_association_operation`.
535
544
  - `:remove_has_one_association_operation`: A `remove_has_one_association_operation`.
536
545
 
537
- The operation callbacks have access to two meta data hashes, `@operations_meta` and `@operation_meta`, the full list of
538
- `@operations`, each individual `@operation` and the `@result` variables.
546
+ The operation callbacks have access to two meta data hashes, `@operations_meta` and `@operation_meta`, two links hashes,
547
+ `@operations_links` and `@operation_links`, the full list of `@operations`, each individual `@operation` and the
548
+ `@result` variables.
539
549
 
540
550
  ##### Custom `OperationsProcessor` Example to Return total_count in Meta
541
551
 
552
+ Note: this can also be accomplished with the `top_level_meta_include_record_count` option, and in most cases that will
553
+ be the better option.
554
+
542
555
  To return the total record count of a find operation in the meta data of a find operation you can create a custom
543
556
  OperationsProcessor. For example:
544
557
 
545
558
  ```ruby
546
559
  class CountingActiveRecordOperationsProcessor < ActiveRecordOperationsProcessor
547
560
  after_find_operation do
548
- count = @operation.resource_klass.find_count(@operation.resource_klass.verify_filters(@operation.filters, @context),
549
- context: @context,
550
- include_directives: @operation.include_directives,
551
- sort_criteria: @operation.sort_criteria)
552
-
553
- @operation_meta[:total_records] = count
561
+ @operation_meta[:total_records] = @operation.record_count
554
562
  end
555
563
  end
556
564
  ```
@@ -730,13 +738,14 @@ module JSONAPI
730
738
  KEY_NOT_INCLUDED_IN_URL = 110
731
739
  INVALID_INCLUDE = 112
732
740
  RELATION_EXISTS = 113
733
- INVALID_SORT_PARAM = 114
741
+ INVALID_SORT_CRITERIA = 114
734
742
  INVALID_LINKS_OBJECT = 115
735
743
  TYPE_MISMATCH = 116
736
744
  INVALID_PAGE_OBJECT = 117
737
745
  INVALID_PAGE_VALUE = 118
738
746
  INVALID_FIELD_FORMAT = 119
739
747
  INVALID_FILTERS_SYNTAX = 120
748
+ SAVE_FAILED = 121
740
749
  FORBIDDEN = 403
741
750
  RECORD_NOT_FOUND = 404
742
751
  UNSUPPORTED_MEDIA_TYPE = 415
@@ -746,7 +755,7 @@ end
746
755
 
747
756
  These codes can be customized in your app by creating an initializer to override any or all of the codes.
748
757
 
749
- In addition textual error coses can be returned by setting the configuration option `use_text_errors = true`. For
758
+ In addition textual error codes can be returned by setting the configuration option `use_text_errors = true`. For
750
759
  example:
751
760
 
752
761
  ```ruby
@@ -762,7 +771,6 @@ The `ResourceSerializer` can be used to serialize a resource into JSON API compl
762
771
  method that takes a resource instance or array of resource instances to serialize. For example:
763
772
 
764
773
  ```ruby
765
- require 'jsonapi/resource_serializer'
766
774
  post = Post.find(1)
767
775
  JSONAPI::ResourceSerializer.new(PostResource).serialize_to_hash(PostResource.new(post))
768
776
  ```
@@ -882,8 +890,6 @@ contact_links_phone_numbers GET /contacts/:contact_id/links/phone-numbers(
882
890
  contact_phone_numbers GET /contacts/:contact_id/phone-numbers(.:format) phone_numbers#get_related_resources {:association=>"phone_numbers", :source=>"contacts"}
883
891
  contacts GET /contacts(.:format) contacts#index
884
892
  POST /contacts(.:format) contacts#create
885
- new_contact GET /contacts/new(.:format) contacts#new
886
- edit_contact GET /contacts/:id/edit(.:format) contacts#edit
887
893
  contact GET /contacts/:id(.:format) contacts#show
888
894
  PATCH /contacts/:id(.:format) contacts#update
889
895
  PUT /contacts/:id(.:format) contacts#update
@@ -894,8 +900,6 @@ contact_links_phone_numbers GET /contacts/:contact_id/links/phone-numbers(
894
900
  phone_number_contact GET /phone-numbers/:phone_number_id/contact(.:format) contacts#get_related_resource {:association=>"contact", :source=>"phone_numbers"}
895
901
  phone_numbers GET /phone-numbers(.:format) phone_numbers#index
896
902
  POST /phone-numbers(.:format) phone_numbers#create
897
- new_phone_number GET /phone-numbers/new(.:format) phone_numbers#new
898
- edit_phone_number GET /phone-numbers/:id/edit(.:format) phone_numbers#edit
899
903
  phone_number GET /phone-numbers/:id(.:format) phone_numbers#show
900
904
  PATCH /phone-numbers/:id(.:format) phone_numbers#update
901
905
  PUT /phone-numbers/:id(.:format) phone_numbers#update
@@ -925,8 +929,6 @@ gives routes that are only related to the primary resource, and none for its rel
925
929
  Prefix Verb URI Pattern Controller#Action
926
930
  contacts GET /contacts(.:format) contacts#index
927
931
  POST /contacts(.:format) contacts#create
928
- new_contact GET /contacts/new(.:format) contacts#new
929
- edit_contact GET /contacts/:id/edit(.:format) contacts#edit
930
932
  contact GET /contacts/:id(.:format) contacts#show
931
933
  PATCH /contacts/:id(.:format) contacts#update
932
934
  PUT /contacts/:id(.:format) contacts#update
@@ -965,8 +967,6 @@ contact_links_phone_numbers GET /contacts/:contact_id/links/phone-numbers(.:f
965
967
  DELETE /contacts/:contact_id/links/phone-numbers/:keys(.:format) contacts#destroy_association {:association=>"phone_numbers"}
966
968
  contacts GET /contacts(.:format) contacts#index
967
969
  POST /contacts(.:format) contacts#create
968
- new_contact GET /contacts/new(.:format) contacts#new
969
- edit_contact GET /contacts/:id/edit(.:format) contacts#edit
970
970
  contact GET /contacts/:id(.:format) contacts#show
971
971
  PATCH /contacts/:id(.:format) contacts#update
972
972
  PUT /contacts/:id(.:format) contacts#update
@@ -996,8 +996,6 @@ gives the following routes:
996
996
  contact_phone_numbers GET /contacts/:contact_id/phone-numbers(.:format) phone_numbers#get_related_resources {:association=>"phone_numbers", :source=>"contacts"}
997
997
  contacts GET /contacts(.:format) contacts#index
998
998
  POST /contacts(.:format) contacts#create
999
- new_contact GET /contacts/new(.:format) contacts#new
1000
- edit_contact GET /contacts/:id/edit(.:format) contacts#edit
1001
999
  contact GET /contacts/:id(.:format) contacts#show
1002
1000
  PATCH /contacts/:id(.:format) contacts#update
1003
1001
  PUT /contacts/:id(.:format) contacts#update
@@ -1026,8 +1024,6 @@ gives the following routes:
1026
1024
  phone_number_contact GET /phone-numbers/:phone_number_id/contact(.:format) contacts#get_related_resource {:association=>"contact", :source=>"phone_numbers"}
1027
1025
  phone_numbers GET /phone-numbers(.:format) phone_numbers#index
1028
1026
  POST /phone-numbers(.:format) phone_numbers#create
1029
- new_phone_number GET /phone-numbers/new(.:format) phone_numbers#new
1030
- edit_phone_number GET /phone-numbers/:id/edit(.:format) phone_numbers#edit
1031
1027
  phone_number GET /phone-numbers/:id(.:format) phone_numbers#show
1032
1028
  PATCH /phone-numbers/:id(.:format) phone_numbers#update
1033
1029
  PUT /phone-numbers/:id(.:format) phone_numbers#update
@@ -1179,6 +1175,42 @@ end
1179
1175
 
1180
1176
  You would specify this in `JSONAPI.configure` as `:upper_camelized`.
1181
1177
 
1178
+ ## Configuration
1179
+
1180
+ JR has a few configuration options. Some have already been mentioned above. To set configuration options create an
1181
+ initializer and add the options you wish to set. All options have defaults, so you only need to set the options that
1182
+ are different. The default options are shown below.
1183
+
1184
+ ```ruby
1185
+ JSONAPI.configure do |config|
1186
+ #:underscored_key, :camelized_key, :dasherized_key, or custom
1187
+ config.json_key_format = :dasherized_key
1188
+
1189
+ #:underscored_route, :camelized_route, :dasherized_route, or custom
1190
+ config.route_format = :dasherized_route
1191
+
1192
+ #:basic, :active_record, or custom
1193
+ config.operations_processor = :active_record
1194
+
1195
+ config.allowed_request_params = [:include, :fields, :format, :controller, :action, :sort, :page]
1196
+
1197
+ # :none, :offset, :paged, or a custom paginator name
1198
+ config.default_paginator = :none
1199
+
1200
+ # Output pagination links at top level
1201
+ config.top_level_links_include_pagination = true
1202
+
1203
+ config.default_page_size = 10
1204
+ config.maximum_page_size = 20
1205
+
1206
+ # Output the record count in top level meta data for find operations
1207
+ config.top_level_meta_include_record_count = false
1208
+ config.top_level_meta_record_count_key = :record_count
1209
+
1210
+ config.use_text_errors = false
1211
+ end
1212
+ ```
1213
+
1182
1214
  ## Contributing
1183
1215
 
1184
1216
  1. Fork it ( http://github.com/cerebris/jsonapi-resources/fork )
@@ -123,6 +123,10 @@ module JSONAPI
123
123
  {}
124
124
  end
125
125
 
126
+ def base_response_links
127
+ {}
128
+ end
129
+
126
130
  def render_errors(errors)
127
131
  operation_results = JSONAPI::OperationResults.new()
128
132
  result = JSONAPI::ErrorsOperationResult.new(errors[0].status, errors)
@@ -147,7 +151,9 @@ module JSONAPI
147
151
  key_formatter: key_formatter,
148
152
  route_formatter: route_formatter,
149
153
  base_meta: base_response_meta,
150
- resource_serializer_klass: resource_serializer_klass
154
+ base_links: base_response_links,
155
+ resource_serializer_klass: resource_serializer_klass,
156
+ request: @request
151
157
  }
152
158
  )
153
159
  end
@@ -13,7 +13,10 @@ module JSONAPI
13
13
  :default_paginator,
14
14
  :default_page_size,
15
15
  :maximum_page_size,
16
- :use_text_errors
16
+ :use_text_errors,
17
+ :top_level_links_include_pagination,
18
+ :top_level_meta_include_record_count,
19
+ :top_level_meta_record_count_key
17
20
 
18
21
  def initialize
19
22
  #:underscored_key, :camelized_key, :dasherized_key, or custom
@@ -30,8 +33,17 @@ module JSONAPI
30
33
  # :none, :offset, :paged, or a custom paginator name
31
34
  self.default_paginator = :none
32
35
 
36
+ # Output pagination links at top level
37
+ self.top_level_links_include_pagination = true
38
+
33
39
  self.default_page_size = 10
34
40
  self.maximum_page_size = 20
41
+
42
+ # Metadata
43
+ # Output record count in top level meta for find operation
44
+ self.top_level_meta_include_record_count = false
45
+ self.top_level_meta_record_count_key = :record_count
46
+
35
47
  self.use_text_errors = false
36
48
  end
37
49
 
@@ -69,6 +81,18 @@ module JSONAPI
69
81
  def use_text_errors=(use_text_errors)
70
82
  @use_text_errors = use_text_errors
71
83
  end
84
+
85
+ def top_level_links_include_pagination=(top_level_links_include_pagination)
86
+ @top_level_links_include_pagination = top_level_links_include_pagination
87
+ end
88
+
89
+ def top_level_meta_include_record_count=(top_level_meta_include_record_count)
90
+ @top_level_meta_include_record_count = top_level_meta_include_record_count
91
+ end
92
+
93
+ def top_level_meta_record_count_key=(top_level_meta_record_count_key)
94
+ @top_level_meta_record_count_key = top_level_meta_record_count_key
95
+ end
72
96
  end
73
97
 
74
98
  class << self
@@ -23,6 +23,22 @@ module JSONAPI
23
23
  super(resource_klass, false)
24
24
  end
25
25
 
26
+ def record_count
27
+ @_record_count ||= @resource_klass.find_count(@resource_klass.verify_filters(@filters, @context),
28
+ context: @context,
29
+ include_directives: @include_directives)
30
+ end
31
+
32
+ def pagination_params
33
+ if @paginator && JSONAPI.configuration.top_level_links_include_pagination
34
+ options = {}
35
+ options[:record_count] = record_count if @paginator.class.requires_record_count
36
+ return @paginator.links_page_params(options)
37
+ else
38
+ return {}
39
+ end
40
+ end
41
+
26
42
  def apply(context)
27
43
  resource_records = @resource_klass.find(@resource_klass.verify_filters(@filters, context),
28
44
  context: context,
@@ -30,7 +46,18 @@ module JSONAPI
30
46
  sort_criteria: @sort_criteria,
31
47
  paginator: @paginator)
32
48
 
33
- return JSONAPI::ResourcesOperationResult.new(:ok, resource_records)
49
+ options = {}
50
+ if JSONAPI.configuration.top_level_links_include_pagination
51
+ options[:pagination_params] = pagination_params
52
+ end
53
+
54
+ if JSONAPI.configuration.top_level_meta_include_record_count
55
+ options[:record_count] = record_count
56
+ end
57
+
58
+ return JSONAPI::ResourcesOperationResult.new(:ok,
59
+ resource_records,
60
+ options)
34
61
 
35
62
  rescue JSONAPI::Exceptions::Error => e
36
63
  return JSONAPI::ErrorsOperationResult.new(e.errors[0].code, e.errors)
@@ -2,47 +2,53 @@ module JSONAPI
2
2
  class OperationResult
3
3
  attr_accessor :code
4
4
  attr_accessor :meta
5
+ attr_accessor :links
6
+ attr_accessor :options
5
7
 
6
- def initialize(code)
8
+ def initialize(code, options = {})
7
9
  @code = code
8
- @meta = {}
10
+ @options = options
11
+ @meta = options.fetch(:meta, {})
12
+ @links = options.fetch(:links, {})
9
13
  end
10
14
  end
11
15
 
12
16
  class ErrorsOperationResult < OperationResult
13
17
  attr_accessor :errors
14
18
 
15
- def initialize(code, errors)
19
+ def initialize(code, errors, options = {})
16
20
  @errors = errors
17
- super(code)
21
+ super(code, options)
18
22
  end
19
23
  end
20
24
 
21
25
  class ResourceOperationResult < OperationResult
22
26
  attr_accessor :resource
23
27
 
24
- def initialize(code, resource)
28
+ def initialize(code, resource, options = {})
25
29
  @resource = resource
26
- super(code)
30
+ super(code, options)
27
31
  end
28
32
  end
29
33
 
30
34
  class ResourcesOperationResult < OperationResult
31
- attr_accessor :resources
35
+ attr_accessor :resources, :pagination_params, :record_count
32
36
 
33
- def initialize(code, resources)
37
+ def initialize(code, resources, options = {})
34
38
  @resources = resources
35
- super(code)
39
+ @pagination_params = options.fetch(:pagination_params, {})
40
+ @record_count = options[:record_count]
41
+ super(code, options)
36
42
  end
37
43
  end
38
44
 
39
45
  class LinksObjectOperationResult < OperationResult
40
46
  attr_accessor :parent_resource, :association
41
47
 
42
- def initialize(code, parent_resource, association)
48
+ def initialize(code, parent_resource, association, options = {})
43
49
  @parent_resource = parent_resource
44
50
  @association = association
45
- super(code)
51
+ super(code, options)
46
52
  end
47
53
  end
48
54
  end
@@ -2,11 +2,13 @@ module JSONAPI
2
2
  class OperationResults
3
3
  attr_accessor :results
4
4
  attr_accessor :meta
5
+ attr_accessor :links
5
6
 
6
7
  def initialize
7
8
  @results = []
8
9
  @has_errors = false
9
10
  @meta = {}
11
+ @links = {}
10
12
  end
11
13
 
12
14
  def add_result(result)
@@ -41,16 +41,21 @@ module JSONAPI
41
41
 
42
42
  run_callbacks :operations do
43
43
  transaction do
44
+ # Links and meta data global to the set of operations
44
45
  @operations_meta = {}
46
+ @operations_links = {}
45
47
  @operations.each do |operation|
46
48
  @operation = operation
49
+ # Links and meta data for each operation
47
50
  @operation_meta = {}
51
+ @operation_links = {}
48
52
  run_callbacks :operation do
49
53
  @result = nil
50
54
  run_callbacks @operation.class.name.demodulize.underscore.to_sym do
51
55
  @result = process_operation(@operation)
52
56
  end
53
57
  @result.meta.merge!(@operation_meta)
58
+ @result.links.merge!(@operation_links)
54
59
  @results.add_result(@result)
55
60
  if @results.has_errors?
56
61
  rollback
@@ -58,6 +63,7 @@ module JSONAPI
58
63
  end
59
64
  end
60
65
  @results.meta = @operations_meta
66
+ @results.links = @operations_links
61
67
  end
62
68
  end
63
69
  @results
@@ -7,7 +7,19 @@ module JSONAPI
7
7
  # relation
8
8
  end
9
9
 
10
+ def links_page_params(options = {})
11
+ # :nocov:
12
+ {}
13
+ # :nocov:
14
+ end
15
+
10
16
  class << self
17
+ def requires_record_count
18
+ # :nocov:
19
+ false
20
+ # :nocov:
21
+ end
22
+
11
23
  def paginator_for(paginator)
12
24
  paginator_class_name = "#{paginator.to_s.camelize}Paginator"
13
25
  paginator_class_name.safe_constantize if paginator_class_name
@@ -17,15 +29,62 @@ module JSONAPI
17
29
  end
18
30
 
19
31
  class OffsetPaginator < JSONAPI::Paginator
32
+ attr_reader :limit, :offset
33
+
20
34
  def initialize(params)
21
35
  parse_pagination_params(params)
22
36
  verify_pagination_params
23
37
  end
24
38
 
39
+ def self.requires_record_count
40
+ true
41
+ end
42
+
25
43
  def apply(relation, order_options)
26
44
  relation.offset(@offset).limit(@limit)
27
45
  end
28
46
 
47
+ def links_page_params(options = {})
48
+ record_count = options[:record_count]
49
+ links_page_params = {}
50
+
51
+ links_page_params['first'] = {
52
+ 'offset' => 0,
53
+ 'limit' => @limit
54
+ }
55
+
56
+ if @offset > 0
57
+ previous_offset = @offset - @limit
58
+
59
+ if previous_offset < 0
60
+ previous_offset = 0
61
+ end
62
+
63
+ links_page_params['previous'] = {
64
+ 'offset' => previous_offset,
65
+ 'limit' => @limit
66
+ }
67
+ end
68
+
69
+ next_offset = @offset + @limit
70
+
71
+ unless next_offset >= record_count
72
+ links_page_params['next'] = {
73
+ 'offset' => next_offset,
74
+ 'limit'=> @limit
75
+ }
76
+ end
77
+
78
+ if record_count
79
+ links_page_params['last'] = {
80
+ 'offset' => record_count - @limit,
81
+ 'limit' => @limit
82
+ }
83
+ end
84
+
85
+ links_page_params
86
+ end
87
+
29
88
  private
30
89
  def parse_pagination_params(params)
31
90
  if params.nil?
@@ -58,16 +117,57 @@ class OffsetPaginator < JSONAPI::Paginator
58
117
  end
59
118
 
60
119
  class PagedPaginator < JSONAPI::Paginator
120
+ attr_reader :size, :number
121
+
61
122
  def initialize(params)
62
123
  parse_pagination_params(params)
63
124
  verify_pagination_params
64
125
  end
65
126
 
127
+ def self.requires_record_count
128
+ true
129
+ end
130
+
66
131
  def apply(relation, order_options)
67
132
  offset = (@number - 1) * @size
68
133
  relation.offset(offset).limit(@size)
69
134
  end
70
135
 
136
+ def links_page_params(options = {})
137
+ record_count = options[:record_count]
138
+ page_count = (record_count / @size.to_f).ceil
139
+
140
+ links_page_params = {}
141
+
142
+ links_page_params['first'] = {
143
+ 'number' => 1,
144
+ 'size' => @size
145
+ }
146
+
147
+ if @number > 1
148
+ links_page_params['previous'] = {
149
+ 'number' => @number - 1,
150
+ 'size' => @size
151
+ }
152
+ end
153
+
154
+ unless @number >= page_count
155
+ links_page_params['next'] = {
156
+ 'number' => @number + 1,
157
+ 'size'=> @size
158
+ }
159
+ end
160
+
161
+ if record_count
162
+ links_page_params['last'] = {
163
+ 'number' => page_count,
164
+ 'size' => @size
165
+ }
166
+ end
167
+
168
+ links_page_params
169
+ end
170
+
71
171
  private
72
172
  def parse_pagination_params(params)
73
173
  if params.nil?
@@ -5,9 +5,10 @@ module JSONAPI
5
5
  class Request
6
6
  attr_accessor :fields, :include, :filters, :sort_criteria, :errors, :operations,
7
7
  :resource_klass, :context, :paginator, :source_klass, :source_id,
8
- :include_directives
8
+ :include_directives, :params
9
9
 
10
10
  def initialize(params = nil, options = {})
11
+ @params = params
11
12
  @context = options[:context]
12
13
  @key_formatter = options.fetch(:key_formatter, JSONAPI.configuration.key_formatter)
13
14
  @errors = []
@@ -21,7 +22,7 @@ module JSONAPI
21
22
  @paginator = nil
22
23
  @id = nil
23
24
 
24
- setup_action(params)
25
+ setup_action(@params)
25
26
  end
26
27
 
27
28
  def setup_action(params)
@@ -67,6 +67,10 @@ module JSONAPI
67
67
  }
68
68
  end
69
69
 
70
+ def find_link(query_params)
71
+ "#{@base_url}/#{formatted_module_path_from_klass(@primary_resource_klass)}#{@route_formatter.format(@primary_resource_klass._type.to_s)}?#{query_params.to_query}"
72
+ end
73
+
70
74
  private
71
75
  # Process the primary source object(s). This will then serialize associated object recursively based on the
72
76
  # requested includes. Fields are controlled fields option for each resource type, such
@@ -200,7 +204,11 @@ module JSONAPI
200
204
  end
201
205
 
202
206
  def formatted_module_path(source)
203
- source.class.name =~ /::[^:]+\Z/ ? (@route_formatter.format($`).freeze.gsub('::', '/') + '/').downcase : ''
207
+ formatted_module_path_from_klass(source.class)
208
+ end
209
+
210
+ def formatted_module_path_from_klass(klass)
211
+ klass.name =~ /::[^:]+\Z/ ? (@route_formatter.format($`).freeze.gsub('::', '/') + '/').downcase : ''
204
212
  end
205
213
 
206
214
  def self_href(source)
@@ -1,5 +1,5 @@
1
1
  module JSONAPI
2
2
  module Resources
3
- VERSION = "0.4.0"
3
+ VERSION = "0.4.1"
4
4
  end
5
5
  end
@@ -13,6 +13,9 @@ module JSONAPI
13
13
  meta = top_level_meta
14
14
  hash.merge!(meta: meta) unless meta.empty?
15
15
 
16
+ links = top_level_links
17
+ hash.merge!(links: links) unless links.empty?
18
+
16
19
  hash
17
20
  end
18
21
 
@@ -37,6 +40,8 @@ module JSONAPI
37
40
  )
38
41
  end
39
42
 
43
+ # Rolls up the top level meta data from the base_meta, the set of operations,
44
+ # and the result of each operation. The keys are then formatted.
40
45
  def top_level_meta
41
46
  meta = @options.fetch(:base_meta, {})
42
47
 
@@ -44,11 +49,45 @@ module JSONAPI
44
49
 
45
50
  @operation_results.results.each do |result|
46
51
  meta.merge!(result.meta)
52
+
53
+ if JSONAPI.configuration.top_level_meta_include_record_count
54
+ meta[JSONAPI.configuration.top_level_meta_record_count_key] = result.record_count
55
+ end
47
56
  end
48
57
 
49
58
  meta.deep_transform_keys { |key| @key_formatter.format(key) }
50
59
  end
51
60
 
61
+ # Rolls up the top level links from the base_links, the set of operations,
62
+ # and the result of each operation. The keys are then formatted.
63
+ def top_level_links
64
+ links = @options.fetch(:base_links, {})
65
+
66
+ links.merge!(@operation_results.links)
67
+
68
+ @operation_results.results.each do |result|
69
+ links.merge!(result.links)
70
+
71
+ # Build pagination links
72
+ if result.is_a?(JSONAPI::ResourcesOperationResult)
73
+ result.pagination_params.each_pair do |link_name, params|
74
+ query_params = {}
75
+ query_params[:page] = params
76
+
77
+ request = @options[:request]
78
+ query_params[:fields] = request.params[:fields] if request.params[:fields]
79
+ query_params[:include] = request.params[:include] if request.params[:include]
80
+ query_params[:sort] = request.params[:sort] if request.params[:sort]
81
+ query_params[:filter] = request.params[:filter] if request.params[:filter]
82
+
83
+ links[link_name] = serializer.find_link(query_params)
84
+ end
85
+ end
86
+ end
87
+
88
+ links.deep_transform_keys { |key| @key_formatter.format(key) }
89
+ end
90
+
52
91
  def results_to_hash
53
92
  if @operation_results.has_errors?
54
93
  {errors: @operation_results.all_errors}
@@ -26,6 +26,13 @@ module ActionDispatch
26
26
  options.merge!(res.routing_resource_options)
27
27
  options[:path] = format_route(@resource_type)
28
28
 
29
+ if options[:except]
30
+ options[:except] << :new unless options[:except].include?(:new) || options[:except].include?('new')
31
+ options[:except] << :edit unless options[:except].include?(:edit) || options[:except].include?('edit')
32
+ else
33
+ options[:except] = [:new, :edit]
34
+ end
35
+
29
36
  resource @resource_type, options do
30
37
  @scope[:jsonapi_resource] = @resource_type
31
38
 
@@ -37,15 +44,15 @@ module ActionDispatch
37
44
  end
38
45
  end
39
46
 
40
- def jsonapi_relationships
47
+ def jsonapi_relationships(options = {})
41
48
  res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(@resource_type))
42
49
  res._associations.each do |association_name, association|
43
50
  if association.is_a?(JSONAPI::Association::HasMany)
44
- jsonapi_links(association_name)
45
- jsonapi_related_resources(association_name)
51
+ jsonapi_links(association_name, options)
52
+ jsonapi_related_resources(association_name, options)
46
53
  else
47
- jsonapi_link(association_name)
48
- jsonapi_related_resource(association_name)
54
+ jsonapi_link(association_name, options)
55
+ jsonapi_related_resource(association_name, options)
49
56
  end
50
57
  end
51
58
  end
@@ -62,6 +69,13 @@ module ActionDispatch
62
69
 
63
70
  options[:path] = format_route(@resource_type)
64
71
 
72
+ if options[:except]
73
+ options[:except] << :new unless options[:except].include?(:new) || options[:except].include?('new')
74
+ options[:except] << :edit unless options[:except].include?(:edit) || options[:except].include?('edit')
75
+ else
76
+ options[:except] = [:new, :edit]
77
+ end
78
+
65
79
  resources @resource_type, options do
66
80
  @scope[:jsonapi_resource] = @resource_type
67
81
 
@@ -2148,6 +2148,33 @@ class Api::V2::BooksControllerTest < ActionController::TestCase
2148
2148
  assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2149
2149
  end
2150
2150
 
2151
+ def test_books_record_count_in_meta
2152
+ Api::V2::BookResource.paginator :offset
2153
+ JSONAPI.configuration.top_level_meta_include_record_count = true
2154
+ get :index, {include: 'book-comments'}
2155
+ JSONAPI.configuration.top_level_meta_include_record_count = false
2156
+
2157
+ assert_response :success
2158
+ assert_equal 1000, json_response['meta']['record-count']
2159
+ assert_equal 10, json_response['data'].size
2160
+ assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2161
+ end
2162
+
2163
+ def test_books_record_count_in_meta_custom_name
2164
+ Api::V2::BookResource.paginator :offset
2165
+ JSONAPI.configuration.top_level_meta_include_record_count = true
2166
+ JSONAPI.configuration.top_level_meta_record_count_key = 'total_records'
2167
+
2168
+ get :index, {include: 'book-comments'}
2169
+ JSONAPI.configuration.top_level_meta_include_record_count = false
2170
+ JSONAPI.configuration.top_level_meta_record_count_key = :record_count
2171
+
2172
+ assert_response :success
2173
+ assert_equal 1000, json_response['meta']['total-records']
2174
+ assert_equal 10, json_response['data'].size
2175
+ assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2176
+ end
2177
+
2151
2178
  def test_books_offset_pagination_no_params_includes_query_count_one_level
2152
2179
  Api::V2::BookResource.paginator :offset
2153
2180
 
@@ -2157,7 +2184,7 @@ class Api::V2::BooksControllerTest < ActionController::TestCase
2157
2184
  assert_response :success
2158
2185
  assert_equal 10, json_response['data'].size
2159
2186
  assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2160
- assert_equal 2, query_count
2187
+ assert_equal 3, query_count
2161
2188
  end
2162
2189
 
2163
2190
  def test_books_offset_pagination_no_params_includes_query_count_two_levels
@@ -2169,7 +2196,7 @@ class Api::V2::BooksControllerTest < ActionController::TestCase
2169
2196
  assert_response :success
2170
2197
  assert_equal 10, json_response['data'].size
2171
2198
  assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2172
- assert_equal 3, query_count
2199
+ assert_equal 4, query_count
2173
2200
  end
2174
2201
 
2175
2202
  def test_books_offset_pagination
@@ -2305,6 +2332,18 @@ class Api::V4::BooksControllerTest < ActionController::TestCase
2305
2332
  assert_equal 1000, json_response['meta']['totalRecords']
2306
2333
  JSONAPI.configuration.operations_processor = :active_record
2307
2334
  end
2335
+
2336
+ def test_books_operation_links
2337
+ JSONAPI.configuration.operations_processor = :counting_active_record
2338
+ Api::V4::BookResource.paginator :offset
2339
+ get :index, {page: {offset: 50, limit: 12}}
2340
+ assert_response :success
2341
+ assert_equal 12, json_response['data'].size
2342
+ assert_equal 'Book 50', json_response['data'][0]['attributes']['title']
2343
+ assert_equal 5, json_response['links'].size
2344
+ assert_equal 'https://test_corp.com', json_response['links']['spec']
2345
+ JSONAPI.configuration.operations_processor = :active_record
2346
+ end
2308
2347
  end
2309
2348
 
2310
2349
  class CategoriesControllerTest < ActionController::TestCase
@@ -353,13 +353,8 @@ $breed_data.add(Breed.new(3, 'to_delete'))
353
353
  ### OperationsProcessor
354
354
  class CountingActiveRecordOperationsProcessor < ActiveRecordOperationsProcessor
355
355
  after_find_operation do
356
-
357
- count = @operation.resource_klass.find_count(@operation.resource_klass.verify_filters(@operation.filters, @context),
358
- context: @context,
359
- include_directives: @operation.include_directives,
360
- sort_criteria: @operation.sort_criteria)
361
-
362
- @operation_meta[:total_records] = count
356
+ @operation_meta[:total_records] = @operation.record_count
357
+ @operation_links['spec'] = 'https://test_corp.com'
363
358
  end
364
359
  end
365
360
 
@@ -113,7 +113,7 @@ TestApp.routes.draw do
113
113
  jsonapi_link :author, except: [:destroy]
114
114
  end
115
115
 
116
- jsonapi_resource :preferences
116
+ jsonapi_resource :preferences, except: [:create, :destroy]
117
117
 
118
118
  jsonapi_resources :books
119
119
  jsonapi_resources :book_comments
@@ -0,0 +1,206 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+ require 'jsonapi-resources'
3
+
4
+ class OffsetPaginatorTest < ActiveSupport::TestCase
5
+
6
+ def test_offset_default_page_params
7
+ params = ActionController::Parameters.new(
8
+ {
9
+ }
10
+ )
11
+
12
+ paginator = OffsetPaginator.new(params)
13
+
14
+ assert_equal JSONAPI.configuration.default_page_size, paginator.limit
15
+ assert_equal 0, paginator.offset
16
+ end
17
+
18
+ def test_offset_parse_page_params_default_offset
19
+ params = ActionController::Parameters.new(
20
+ {
21
+ limit: 20
22
+ }
23
+ )
24
+
25
+ paginator = OffsetPaginator.new(params)
26
+
27
+ assert_equal 20, paginator.limit
28
+ assert_equal 0, paginator.offset
29
+ end
30
+
31
+ def test_offset_parse_page_params
32
+ params = ActionController::Parameters.new(
33
+ {
34
+ limit: 5,
35
+ offset: 7
36
+ }
37
+ )
38
+
39
+ paginator = OffsetPaginator.new(params)
40
+
41
+ assert_equal 5, paginator.limit
42
+ assert_equal 7, paginator.offset
43
+ end
44
+
45
+ def test_offset_parse_page_params_limit_too_large
46
+ params = ActionController::Parameters.new(
47
+ {
48
+ limit: 50,
49
+ offset: 0
50
+ }
51
+ )
52
+
53
+ assert_raises JSONAPI::Exceptions::InvalidPageValue do
54
+ OffsetPaginator.new(params)
55
+ end
56
+ end
57
+
58
+ def test_offset_parse_page_params_not_allowed
59
+ params = ActionController::Parameters.new(
60
+ {
61
+ limit: 50,
62
+ start: 0
63
+ }
64
+ )
65
+
66
+ assert_raises JSONAPI::Exceptions::PageParametersNotAllowed do
67
+ OffsetPaginator.new(params)
68
+ end
69
+ end
70
+
71
+ def test_offset_parse_page_params_start
72
+ params = ActionController::Parameters.new(
73
+ {
74
+ limit: 5,
75
+ offset: 0
76
+ }
77
+ )
78
+
79
+ paginator = OffsetPaginator.new(params)
80
+
81
+ assert_equal 5, paginator.limit
82
+ assert_equal 0, paginator.offset
83
+ end
84
+
85
+
86
+ def test_offset_links_page_params_large_data_set_start
87
+ params = ActionController::Parameters.new(
88
+ {
89
+ limit: 5,
90
+ offset: 0
91
+ }
92
+ )
93
+
94
+ paginator = OffsetPaginator.new(params)
95
+ links_params = paginator.links_page_params(record_count: 50)
96
+
97
+ assert_equal 3, links_params.size
98
+
99
+ assert_equal 5, links_params['first']['limit']
100
+ assert_equal 0, links_params['first']['offset']
101
+
102
+ assert_equal 5, links_params['next']['limit']
103
+ assert_equal 5, links_params['next']['offset']
104
+
105
+ assert_equal 5, links_params['last']['limit']
106
+ assert_equal 45, links_params['last']['offset']
107
+ end
108
+
109
+ def test_offset_links_page_params_large_data_set_before_start
110
+ params = ActionController::Parameters.new(
111
+ {
112
+ limit: 5,
113
+ offset: 2
114
+ }
115
+ )
116
+
117
+ paginator = OffsetPaginator.new(params)
118
+ links_params = paginator.links_page_params(record_count: 50)
119
+
120
+ assert_equal 4, links_params.size
121
+
122
+ assert_equal 5, links_params['first']['limit']
123
+ assert_equal 0, links_params['first']['offset']
124
+
125
+ assert_equal 5, links_params['previous']['limit']
126
+ assert_equal 0, links_params['previous']['offset']
127
+
128
+ assert_equal 5, links_params['next']['limit']
129
+ assert_equal 7, links_params['next']['offset']
130
+
131
+ assert_equal 5, links_params['last']['limit']
132
+ assert_equal 45, links_params['last']['offset']
133
+ end
134
+
135
+ def test_offset_links_page_params_large_data_set_middle
136
+ params = ActionController::Parameters.new(
137
+ {
138
+ limit: 5,
139
+ offset: 27
140
+ }
141
+ )
142
+
143
+ paginator = OffsetPaginator.new(params)
144
+ links_params = paginator.links_page_params(record_count: 50)
145
+
146
+ assert_equal 4, links_params.size
147
+
148
+ assert_equal 5, links_params['first']['limit']
149
+ assert_equal 0, links_params['first']['offset']
150
+
151
+ assert_equal 5, links_params['previous']['limit']
152
+ assert_equal 22, links_params['previous']['offset']
153
+
154
+ assert_equal 5, links_params['next']['limit']
155
+ assert_equal 32, links_params['next']['offset']
156
+
157
+ assert_equal 5, links_params['last']['limit']
158
+ assert_equal 45, links_params['last']['offset']
159
+ end
160
+
161
+ def test_offset_links_page_params_large_data_set_end
162
+ params = ActionController::Parameters.new(
163
+ {
164
+ limit: 5,
165
+ offset: 45
166
+ }
167
+ )
168
+
169
+ paginator = OffsetPaginator.new(params)
170
+ links_params = paginator.links_page_params(record_count: 50)
171
+
172
+ assert_equal 3, links_params.size
173
+
174
+ assert_equal 5, links_params['first']['limit']
175
+ assert_equal 0, links_params['first']['offset']
176
+
177
+ assert_equal 5, links_params['previous']['limit']
178
+ assert_equal 40, links_params['previous']['offset']
179
+
180
+ assert_equal 5, links_params['last']['limit']
181
+ assert_equal 45, links_params['last']['offset']
182
+ end
183
+
184
+ def test_offset_links_page_params_large_data_set_past_end
185
+ params = ActionController::Parameters.new(
186
+ {
187
+ limit: 5,
188
+ offset: 48
189
+ }
190
+ )
191
+
192
+ paginator = OffsetPaginator.new(params)
193
+ links_params = paginator.links_page_params(record_count: 50)
194
+
195
+ assert_equal 3, links_params.size
196
+
197
+ assert_equal 5, links_params['first']['limit']
198
+ assert_equal 0, links_params['first']['offset']
199
+
200
+ assert_equal 5, links_params['previous']['limit']
201
+ assert_equal 43, links_params['previous']['offset']
202
+
203
+ assert_equal 5, links_params['last']['limit']
204
+ assert_equal 45, links_params['last']['offset']
205
+ end
206
+ end
@@ -0,0 +1,203 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+ require 'jsonapi-resources'
3
+
4
+ class PagedPaginatorTest < ActiveSupport::TestCase
5
+
6
+ def test_paged_default_page_params
7
+ params = ActionController::Parameters.new(
8
+ {
9
+ }
10
+ )
11
+
12
+ paginator = PagedPaginator.new(params)
13
+
14
+ assert_equal JSONAPI.configuration.default_page_size, paginator.size
15
+ assert_equal 1, paginator.number
16
+ end
17
+
18
+ def test_paged_parse_page_params_default_page
19
+ params = ActionController::Parameters.new(
20
+ {
21
+ size: 20
22
+ }
23
+ )
24
+
25
+ paginator = PagedPaginator.new(params)
26
+
27
+ assert_equal 20, paginator.size
28
+ assert_equal 1, paginator.number
29
+ end
30
+
31
+ def test_paged_parse_page_params
32
+ params = ActionController::Parameters.new(
33
+ {
34
+ size: 5,
35
+ number: 7
36
+ }
37
+ )
38
+
39
+ paginator = PagedPaginator.new(params)
40
+
41
+ assert_equal 5, paginator.size
42
+ assert_equal 7, paginator.number
43
+ end
44
+
45
+ def test_paged_parse_page_params_size_too_large
46
+ params = ActionController::Parameters.new(
47
+ {
48
+ size: 50,
49
+ number: 1
50
+ }
51
+ )
52
+
53
+ assert_raises JSONAPI::Exceptions::InvalidPageValue do
54
+ PagedPaginator.new(params)
55
+ end
56
+ end
57
+
58
+ def test_paged_parse_page_params_not_allowed
59
+ params = ActionController::Parameters.new(
60
+ {
61
+ size: 50,
62
+ start: 1
63
+ }
64
+ )
65
+
66
+ assert_raises JSONAPI::Exceptions::PageParametersNotAllowed do
67
+ PagedPaginator.new(params)
68
+ end
69
+ end
70
+
71
+ def test_paged_parse_page_params_start
72
+ params = ActionController::Parameters.new(
73
+ {
74
+ size: 5,
75
+ number: 1
76
+ }
77
+ )
78
+
79
+ paginator = PagedPaginator.new(params)
80
+
81
+ assert_equal 5, paginator.size
82
+ assert_equal 1, paginator.number
83
+ end
84
+
85
+
86
+ def test_paged_links_page_params_large_data_set_start_full_pages
87
+ params = ActionController::Parameters.new(
88
+ {
89
+ size: 5,
90
+ number: 1
91
+ }
92
+ )
93
+
94
+ paginator = PagedPaginator.new(params)
95
+ links_params = paginator.links_page_params(record_count: 50)
96
+
97
+ assert_equal 3, links_params.size
98
+
99
+ assert_equal 5, links_params['first']['size']
100
+ assert_equal 1, links_params['first']['number']
101
+
102
+ assert_equal 5, links_params['next']['size']
103
+ assert_equal 2, links_params['next']['number']
104
+
105
+ assert_equal 5, links_params['last']['size']
106
+ assert_equal 10, links_params['last']['number']
107
+ end
108
+
109
+ def test_paged_links_page_params_large_data_set_start_partial_last
110
+ params = ActionController::Parameters.new(
111
+ {
112
+ size: 5,
113
+ number: 1
114
+ }
115
+ )
116
+
117
+ paginator = PagedPaginator.new(params)
118
+ links_params = paginator.links_page_params(record_count: 51)
119
+
120
+ assert_equal 3, links_params.size
121
+
122
+ assert_equal 5, links_params['first']['size']
123
+ assert_equal 1, links_params['first']['number']
124
+
125
+ assert_equal 5, links_params['next']['size']
126
+ assert_equal 2, links_params['next']['number']
127
+
128
+ assert_equal 5, links_params['last']['size']
129
+ assert_equal 11, links_params['last']['number']
130
+ end
131
+
132
+ def test_paged_links_page_params_large_data_set_middle
133
+ params = ActionController::Parameters.new(
134
+ {
135
+ size: 5,
136
+ number: 4
137
+ }
138
+ )
139
+
140
+ paginator = PagedPaginator.new(params)
141
+ links_params = paginator.links_page_params(record_count: 50)
142
+
143
+ assert_equal 4, links_params.size
144
+
145
+ assert_equal 5, links_params['first']['size']
146
+ assert_equal 1, links_params['first']['number']
147
+
148
+ assert_equal 5, links_params['previous']['size']
149
+ assert_equal 3, links_params['previous']['number']
150
+
151
+ assert_equal 5, links_params['next']['size']
152
+ assert_equal 5, links_params['next']['number']
153
+
154
+ assert_equal 5, links_params['last']['size']
155
+ assert_equal 10, links_params['last']['number']
156
+ end
157
+
158
+ def test_paged_links_page_params_large_data_set_end
159
+ params = ActionController::Parameters.new(
160
+ {
161
+ size: 5,
162
+ number: 10
163
+ }
164
+ )
165
+
166
+ paginator = PagedPaginator.new(params)
167
+ links_params = paginator.links_page_params(record_count: 50)
168
+
169
+ assert_equal 3, links_params.size
170
+
171
+ assert_equal 5, links_params['first']['size']
172
+ assert_equal 1, links_params['first']['number']
173
+
174
+ assert_equal 5, links_params['previous']['size']
175
+ assert_equal 9, links_params['previous']['number']
176
+
177
+ assert_equal 5, links_params['last']['size']
178
+ assert_equal 10, links_params['last']['number']
179
+ end
180
+
181
+ def test_paged_links_page_params_large_data_set_past_end
182
+ params = ActionController::Parameters.new(
183
+ {
184
+ size: 5,
185
+ number: 11
186
+ }
187
+ )
188
+
189
+ paginator = PagedPaginator.new(params)
190
+ links_params = paginator.links_page_params(record_count: 50)
191
+
192
+ assert_equal 3, links_params.size
193
+
194
+ assert_equal 5, links_params['first']['size']
195
+ assert_equal 1, links_params['first']['number']
196
+
197
+ assert_equal 5, links_params['previous']['size']
198
+ assert_equal 10, links_params['previous']['number']
199
+
200
+ assert_equal 5, links_params['last']['size']
201
+ assert_equal 10, links_params['last']['number']
202
+ end
203
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi-resources
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Gebhardt
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-06-10 00:00:00.000000000 Z
12
+ date: 2015-06-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -194,6 +194,8 @@ files:
194
194
  - test/test_helper.rb
195
195
  - test/unit/jsonapi_request/jsonapi_request_test.rb
196
196
  - test/unit/operation/operations_processor_test.rb
197
+ - test/unit/pagination/offset_paginator_test.rb
198
+ - test/unit/pagination/paged_paginator_test.rb
197
199
  - test/unit/resource/resource_test.rb
198
200
  - test/unit/serializer/include_directives_test.rb
199
201
  - test/unit/serializer/response_document_test.rb
@@ -254,6 +256,8 @@ test_files:
254
256
  - test/test_helper.rb
255
257
  - test/unit/jsonapi_request/jsonapi_request_test.rb
256
258
  - test/unit/operation/operations_processor_test.rb
259
+ - test/unit/pagination/offset_paginator_test.rb
260
+ - test/unit/pagination/paged_paginator_test.rb
257
261
  - test/unit/resource/resource_test.rb
258
262
  - test/unit/serializer/include_directives_test.rb
259
263
  - test/unit/serializer/response_document_test.rb