rom-http 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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">![Gem Version](https://badge.fury.io/rb/rom-http.svg)</a>
|
4
|
-
<a href="https://travis-ci.org/rom-rb/rom-http" target="_blank">![Build Status](https://travis-ci.org/rom-rb/rom-http.svg?branch=master)</a>
|
5
|
-
<a href="https://gemnasium.com/rom-rb/rom-http" target="_blank">![Dependency Status](https://gemnasium.com/rom-rb/rom-http.svg)</a>
|
6
|
-
<a href="https://codeclimate.com/github/rom-rb/rom-http" target="_blank">![Code Climate](https://codeclimate.com/github/rom-rb/rom-http/badges/gpa.svg)</a>
|
7
|
-
<a href="http://inch-ci.org/github/rom-rb/rom-http" target="_blank">![Documentation Status](http://inch-ci.org/github/rom-rb/rom-http.svg?branch=master&style=flat)</a>
|
8
9
|
|
9
|
-
|
10
|
+
# ROM-http [![Gitter chat](https://badges.gitter.im/rom-rb/chat.svg)][gitter]
|
10
11
|
|
11
|
-
|
12
|
+
[![Gem Version](https://badge.fury.io/rb/rom-http.svg)][gem]
|
13
|
+
[![Build Status](https://travis-ci.org/rom-rb/rom-http.svg?branch=master)][travis]
|
14
|
+
[![Dependency Status](https://gemnasium.com/rom-rb/rom-http.svg)][gemnasium]
|
15
|
+
[![Code Climate](https://codeclimate.com/github/rom-rb/rom-http/badges/gpa.svg)][codeclimate]
|
16
|
+
[![Documentation Status](http://inch-ci.org/github/rom-rb/rom-http.svg?branch=master&style=flat)][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
|