onsi 1.3.1 → 2.0.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 +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +1 -0
- data/lib/onsi.rb +1 -0
- data/lib/onsi/error_responder.rb +13 -0
- data/lib/onsi/errors.rb +8 -0
- data/lib/onsi/model.rb +28 -0
- data/lib/onsi/paginate.rb +83 -0
- data/lib/onsi/resource.rb +6 -0
- data/lib/onsi/version.rb +1 -1
- data/onsi.gemspec +9 -9
- metadata +35 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 866068b856dc9ce02d03c655448053a23e776388fdfa7569576411c8c92b01a4
|
4
|
+
data.tar.gz: 4c1eb3d324d81f30bf394120d3baf6822d83fa7e2b0ca1bc6124081ed71fb9ac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef0a1ee5e326bc2bfa9769882143be56d27b1bf0811d81aa0fce1a26a7c5df4c49d56961f84d1ce82c1c2dbe4e9afd06efab0bf6408940410c12ed2fa5cb46a1
|
7
|
+
data.tar.gz: 0201c618fcc64b69801ed66ff2fd85bea5f912027b53437aa65ffd7b83d67a8c8c111443b3481eee328c6d8e0b592df217886bab0da2d8291f22a5f4f085bbae
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## Version 2.0.0
|
4
|
+
|
5
|
+
### unreleased
|
6
|
+
|
7
|
+
- Added pagination support
|
8
|
+
|
9
|
+
- Fix: Relationships without a valid value now render a `nil` data structure. This is a breaking change. To keep the old behavior you can use `legacy_relationship_render!`
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
api_render(:v1) do
|
13
|
+
legacy_relationship_render!
|
14
|
+
end
|
15
|
+
```
|
16
|
+
|
3
17
|
## Version 1.3.0
|
4
18
|
|
5
19
|
### Released March 19, 2019
|
data/README.md
CHANGED
data/lib/onsi.rb
CHANGED
data/lib/onsi/error_responder.rb
CHANGED
@@ -34,6 +34,7 @@ module Onsi
|
|
34
34
|
rescue_from Onsi::Params::RelationshipNotFound, with: :respond_missing_relationship_error_400
|
35
35
|
rescue_from Onsi::Errors::UnknownVersionError, with: :respond_invalid_version_error_400
|
36
36
|
rescue_from Onsi::Errors::IncludedParamError, with: :respond_included_param_error_400
|
37
|
+
rescue_from Onsi::Errors::PaginationError, with: :respond_pagination_error_400
|
37
38
|
end
|
38
39
|
|
39
40
|
##
|
@@ -154,6 +155,18 @@ module Onsi
|
|
154
155
|
render_error(response)
|
155
156
|
end
|
156
157
|
|
158
|
+
##
|
159
|
+
# @private
|
160
|
+
def respond_pagination_error_400(error)
|
161
|
+
response = ErrorResponse.new(400)
|
162
|
+
response.add(
|
163
|
+
400,
|
164
|
+
'pagination_error',
|
165
|
+
details: error.message
|
166
|
+
)
|
167
|
+
render_error(response)
|
168
|
+
end
|
169
|
+
|
157
170
|
private
|
158
171
|
|
159
172
|
def error_metadata(error)
|
data/lib/onsi/errors.rb
CHANGED
data/lib/onsi/model.rb
CHANGED
@@ -204,6 +204,10 @@ module Onsi
|
|
204
204
|
end
|
205
205
|
end
|
206
206
|
|
207
|
+
def legacy_relationship_render!
|
208
|
+
@legacy_relationship_render = true
|
209
|
+
end
|
210
|
+
|
207
211
|
private
|
208
212
|
|
209
213
|
def render_relationship_entry(object, key, value, rels)
|
@@ -224,6 +228,30 @@ module Onsi
|
|
224
228
|
end
|
225
229
|
|
226
230
|
def format_relationship(relationship, value)
|
231
|
+
if @legacy_relationship_render == true
|
232
|
+
return legacy_format_relationship(relationship, value)
|
233
|
+
end
|
234
|
+
|
235
|
+
case relationship
|
236
|
+
when Enumerable
|
237
|
+
if relationship.empty?
|
238
|
+
return []
|
239
|
+
end
|
240
|
+
|
241
|
+
relationship.map { |v| { 'type' => value[:type].to_s, 'id' => v.to_s } }
|
242
|
+
else
|
243
|
+
unless relationship.to_s.present?
|
244
|
+
return nil
|
245
|
+
end
|
246
|
+
|
247
|
+
{
|
248
|
+
'type' => value[:type].to_s,
|
249
|
+
'id' => relationship.to_s
|
250
|
+
}
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def legacy_format_relationship(relationship, value)
|
227
255
|
case relationship
|
228
256
|
when Array
|
229
257
|
relationship.map { |v| { 'type' => value[:type].to_s, 'id' => v.to_s } }
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require_relative 'errors'
|
2
|
+
|
3
|
+
module Onsi
|
4
|
+
##
|
5
|
+
# Pagination handles cursor pagination.
|
6
|
+
#
|
7
|
+
# It handles setting up a cursor and ordering the query. The next cursor will be added to the
|
8
|
+
# response's meta object.
|
9
|
+
#
|
10
|
+
# @example Controller Action
|
11
|
+
# def index
|
12
|
+
# render_resource(Onsi::Paginate.perform(person.messages, 'messages', params))
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# @author Maddie Schipper
|
16
|
+
# @since 1.4.0
|
17
|
+
class Paginate
|
18
|
+
Result = Struct.new(:query, :params)
|
19
|
+
|
20
|
+
class << self
|
21
|
+
##
|
22
|
+
# Modify the query based on the pagination options
|
23
|
+
#
|
24
|
+
# @param query [#reorder, #limit, #where, #last] The query to modify
|
25
|
+
#
|
26
|
+
# @param type [#to_s] The type of the pagination. This us used to verify the cursor
|
27
|
+
#
|
28
|
+
# @param params [#fetch] The request params.
|
29
|
+
#
|
30
|
+
# @return [Onsi::Paginate::Result]
|
31
|
+
def perform(query, type, params, options = {})
|
32
|
+
cursor_type = type.to_s
|
33
|
+
cursor_param = options.fetch(:cursor_param, :cursor)
|
34
|
+
max_per_page = options.fetch(:max_per_page, 100)
|
35
|
+
per_page_param = options.fetch(:per_page_param, :per_page)
|
36
|
+
cursor_generator = options.fetch(:cursor, lambda { |query, type| Paginate.cursor_for_query(query, type) })
|
37
|
+
cursor_offset = options.fetch(:offset, lambda { |query, type, cursor| Paginate.cursor_offset(query, type, cursor) })
|
38
|
+
order_by = options.fetch(:order_by, id: :asc)
|
39
|
+
|
40
|
+
per_page = params.fetch(per_page_param, 25).to_i
|
41
|
+
raise Onsi::Errors::PaginationError, "too many objects per page, max #{max_per_page}" if per_page > max_per_page
|
42
|
+
|
43
|
+
query = query.reorder(order_by)
|
44
|
+
query = query.limit(per_page)
|
45
|
+
query = cursor_offset.call(query, cursor_type, params.fetch(cursor_param)) if params.fetch(cursor_param, nil).present?
|
46
|
+
|
47
|
+
response_params = {}.tap do |rp|
|
48
|
+
rp[per_page_param] = per_page
|
49
|
+
value = cursor_generator.call(query, cursor_type)
|
50
|
+
rp[cursor_param] = value unless value.nil?
|
51
|
+
end
|
52
|
+
|
53
|
+
Result.new(query, response_params)
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# @private
|
58
|
+
def cursor_for_query(query, type)
|
59
|
+
obj = query.last
|
60
|
+
|
61
|
+
return nil if obj.nil?
|
62
|
+
|
63
|
+
Base64.strict_encode64([
|
64
|
+
type.to_s,
|
65
|
+
obj.id.to_s
|
66
|
+
].join(':'))
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# @private
|
71
|
+
def cursor_offset(query, cursor_type, cursor)
|
72
|
+
type, id = Base64.strict_decode64(cursor).split(':', 2)
|
73
|
+
raise Onsi::Errors::PaginationError, 'invalid cursor type' unless cursor_type.to_s == type
|
74
|
+
|
75
|
+
query.where(id: (id.to_i + 1)...Float::INFINITY)
|
76
|
+
rescue ArgumentError => e
|
77
|
+
raise e if e.message.downcase != 'invalid base64'
|
78
|
+
|
79
|
+
raise Onsi::Errors::PaginationError, 'invalid cursor format'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/onsi/resource.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require_relative 'errors'
|
2
|
+
require_relative 'paginate'
|
2
3
|
|
3
4
|
module Onsi
|
4
5
|
##
|
@@ -71,6 +72,8 @@ module Onsi
|
|
71
72
|
case resource
|
72
73
|
when Onsi::Resource
|
73
74
|
resource
|
75
|
+
when Onsi::Paginate::Result
|
76
|
+
as_resource(resource.query, version)
|
74
77
|
when Enumerable
|
75
78
|
resource.map { |res| as_resource(res, version) }
|
76
79
|
else
|
@@ -97,6 +100,9 @@ module Onsi
|
|
97
100
|
end
|
98
101
|
root[META_KEY] = {}.tap do |meta|
|
99
102
|
meta[:count] = resources.count if resources.respond_to?(:count)
|
103
|
+
if resource.is_a?(Onsi::Paginate::Result)
|
104
|
+
meta[:pagination] = resource.params
|
105
|
+
end
|
100
106
|
end
|
101
107
|
end
|
102
108
|
end
|
data/lib/onsi/version.rb
CHANGED
data/onsi.gemspec
CHANGED
@@ -23,14 +23,14 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.required_ruby_version = '>= 2.3'
|
24
24
|
|
25
25
|
spec.add_dependency 'addressable', '>= 2.5', '< 3.0'
|
26
|
-
spec.add_dependency 'rails', '>= 5.0', '<
|
26
|
+
spec.add_dependency 'rails', '>= 5.0', '< 7.0'
|
27
27
|
|
28
|
-
spec.add_development_dependency 'bundler'
|
29
|
-
spec.add_development_dependency 'database_cleaner'
|
30
|
-
spec.add_development_dependency 'pry'
|
31
|
-
spec.add_development_dependency 'rake'
|
32
|
-
spec.add_development_dependency 'rspec-rails'
|
33
|
-
spec.add_development_dependency 'simplecov',
|
34
|
-
spec.add_development_dependency 'sqlite3'
|
35
|
-
spec.add_development_dependency 'yard'
|
28
|
+
spec.add_development_dependency 'bundler'
|
29
|
+
spec.add_development_dependency 'database_cleaner'
|
30
|
+
spec.add_development_dependency 'pry'
|
31
|
+
spec.add_development_dependency 'rake'
|
32
|
+
spec.add_development_dependency 'rspec-rails'
|
33
|
+
spec.add_development_dependency 'simplecov', '< 0.18' # >= .18 breaks the test reporter
|
34
|
+
spec.add_development_dependency 'sqlite3'
|
35
|
+
spec.add_development_dependency 'yard'
|
36
36
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: onsi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maddie Schipper
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-03-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
version: '5.0'
|
40
40
|
- - "<"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: '
|
42
|
+
version: '7.0'
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -49,125 +49,119 @@ dependencies:
|
|
49
49
|
version: '5.0'
|
50
50
|
- - "<"
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: '
|
52
|
+
version: '7.0'
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: bundler
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
56
56
|
requirements:
|
57
57
|
- - ">="
|
58
58
|
- !ruby/object:Gem::Version
|
59
|
-
version: '
|
60
|
-
- - "<"
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: '3.0'
|
59
|
+
version: '0'
|
63
60
|
type: :development
|
64
61
|
prerelease: false
|
65
62
|
version_requirements: !ruby/object:Gem::Requirement
|
66
63
|
requirements:
|
67
64
|
- - ">="
|
68
65
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
70
|
-
- - "<"
|
71
|
-
- !ruby/object:Gem::Version
|
72
|
-
version: '3.0'
|
66
|
+
version: '0'
|
73
67
|
- !ruby/object:Gem::Dependency
|
74
68
|
name: database_cleaner
|
75
69
|
requirement: !ruby/object:Gem::Requirement
|
76
70
|
requirements:
|
77
|
-
- - "
|
71
|
+
- - ">="
|
78
72
|
- !ruby/object:Gem::Version
|
79
|
-
version:
|
73
|
+
version: '0'
|
80
74
|
type: :development
|
81
75
|
prerelease: false
|
82
76
|
version_requirements: !ruby/object:Gem::Requirement
|
83
77
|
requirements:
|
84
|
-
- - "
|
78
|
+
- - ">="
|
85
79
|
- !ruby/object:Gem::Version
|
86
|
-
version:
|
80
|
+
version: '0'
|
87
81
|
- !ruby/object:Gem::Dependency
|
88
82
|
name: pry
|
89
83
|
requirement: !ruby/object:Gem::Requirement
|
90
84
|
requirements:
|
91
|
-
- - "
|
85
|
+
- - ">="
|
92
86
|
- !ruby/object:Gem::Version
|
93
|
-
version: 0
|
87
|
+
version: '0'
|
94
88
|
type: :development
|
95
89
|
prerelease: false
|
96
90
|
version_requirements: !ruby/object:Gem::Requirement
|
97
91
|
requirements:
|
98
|
-
- - "
|
92
|
+
- - ">="
|
99
93
|
- !ruby/object:Gem::Version
|
100
|
-
version: 0
|
94
|
+
version: '0'
|
101
95
|
- !ruby/object:Gem::Dependency
|
102
96
|
name: rake
|
103
97
|
requirement: !ruby/object:Gem::Requirement
|
104
98
|
requirements:
|
105
|
-
- - "
|
99
|
+
- - ">="
|
106
100
|
- !ruby/object:Gem::Version
|
107
|
-
version: '
|
101
|
+
version: '0'
|
108
102
|
type: :development
|
109
103
|
prerelease: false
|
110
104
|
version_requirements: !ruby/object:Gem::Requirement
|
111
105
|
requirements:
|
112
|
-
- - "
|
106
|
+
- - ">="
|
113
107
|
- !ruby/object:Gem::Version
|
114
|
-
version: '
|
108
|
+
version: '0'
|
115
109
|
- !ruby/object:Gem::Dependency
|
116
110
|
name: rspec-rails
|
117
111
|
requirement: !ruby/object:Gem::Requirement
|
118
112
|
requirements:
|
119
|
-
- - "
|
113
|
+
- - ">="
|
120
114
|
- !ruby/object:Gem::Version
|
121
|
-
version:
|
115
|
+
version: '0'
|
122
116
|
type: :development
|
123
117
|
prerelease: false
|
124
118
|
version_requirements: !ruby/object:Gem::Requirement
|
125
119
|
requirements:
|
126
|
-
- - "
|
120
|
+
- - ">="
|
127
121
|
- !ruby/object:Gem::Version
|
128
|
-
version:
|
122
|
+
version: '0'
|
129
123
|
- !ruby/object:Gem::Dependency
|
130
124
|
name: simplecov
|
131
125
|
requirement: !ruby/object:Gem::Requirement
|
132
126
|
requirements:
|
133
|
-
- - "
|
127
|
+
- - "<"
|
134
128
|
- !ruby/object:Gem::Version
|
135
|
-
version: '0.
|
129
|
+
version: '0.18'
|
136
130
|
type: :development
|
137
131
|
prerelease: false
|
138
132
|
version_requirements: !ruby/object:Gem::Requirement
|
139
133
|
requirements:
|
140
|
-
- - "
|
134
|
+
- - "<"
|
141
135
|
- !ruby/object:Gem::Version
|
142
|
-
version: '0.
|
136
|
+
version: '0.18'
|
143
137
|
- !ruby/object:Gem::Dependency
|
144
138
|
name: sqlite3
|
145
139
|
requirement: !ruby/object:Gem::Requirement
|
146
140
|
requirements:
|
147
|
-
- - "
|
141
|
+
- - ">="
|
148
142
|
- !ruby/object:Gem::Version
|
149
|
-
version:
|
143
|
+
version: '0'
|
150
144
|
type: :development
|
151
145
|
prerelease: false
|
152
146
|
version_requirements: !ruby/object:Gem::Requirement
|
153
147
|
requirements:
|
154
|
-
- - "
|
148
|
+
- - ">="
|
155
149
|
- !ruby/object:Gem::Version
|
156
|
-
version:
|
150
|
+
version: '0'
|
157
151
|
- !ruby/object:Gem::Dependency
|
158
152
|
name: yard
|
159
153
|
requirement: !ruby/object:Gem::Requirement
|
160
154
|
requirements:
|
161
|
-
- - "
|
155
|
+
- - ">="
|
162
156
|
- !ruby/object:Gem::Version
|
163
|
-
version: 0
|
157
|
+
version: '0'
|
164
158
|
type: :development
|
165
159
|
prerelease: false
|
166
160
|
version_requirements: !ruby/object:Gem::Requirement
|
167
161
|
requirements:
|
168
|
-
- - "
|
162
|
+
- - ">="
|
169
163
|
- !ruby/object:Gem::Version
|
170
|
-
version: 0
|
164
|
+
version: '0'
|
171
165
|
description: Format JSON API responses and parse inbound requests.
|
172
166
|
email:
|
173
167
|
- me@maddiesch.com
|
@@ -202,6 +196,7 @@ files:
|
|
202
196
|
- lib/onsi/middleware.rb
|
203
197
|
- lib/onsi/middleware/cors_headers.rb
|
204
198
|
- lib/onsi/model.rb
|
199
|
+
- lib/onsi/paginate.rb
|
205
200
|
- lib/onsi/params.rb
|
206
201
|
- lib/onsi/params_parse_operation.rb
|
207
202
|
- lib/onsi/params_parser.rb
|