jsonapi-resources 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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