rom-http 0.4.0 → 0.5.0
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/.travis.yml +2 -2
- data/CHANGELOG.md +8 -0
- data/Gemfile +3 -0
- data/README.md +42 -8
- data/lib/rom/http/commands/create.rb +6 -0
- data/lib/rom/http/commands/delete.rb +6 -0
- data/lib/rom/http/commands/update.rb +6 -0
- data/lib/rom/http/dataset.rb +195 -0
- data/lib/rom/http/dataset/response_transformers/schemad.rb +9 -16
- data/lib/rom/http/gateway.rb +40 -0
- data/lib/rom/http/relation.rb +16 -5
- data/lib/rom/http/version.rb +1 -1
- data/spec/integration/abstract/relation_spec.rb +34 -7
- data/spec/spec_helper.rb +4 -0
- data/spec/unit/rom/http/dataset/response_transformers/schemad_spec.rb +13 -20
- data/spec/unit/rom/http/relation_spec.rb +1 -1
- metadata +3 -7
- data/lib/rom/plugins/relation/schema.rb +0 -53
- data/spec/unit/rom/plugins/relation/schema/schema_spec.rb +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 940c73eee8219c8b80aa2ec5914549291be5e99d
|
4
|
+
data.tar.gz: 0e852b96a95edb10991aefa9d5bcffa78e5211b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3db2d4a662ae4ae76138119946b71253e36e0be5653fda789a17083f6915f7630357b0680e297690c56fab85da363ffaee1cc03412d568b2c16bd61421f080db
|
7
|
+
data.tar.gz: 8738e9b3524917c5e74535a2ae6b1ef9e23c82a98871fac7079f507321e40da86185a811f54f1b47468b9b6a56a485891c86f5377f15d13c7246f86703c41fbb
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
# v0.5.0 2016-08-08
|
2
|
+
### Changed
|
3
|
+
- Removed ruby 2.0 support
|
4
|
+
- Use `schema` API from ROM::Core. Replaces old schema (solnic)
|
5
|
+
- Now works out of the box with `rom-repository` (solnic)
|
6
|
+
|
7
|
+
[Compare v0.4.0...v0.5.0](https://github.com/rom-rb/rom-http/compare/v0.4.0...v0.5.0)
|
8
|
+
|
1
9
|
# v0.4.0 2016-04-30
|
2
10
|
### Changed
|
3
11
|
- updated to depend on the forthcoming rom 2.0 (cflipse)
|
data/Gemfile
CHANGED
@@ -2,6 +2,8 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
+
gem 'rom-repository', github: 'rom-rb/rom-repository', branch: 'master'
|
6
|
+
|
5
7
|
group :test do
|
6
8
|
gem 'rom', github: 'rom-rb/rom', branch: 'master'
|
7
9
|
gem 'rom-support', github: 'rom-rb/rom-support', branch: 'master'
|
@@ -10,6 +12,7 @@ group :test do
|
|
10
12
|
end
|
11
13
|
|
12
14
|
group :tools do
|
15
|
+
gem 'byebug'
|
13
16
|
gem 'guard'
|
14
17
|
gem 'guard-rspec'
|
15
18
|
gem 'guard-rubocop'
|
data/README.md
CHANGED
@@ -1,14 +1,48 @@
|
|
1
|
-
|
1
|
+
[gem]: https://rubygems.org/gems/rom-http
|
2
|
+
[travis]: https://travis-ci.org/rom-rb/rom-http
|
3
|
+
[gemnasium]: https://gemnasium.com/rom-rb/rom-http
|
4
|
+
[codeclimate]: https://codeclimate.com/github/rom-rb/rom-http
|
5
|
+
[inchpages]: http://inch-ci.org/github/rom-rb/rom-http
|
6
|
+
[gitter]: https://gitter.im/rom-rb/chat
|
7
|
+
[rom]: https://github.com/rom-rb/rom
|
2
8
|
|
3
|
-
<a href="https://rubygems.org/gems/rom-http" target="_blank"></a>
|
4
|
-
<a href="https://travis-ci.org/rom-rb/rom-http" target="_blank"></a>
|
5
|
-
<a href="https://gemnasium.com/rom-rb/rom-http" target="_blank"></a>
|
6
|
-
<a href="https://codeclimate.com/github/rom-rb/rom-http" target="_blank"></a>
|
7
|
-
<a href="http://inch-ci.org/github/rom-rb/rom-http" target="_blank"></a>
|
8
9
|
|
9
|
-
|
10
|
+
# ROM-http [][gitter]
|
10
11
|
|
11
|
-
|
12
|
+
[][gem]
|
13
|
+
[][travis]
|
14
|
+
[][gemnasium]
|
15
|
+
[][codeclimate]
|
16
|
+
[][inchpages]
|
17
|
+
|
18
|
+
HTTP adapter for [Ruby Object Mapper][rom]
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
Add this line to your application's Gemfile:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
gem 'rom-http'
|
26
|
+
```
|
27
|
+
|
28
|
+
And then execute:
|
29
|
+
|
30
|
+
$ bundle
|
31
|
+
|
32
|
+
Or install it yourself as:
|
33
|
+
|
34
|
+
$ gem install rom-http
|
35
|
+
|
36
|
+
## ROADMAP
|
37
|
+
|
38
|
+
For details please refer to [issues](https://github.com/rom-rb/rom-http/issues).
|
39
|
+
|
40
|
+
|
41
|
+
## License
|
42
|
+
|
43
|
+
See `LICENSE` file.
|
44
|
+
|
45
|
+
## Synopsis
|
12
46
|
|
13
47
|
```ruby
|
14
48
|
require 'json'
|
@@ -1,9 +1,15 @@
|
|
1
1
|
module ROM
|
2
2
|
module HTTP
|
3
3
|
module Commands
|
4
|
+
# HTTP Create command
|
5
|
+
#
|
6
|
+
# @api public
|
4
7
|
class Create < ROM::Commands::Create
|
5
8
|
adapter :http
|
6
9
|
|
10
|
+
# Submits each of the provided tuples over HTTP post
|
11
|
+
#
|
12
|
+
# @api public
|
7
13
|
def execute(tuples)
|
8
14
|
Array([tuples]).flatten.map do |tuple|
|
9
15
|
attributes = input[tuple]
|
@@ -1,9 +1,15 @@
|
|
1
1
|
module ROM
|
2
2
|
module HTTP
|
3
3
|
module Commands
|
4
|
+
# HTTP Delete command
|
5
|
+
#
|
6
|
+
# @api public
|
4
7
|
class Delete < ROM::Commands::Delete
|
5
8
|
adapter :http
|
6
9
|
|
10
|
+
# Sends an HTTP delete to the dataset path
|
11
|
+
#
|
12
|
+
# @api public
|
7
13
|
def execute
|
8
14
|
relation.delete
|
9
15
|
end
|
@@ -1,9 +1,15 @@
|
|
1
1
|
module ROM
|
2
2
|
module HTTP
|
3
3
|
module Commands
|
4
|
+
# HTTP update command
|
5
|
+
#
|
6
|
+
# @api public
|
4
7
|
class Update < ROM::Commands::Update
|
5
8
|
adapter :http
|
6
9
|
|
10
|
+
# Submits each of the provided tuples via HTTP put
|
11
|
+
#
|
12
|
+
# @api public
|
7
13
|
def execute(tuples)
|
8
14
|
Array([tuples]).flatten.map do |tuple|
|
9
15
|
attributes = input[tuple]
|
data/lib/rom/http/dataset.rb
CHANGED
@@ -3,6 +3,11 @@ require 'rom/http/dataset/response_transformers/schemaless'
|
|
3
3
|
|
4
4
|
module ROM
|
5
5
|
module HTTP
|
6
|
+
# HTTP Dataset
|
7
|
+
#
|
8
|
+
# Represents a specific HTTP collection resource
|
9
|
+
#
|
10
|
+
# @api public
|
6
11
|
class Dataset
|
7
12
|
include Enumerable
|
8
13
|
include Dry::Equalizer(:config, :options)
|
@@ -28,49 +33,162 @@ module ROM
|
|
28
33
|
end
|
29
34
|
end
|
30
35
|
|
36
|
+
|
37
|
+
# HTTP Dataset interface
|
38
|
+
#
|
39
|
+
# @param [Hash] config the Gateway's HTTP server configuration
|
40
|
+
#
|
41
|
+
# @param [Hash] options dataset configuration options
|
42
|
+
# @option options [Symbol] :request_method (:get) The HTTP verb to use
|
43
|
+
# @option options [Array] :projections ([]) Keys to select from response tuple
|
44
|
+
# @option options [String] :path ('') URI request path
|
45
|
+
# @option options [Hash] :headers ({}) Additional request headers
|
46
|
+
# @option options [Hash] :params ({}) HTTP request parameters
|
47
|
+
#
|
48
|
+
# @api public
|
31
49
|
def initialize(config, options = {})
|
32
50
|
@config = config
|
33
51
|
@response_transformer = ResponseTransformers::Schemaless.new
|
34
52
|
super(options)
|
35
53
|
end
|
36
54
|
|
55
|
+
# @overload response_transformer
|
56
|
+
# Return the current response transformer
|
57
|
+
#
|
58
|
+
# @overload response_transformer(transformer)
|
59
|
+
# Set a new response transformer
|
60
|
+
#
|
61
|
+
# @param transformer [#call] The new response transformer
|
62
|
+
#
|
63
|
+
# @api private
|
37
64
|
def response_transformer(transformer = Undefined)
|
38
65
|
return @response_transformer if Undefined === transformer
|
39
66
|
@response_transformer = transformer
|
40
67
|
end
|
41
68
|
|
69
|
+
# Return the gateway's URI
|
70
|
+
#
|
71
|
+
# @return [String]
|
72
|
+
#
|
73
|
+
# @raise [Error] if the configuration does not contain a URI
|
74
|
+
#
|
75
|
+
# @api public
|
42
76
|
def uri
|
43
77
|
config.fetch(:uri) { fail Error, ':uri configuration missing' }
|
44
78
|
end
|
45
79
|
|
80
|
+
# Return request headers
|
81
|
+
#
|
82
|
+
# Merges default headers from the Gateway configuration and the
|
83
|
+
# current Dataset
|
84
|
+
#
|
85
|
+
# @example
|
86
|
+
# config = { Accepts: 'application/json' }
|
87
|
+
# users = Dataset.new(config, headers: { 'Cache-Control': 'no-cache' }
|
88
|
+
# users.headers
|
89
|
+
# # => {:Accepts => "application/json", :'Cache-Control' => 'no-cache'}
|
90
|
+
#
|
91
|
+
# @return [Hash]
|
92
|
+
#
|
93
|
+
# @api public
|
46
94
|
def headers
|
47
95
|
config.fetch(:headers, {}).merge(options.fetch(:headers, {}))
|
48
96
|
end
|
49
97
|
|
98
|
+
# Return the dataset name
|
99
|
+
#
|
100
|
+
# @return [String]
|
101
|
+
#
|
102
|
+
# @api public
|
50
103
|
def name
|
51
104
|
config[:name].to_s
|
52
105
|
end
|
53
106
|
|
107
|
+
# Return the dataset path
|
108
|
+
#
|
109
|
+
# @example
|
110
|
+
# Dataset.new(config, path: '/users').path
|
111
|
+
# # => 'users'
|
112
|
+
#
|
113
|
+
# @return [String] the dataset path, without a leading slash
|
114
|
+
#
|
115
|
+
# @api public
|
54
116
|
def path
|
55
117
|
options[:path].to_s.sub(%r{\A/}, '')
|
56
118
|
end
|
57
119
|
|
120
|
+
# Return the dataset path
|
121
|
+
#
|
122
|
+
# @example
|
123
|
+
# Dataset.new(config, path: '/users').path
|
124
|
+
# # => '/users'
|
125
|
+
#
|
126
|
+
# @return [string] the dataset path, with leading slash
|
127
|
+
#
|
128
|
+
# @api public
|
58
129
|
def absolute_path
|
59
130
|
'/' + path
|
60
131
|
end
|
61
132
|
|
133
|
+
# Return a new dataset with given headers
|
134
|
+
#
|
135
|
+
# @param headers [Hash] The new headers
|
136
|
+
#
|
137
|
+
# @note this _replaces_ the dataset's currently configured headers.
|
138
|
+
# To non-destructively add a new header, use `#add_header`
|
139
|
+
#
|
140
|
+
# @example
|
141
|
+
# users = Dataset.new(config, headers: { Accept: 'application/json' })
|
142
|
+
# users.with_headers(:'X-Api-Key' => '1234').headers
|
143
|
+
# # => { :'X-Api-Key' => '1234' }
|
144
|
+
#
|
145
|
+
# @return [Dataset]
|
146
|
+
#
|
147
|
+
# @api public
|
62
148
|
def with_headers(headers)
|
63
149
|
__new__(config, options.merge(headers: headers))
|
64
150
|
end
|
65
151
|
|
152
|
+
# Return a new dataset with additional header
|
153
|
+
#
|
154
|
+
# @param header [Symbol] the HTTP header to add
|
155
|
+
# @param value [String] the header value
|
156
|
+
#
|
157
|
+
# @example
|
158
|
+
# users = Dataset.new(config, headers: { Accept: 'application/json' })
|
159
|
+
# users.add_header(:'X-Api-Key', '1234').headers
|
160
|
+
# # => { :Accept => 'application/json', :'X-Api-Key' => '1234' }
|
161
|
+
#
|
162
|
+
# @return [Dataset]
|
163
|
+
#
|
164
|
+
# @api public
|
66
165
|
def add_header(header, value)
|
67
166
|
with_headers(headers.merge(header => value))
|
68
167
|
end
|
69
168
|
|
169
|
+
# Return a new dataset with additional options
|
170
|
+
#
|
171
|
+
# @param opts [Hash] the new options to add
|
172
|
+
#
|
173
|
+
# @return [Dataset]
|
174
|
+
#
|
175
|
+
# @api public
|
70
176
|
def with_options(opts)
|
71
177
|
__new__(config, options.merge(opts))
|
72
178
|
end
|
73
179
|
|
180
|
+
# Add a new set projection to the result set
|
181
|
+
#
|
182
|
+
# @param [Array, *args] projections the keys to add to the projections
|
183
|
+
#
|
184
|
+
# @example
|
185
|
+
# users = Dataset.new(config, projections: [:login])
|
186
|
+
# users.project(:email, :name).projections
|
187
|
+
# # => [:login, :email, :name]
|
188
|
+
#
|
189
|
+
# @return [Dataset]
|
190
|
+
#
|
191
|
+
# @api public
|
74
192
|
def project(*args)
|
75
193
|
projections = args.first.is_a?(::Array) ? args.first : args
|
76
194
|
|
@@ -79,27 +197,86 @@ module ROM
|
|
79
197
|
)
|
80
198
|
end
|
81
199
|
|
200
|
+
# Return a new dataset with a different path
|
201
|
+
#
|
202
|
+
# @param path [String] the new request path
|
203
|
+
#
|
204
|
+
# @example
|
205
|
+
# users.with_path('/profiles').path
|
206
|
+
# # => 'profiles'
|
207
|
+
#
|
208
|
+
# @return [Dataset]
|
209
|
+
#
|
210
|
+
# @api public
|
82
211
|
def with_path(path)
|
83
212
|
with_options(path: path)
|
84
213
|
end
|
85
214
|
|
215
|
+
# Return a new dataset with a modified path
|
216
|
+
#
|
217
|
+
# @param path [String] new path fragment
|
218
|
+
#
|
219
|
+
# @example
|
220
|
+
# users.append_path('profiles').path
|
221
|
+
# # => users/profiles
|
222
|
+
#
|
223
|
+
# @return [Dataset]
|
224
|
+
#
|
225
|
+
# @api public
|
86
226
|
def append_path(path)
|
87
227
|
with_options(path: options[:path] + '/' + path)
|
88
228
|
end
|
89
229
|
|
230
|
+
# Return a new dataset with a different request method
|
231
|
+
#
|
232
|
+
# @param [Symbol] request_method the new HTTP verb
|
233
|
+
#
|
234
|
+
# @example
|
235
|
+
# users.request_method(:put)
|
236
|
+
#
|
237
|
+
# @return [Dataset]
|
238
|
+
#
|
239
|
+
# @api public
|
90
240
|
def with_request_method(request_method)
|
91
241
|
with_options(request_method: request_method)
|
92
242
|
end
|
93
243
|
|
244
|
+
# Return a new dataset with replaced request parameters
|
245
|
+
#
|
246
|
+
# @param [Hash] params the new request parameters
|
247
|
+
#
|
248
|
+
# @example
|
249
|
+
# users = Dataset.new(config, params: { uid: 33 })
|
250
|
+
# users.with_params(login: 'jdoe').params
|
251
|
+
# # => { :login => 'jdoe' }
|
252
|
+
#
|
253
|
+
# @return [Dataset]
|
254
|
+
#
|
255
|
+
# @api public
|
94
256
|
def with_params(params)
|
95
257
|
with_options(params: params)
|
96
258
|
end
|
97
259
|
|
260
|
+
# Iterate over each response value
|
261
|
+
#
|
262
|
+
# @yield [Hash] a dataset tuple
|
263
|
+
#
|
264
|
+
# @return [Enumerator] if no block is given
|
265
|
+
# @return [Array<Hash>]
|
266
|
+
#
|
267
|
+
# @api public
|
98
268
|
def each(&block)
|
99
269
|
return to_enum unless block_given?
|
100
270
|
response.each(&block)
|
101
271
|
end
|
102
272
|
|
273
|
+
# Perform an insert over HTTP Post
|
274
|
+
#
|
275
|
+
# @params [Hash] params The request parameters to send
|
276
|
+
#
|
277
|
+
# @return [Array<Hash>]
|
278
|
+
#
|
279
|
+
# @api public
|
103
280
|
def insert(params)
|
104
281
|
with_options(
|
105
282
|
request_method: :post,
|
@@ -107,6 +284,13 @@ module ROM
|
|
107
284
|
).response
|
108
285
|
end
|
109
286
|
|
287
|
+
# Perform an update over HTTP Put
|
288
|
+
#
|
289
|
+
# @params [Hash] params The request parameters to send
|
290
|
+
#
|
291
|
+
# @return [Array<Hash>]
|
292
|
+
#
|
293
|
+
# @api public
|
110
294
|
def update(params)
|
111
295
|
with_options(
|
112
296
|
request_method: :put,
|
@@ -114,12 +298,23 @@ module ROM
|
|
114
298
|
).response
|
115
299
|
end
|
116
300
|
|
301
|
+
# Perform an delete over HTTP Delete
|
302
|
+
#
|
303
|
+
#
|
304
|
+
# @return [Array<Hash>]
|
305
|
+
#
|
306
|
+
# @api public
|
117
307
|
def delete
|
118
308
|
with_options(
|
119
309
|
request_method: :delete
|
120
310
|
).response
|
121
311
|
end
|
122
312
|
|
313
|
+
# Execute the current dataset
|
314
|
+
#
|
315
|
+
# @return [Array<hash>]
|
316
|
+
#
|
317
|
+
# @api public
|
123
318
|
def response
|
124
319
|
response_transformer.call(
|
125
320
|
response_handler.call(request_handler.call(self), self),
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'rom/
|
1
|
+
require 'rom/types'
|
2
2
|
|
3
3
|
module ROM
|
4
4
|
module HTTP
|
@@ -8,26 +8,19 @@ module ROM
|
|
8
8
|
attr_reader :schema
|
9
9
|
|
10
10
|
def initialize(schema)
|
11
|
-
@schema = schema
|
11
|
+
@schema = Types::Hash.schema(schema)
|
12
12
|
end
|
13
13
|
|
14
14
|
def call(response, dataset)
|
15
|
-
|
16
|
-
t(:accept_keys, projections(dataset.projections)) >> ->(tuple) { schema.apply(tuple) }
|
17
|
-
).call(response)
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def t(*args)
|
23
|
-
ROM::HTTP::Support::Transformations[*args]
|
24
|
-
end
|
15
|
+
projections = dataset.projections
|
25
16
|
|
26
|
-
|
27
|
-
|
28
|
-
|
17
|
+
if projections.size > 0 && schema.member_types.keys != projections
|
18
|
+
projected_schema = Types::Hash.schema(
|
19
|
+
schema.member_types.select { |k, _| projections.include?(k) }
|
20
|
+
)
|
21
|
+
projected_schema[response]
|
29
22
|
else
|
30
|
-
|
23
|
+
response.map { |tuple| schema[tuple] }
|
31
24
|
end
|
32
25
|
end
|
33
26
|
end
|
data/lib/rom/http/gateway.rb
CHANGED
@@ -3,24 +3,64 @@ require 'rom/http/dataset'
|
|
3
3
|
|
4
4
|
module ROM
|
5
5
|
module HTTP
|
6
|
+
# HTTP gateway
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# config = {
|
10
|
+
# uri: 'http://jsonplaceholder.typicode.com',
|
11
|
+
# headers: { Accept: 'applicaiton/json' }
|
12
|
+
# }
|
13
|
+
#
|
14
|
+
# gateway = ROM::HTTP::Gateway.new(config)
|
15
|
+
# users = gateway.dataset(:users)
|
16
|
+
#
|
17
|
+
# @api public
|
6
18
|
class Gateway < ROM::Gateway
|
7
19
|
attr_reader :datasets, :config
|
8
20
|
private :datasets, :config
|
9
21
|
|
22
|
+
# HTTP gateway interface
|
23
|
+
#
|
24
|
+
# @param [Hash] config configuration options
|
25
|
+
# @option config [String] :uri The base API for the HTTP service
|
26
|
+
# @option config [Hash] :headers Default request headers
|
27
|
+
#
|
28
|
+
# @see Dataset
|
29
|
+
#
|
30
|
+
# @api public
|
10
31
|
def initialize(config)
|
11
32
|
@datasets = ThreadSafe::Cache.new
|
12
33
|
@config = config
|
13
34
|
end
|
14
35
|
|
36
|
+
# Retrieve dataset with the given name
|
37
|
+
#
|
38
|
+
# @param [String] name dataaset name
|
39
|
+
#
|
40
|
+
# @return [Dataset]
|
41
|
+
#
|
42
|
+
# @api public
|
15
43
|
def [](name)
|
16
44
|
datasets.fetch(name)
|
17
45
|
end
|
18
46
|
|
47
|
+
# Build dataset with the given name
|
48
|
+
#
|
49
|
+
# @param [String] name dataaset name
|
50
|
+
#
|
51
|
+
# @return [Dataset]
|
52
|
+
#
|
53
|
+
# @api public
|
19
54
|
def dataset(name)
|
20
55
|
dataset_klass = namespace.const_defined?(:Dataset) ? namespace.const_get(:Dataset) : Dataset
|
21
56
|
datasets[name] = dataset_klass.new(config.merge(name: name))
|
22
57
|
end
|
23
58
|
|
59
|
+
# Check if dataset exists
|
60
|
+
#
|
61
|
+
# @param [String] name dataset name
|
62
|
+
#
|
63
|
+
# @api public
|
24
64
|
def dataset?(name)
|
25
65
|
datasets.key?(name)
|
26
66
|
end
|
data/lib/rom/http/relation.rb
CHANGED
@@ -1,32 +1,43 @@
|
|
1
|
-
require 'rom/plugins/relation/
|
1
|
+
require 'rom/plugins/relation/view'
|
2
|
+
require 'rom/plugins/relation/key_inference'
|
2
3
|
|
3
4
|
module ROM
|
4
5
|
module HTTP
|
6
|
+
# HTTP-specific relation extensions
|
7
|
+
#
|
5
8
|
class Relation < ROM::Relation
|
6
9
|
include Enumerable
|
7
10
|
|
8
11
|
adapter :http
|
9
|
-
|
12
|
+
|
13
|
+
use :view
|
14
|
+
use :key_inference
|
10
15
|
|
11
16
|
forward :with_request_method, :with_path, :append_path, :with_options,
|
12
17
|
:with_params, :clear_params, :project
|
13
18
|
|
19
|
+
# @api private
|
14
20
|
def initialize(*)
|
15
21
|
super
|
16
|
-
|
17
|
-
|
18
|
-
|
22
|
+
if schema?
|
23
|
+
dataset.response_transformer(
|
24
|
+
Dataset::ResponseTransformers::Schemad.new(schema.to_h)
|
25
|
+
)
|
26
|
+
end
|
19
27
|
end
|
20
28
|
|
29
|
+
# @see Dataset#insert
|
21
30
|
def insert(*args)
|
22
31
|
dataset.insert(*args)
|
23
32
|
end
|
24
33
|
alias_method :<<, :insert
|
25
34
|
|
35
|
+
# @see Dataset#update
|
26
36
|
def update(*args)
|
27
37
|
dataset.update(*args)
|
28
38
|
end
|
29
39
|
|
40
|
+
# @see Dataset#delete
|
30
41
|
def delete
|
31
42
|
dataset.delete
|
32
43
|
end
|
data/lib/rom/http/version.rb
CHANGED
@@ -1,9 +1,19 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'rom-repository'
|
3
|
+
|
1
4
|
RSpec.describe ROM::HTTP::Relation do
|
5
|
+
subject(:users) { container.relation(:users).by_id(id).filter(params) }
|
6
|
+
|
2
7
|
include_context 'setup'
|
8
|
+
|
3
9
|
let(:relation) do
|
4
10
|
Class.new(ROM::HTTP::Relation) do
|
5
11
|
dataset :users
|
6
12
|
|
13
|
+
view :base, [:id, :name] do
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
7
17
|
def by_id(id)
|
8
18
|
append_path(id.to_s)
|
9
19
|
end
|
@@ -13,8 +23,12 @@ RSpec.describe ROM::HTTP::Relation do
|
|
13
23
|
end
|
14
24
|
end
|
15
25
|
end
|
16
|
-
|
17
|
-
let(:
|
26
|
+
|
27
|
+
let(:response) { tuples.to_json }
|
28
|
+
let(:tuples) { [{ id: 1337, name: 'John' }] }
|
29
|
+
let(:id) { 1337 }
|
30
|
+
let(:params) { { filters: { first_name: 'John' } } }
|
31
|
+
|
18
32
|
let(:dataset) do
|
19
33
|
ROM::HTTP::Dataset.new(
|
20
34
|
{
|
@@ -29,8 +43,6 @@ RSpec.describe ROM::HTTP::Relation do
|
|
29
43
|
params: params
|
30
44
|
)
|
31
45
|
end
|
32
|
-
let(:id) { 1337 }
|
33
|
-
let(:params) { { filters: { first_name: 'John' } } }
|
34
46
|
|
35
47
|
before do
|
36
48
|
configuration.register_relation(relation)
|
@@ -39,11 +51,26 @@ RSpec.describe ROM::HTTP::Relation do
|
|
39
51
|
allow(response_handler).to receive(:call).and_return(tuples)
|
40
52
|
end
|
41
53
|
|
42
|
-
|
54
|
+
it 'returns relation tuples' do
|
55
|
+
expect(users.to_a).to eql(tuples)
|
43
56
|
|
44
|
-
it do
|
45
57
|
expect(request_handler).to have_received(:call).with(dataset).once
|
46
58
|
expect(response_handler).to have_received(:call).with(response, dataset).once
|
47
|
-
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'using a repo' do
|
62
|
+
let(:repo) do
|
63
|
+
Class.new(ROM::Repository) { relations :users }.new(container)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'returns structs' do
|
67
|
+
user = repo.users.by_id(1337).filter(params).one
|
68
|
+
|
69
|
+
expect(user.id).to be(1337)
|
70
|
+
expect(user.name).to eql('John')
|
71
|
+
|
72
|
+
expect(request_handler).to have_received(:call).with(dataset).once
|
73
|
+
expect(response_handler).to have_received(:call).with(response, dataset).once
|
74
|
+
end
|
48
75
|
end
|
49
76
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
RSpec.describe ROM::HTTP::Dataset::ResponseTransformers::Schemad do
|
2
|
-
|
2
|
+
subject(:transformer) { ROM::HTTP::Dataset::ResponseTransformers::Schemad.new(schema) }
|
3
|
+
|
3
4
|
let(:schema) do
|
4
|
-
ROM::
|
5
|
-
|
6
|
-
|
7
|
-
attribute :active, 'form.bool'
|
8
|
-
end
|
5
|
+
{ id: ROM::Types::Form::Int,
|
6
|
+
name: ROM::Types::Strict::String,
|
7
|
+
active: ROM::Types::Form::Bool }
|
9
8
|
end
|
10
9
|
|
11
10
|
describe '#call' do
|
@@ -23,29 +22,23 @@ RSpec.describe ROM::HTTP::Dataset::ResponseTransformers::Schemad do
|
|
23
22
|
double('ROM::HTTP::Dataset', projections: projections)
|
24
23
|
end
|
25
24
|
|
26
|
-
subject! { transformer.call(response, dataset) }
|
27
|
-
|
28
25
|
context 'with no projections' do
|
29
26
|
let(:projections) { [] }
|
30
27
|
|
31
|
-
it do
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
active: true
|
36
|
-
])
|
28
|
+
it 'returns original tuples' do
|
29
|
+
result = transformer.call(response, dataset)
|
30
|
+
|
31
|
+
expect(result).to eql([id: 1, name: 'Jill', active: true])
|
37
32
|
end
|
38
33
|
end
|
39
34
|
|
40
35
|
context 'with projections' do
|
41
36
|
let(:projections) { [:id, :name, :active] }
|
42
37
|
|
43
|
-
it do
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
active: true
|
48
|
-
])
|
38
|
+
it 'returns projected relation tuples' do
|
39
|
+
result = transformer.call(response, dataset)
|
40
|
+
|
41
|
+
expect(result).to eql([id: 1, name: 'Jill', active: true])
|
49
42
|
end
|
50
43
|
end
|
51
44
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rom-http
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2016-
|
13
|
+
date: 2016-08-08 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: thread_safe
|
@@ -143,7 +143,6 @@ files:
|
|
143
143
|
- lib/rom/http/relation.rb
|
144
144
|
- lib/rom/http/support/transformations.rb
|
145
145
|
- lib/rom/http/version.rb
|
146
|
-
- lib/rom/plugins/relation/schema.rb
|
147
146
|
- rakelib/rubocop.rake
|
148
147
|
- rom-http.gemspec
|
149
148
|
- spec/integration/abstract/commands/create_spec.rb
|
@@ -159,7 +158,6 @@ files:
|
|
159
158
|
- spec/unit/rom/http/dataset_spec.rb
|
160
159
|
- spec/unit/rom/http/gateway_spec.rb
|
161
160
|
- spec/unit/rom/http/relation_spec.rb
|
162
|
-
- spec/unit/rom/plugins/relation/schema/schema_spec.rb
|
163
161
|
homepage: http://rom-rb.org
|
164
162
|
licenses:
|
165
163
|
- MIT
|
@@ -180,7 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
180
178
|
version: '0'
|
181
179
|
requirements: []
|
182
180
|
rubyforge_project:
|
183
|
-
rubygems_version: 2.
|
181
|
+
rubygems_version: 2.6.3
|
184
182
|
signing_key:
|
185
183
|
specification_version: 4
|
186
184
|
summary: HTTP support for ROM
|
@@ -198,5 +196,3 @@ test_files:
|
|
198
196
|
- spec/unit/rom/http/dataset_spec.rb
|
199
197
|
- spec/unit/rom/http/gateway_spec.rb
|
200
198
|
- spec/unit/rom/http/relation_spec.rb
|
201
|
-
- spec/unit/rom/plugins/relation/schema/schema_spec.rb
|
202
|
-
has_rdoc:
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'dry/types'
|
2
|
-
|
3
|
-
module ROM
|
4
|
-
module Plugins
|
5
|
-
module Relation
|
6
|
-
module Schema
|
7
|
-
def self.included(klass)
|
8
|
-
super
|
9
|
-
|
10
|
-
klass.class_eval do
|
11
|
-
def self.schema(&block)
|
12
|
-
@__schema__ = Schema.create(&block) if block_given?
|
13
|
-
@__schema__
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
class Schema
|
19
|
-
attr_reader :schema
|
20
|
-
attr_reader :coercer
|
21
|
-
|
22
|
-
def self.create(&block)
|
23
|
-
new.tap { |schema| schema.instance_eval(&block) }
|
24
|
-
end
|
25
|
-
|
26
|
-
def initialize(schema = {}, coercer = Dry::Types['hash'])
|
27
|
-
@schema = schema
|
28
|
-
@coercer = coercer
|
29
|
-
end
|
30
|
-
|
31
|
-
def attribute_names
|
32
|
-
schema.keys
|
33
|
-
end
|
34
|
-
|
35
|
-
def apply(attributes = {})
|
36
|
-
coercer.schema(schema).call(attributes)
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def attribute(name, type)
|
42
|
-
schema[name] = type
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
|
51
|
-
ROM.plugins do
|
52
|
-
register :schema, ROM::Plugins::Relation::Schema, type: :relation
|
53
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
RSpec.describe ROM::Plugins::Relation::Schema::Schema do
|
2
|
-
let(:klass) { ROM::Plugins::Relation::Schema::Schema }
|
3
|
-
let(:schema) do
|
4
|
-
klass.create do
|
5
|
-
attribute :id, 'form.int'
|
6
|
-
attribute :name, 'strict.string'
|
7
|
-
attribute :active, 'form.bool'
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
describe '#attribute_names' do
|
12
|
-
subject! { schema.attribute_names }
|
13
|
-
|
14
|
-
it { is_expected.to match_array([:id, :name, :active])}
|
15
|
-
end
|
16
|
-
|
17
|
-
describe '#apply' do
|
18
|
-
let(:attributes) do
|
19
|
-
{
|
20
|
-
id: '1',
|
21
|
-
name: 'John',
|
22
|
-
active: 'true'
|
23
|
-
}
|
24
|
-
end
|
25
|
-
|
26
|
-
subject! { schema.apply(attributes) }
|
27
|
-
|
28
|
-
it { is_expected.to eq(id: 1, name: 'John', active: true) }
|
29
|
-
end
|
30
|
-
end
|