rom-http 0.5.0 → 0.6.0.rc1

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: 940c73eee8219c8b80aa2ec5914549291be5e99d
4
- data.tar.gz: 0e852b96a95edb10991aefa9d5bcffa78e5211b4
3
+ metadata.gz: e61d4626a34ea84673dc4632b6f1bbdd668e0b8c
4
+ data.tar.gz: 859e9539a8127ad7c8b7cc2fd6d0904cb734e404
5
5
  SHA512:
6
- metadata.gz: 3db2d4a662ae4ae76138119946b71253e36e0be5653fda789a17083f6915f7630357b0680e297690c56fab85da363ffaee1cc03412d568b2c16bd61421f080db
7
- data.tar.gz: 8738e9b3524917c5e74535a2ae6b1ef9e23c82a98871fac7079f507321e40da86185a811f54f1b47468b9b6a56a485891c86f5377f15d13c7246f86703c41fbb
6
+ metadata.gz: fd492be4654b12a16194c74f2e0ae3db44f4a456b6d8edf85ead74a8f3581ac3bca6bd2d436a67370502c10d416f75692388832249a0e2e53dc4dc05b238cca6
7
+ data.tar.gz: 666263147a7e6f534d602d6aa904ae8ed28a35c2307799bd871b8312276419750457d5dce5d92218b0c578cf7c7e3f3bea06a4e0b85b034944d2345a28728131
@@ -1,24 +1,21 @@
1
1
  language: ruby
2
- sudo: false
2
+ dist: trusty
3
+ sudo: required
3
4
  cache: bundler
4
5
  bundler_args: --without sql benchmarks console tools
5
6
  script: "bundle exec rake ci"
6
7
  rvm:
7
- - 2.1
8
- - 2.2
9
- - 2.3.1
10
- - rbx-2
11
- - jruby-9.0.5.0
12
- - ruby-head
13
- - jruby-head
8
+ - 2.2.6
9
+ - 2.3.3
10
+ - 2.4.0
11
+ - rbx-3
12
+ - jruby-9.1.6.0
14
13
  env:
15
14
  global:
16
15
  - JRUBY_OPTS='--dev -J-Xmx1024M'
17
16
  matrix:
18
17
  allow_failures:
19
- - rvm: ruby-head
20
- - rvm: jruby-head
21
- - rvm: rbx-2
18
+ - rvm: rbx-3
22
19
  notifications:
23
20
  webhooks:
24
21
  urls:
@@ -1,3 +1,16 @@
1
+ # v0.6.0 to-be-released
2
+ # Changed
3
+ - Make schemas mandatory and use schema API from ROM core (AMHOL)
4
+ - Generate transformer using schema (AMHOL)
5
+ - Removed rbx-2 support (solnic)
6
+ - Add Dataset#base_path and Relation#primary_key (AMHOL)
7
+ - Updated to work with ROM 3.0.beta (maximderbin)
8
+ - Removed ruby 2.1 support (maximderbin)
9
+ - Fix Relation#primary_key when schema defines alias (AMHOL)
10
+ - Transform keys on insert and update (maximderbin)
11
+
12
+ [Compare v0.5.0...v0.6.0](https://github.com/rom-rb/rom-http/compare/v0.5.0...master)
13
+
1
14
  # v0.5.0 2016-08-08
2
15
  ### Changed
3
16
  - Removed ruby 2.0 support
data/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [rom]: https://github.com/rom-rb/rom
8
8
 
9
9
 
10
- # ROM-http [![Gitter chat](https://badges.gitter.im/rom-rb/chat.svg)][gitter]
10
+ # rom-http [![Gitter chat](https://badges.gitter.im/rom-rb/chat.svg)][gitter]
11
11
 
12
12
  [![Gem Version](https://badge.fury.io/rb/rom-http.svg)][gem]
13
13
  [![Build Status](https://travis-ci.org/rom-rb/rom-http.svg?branch=master)][travis]
@@ -45,6 +45,7 @@ See `LICENSE` file.
45
45
  ## Synopsis
46
46
 
47
47
  ```ruby
48
+ require 'inflecto'
48
49
  require 'json'
49
50
  require 'uri'
50
51
  require 'net/http'
@@ -52,11 +53,11 @@ require 'net/http'
52
53
  class RequestHandler
53
54
  def call(dataset)
54
55
  uri = URI(dataset.uri)
55
- uri.path = "/#{dataset.name}/#{dataset.path}"
56
+ uri.path = dataset.absolute_path
56
57
  uri.query = URI.encode_www_form(dataset.params)
57
58
 
58
59
  http = Net::HTTP.new(uri.host, uri.port)
59
- request_klass = Net::HTTP.const_get(ROM::Inflector.classify(dataset.request_method))
60
+ request_klass = Net::HTTP.const_get(Inflecto.classify(dataset.request_method))
60
61
 
61
62
  request = request_klass.new(uri.request_uri)
62
63
  dataset.headers.each_with_object(request) do |(header, value), request|
@@ -69,23 +70,22 @@ end
69
70
 
70
71
  class ResponseHandler
71
72
  def call(response, dataset)
72
- Array([JSON.parse(response.body)]).flatten
73
+ if %i(post put patch).include?(dataset.request_method)
74
+ JSON.parse(response.body, symbolize_names: true)
75
+ else
76
+ Array([JSON.parse(response.body, symbolize_names: true)]).flatten
77
+ end
73
78
  end
74
79
  end
75
80
 
76
81
  class Users < ROM::Relation[:http]
77
- dataset :users
78
-
79
- # You can also define a schema block
80
- # which will use dry-types' Dry::Types['hash']
81
- # coercion to pre-process your data
82
- schema do
83
- attribute 'id', 'strict.int'
84
- attribute 'name', 'strict.string'
85
- attribute 'username', 'strict.string'
86
- attribute 'email', 'strict.string'
87
- attribute 'phone', 'strict.string'
88
- attribute 'website', 'strict.string'
82
+ schema(:users) do
83
+ attribute :id, ROM::Types::Int
84
+ attribute :name, ROM::Types::String
85
+ attribute :username, ROM::Types::String
86
+ attribute :email, ROM::Types::String
87
+ attribute :phone, ROM::Types::String
88
+ attribute :website, ROM::Types::String
89
89
  end
90
90
 
91
91
  def by_id(id)
@@ -111,6 +111,7 @@ container.relation(:users).by_id(1).to_a
111
111
  ### Extending
112
112
 
113
113
  ```ruby
114
+ require 'inflecto'
114
115
  require 'json'
115
116
  require 'uri'
116
117
  require 'net/http'
@@ -120,11 +121,11 @@ module ROM
120
121
  class Dataset < ROM::HTTP::Dataset
121
122
  default_request_handler ->(dataset) do
122
123
  uri = URI(dataset.uri)
123
- uri.path = "/#{dataset.name}/#{dataset.path}"
124
+ uri.path = dataset.absolute_path
124
125
  uri.query = URI.encode_www_form(dataset.params)
125
126
 
126
127
  http = Net::HTTP.new(uri.host, uri.port)
127
- request_klass = Net::HTTP.const_get(ROM::Inflector.classify(dataset.request_method))
128
+ request_klass = Net::HTTP.const_get(Inflecto.classify(dataset.request_method))
128
129
 
129
130
  request = request_klass.new(uri.request_uri)
130
131
  dataset.headers.each_with_object(request) do |(header, value), request|
@@ -135,7 +136,11 @@ module ROM
135
136
  end
136
137
 
137
138
  default_response_handler ->(response, dataset) do
138
- Array([JSON.parse(response.body)]).flatten
139
+ if %i(post put patch).include?(dataset.request_method)
140
+ JSON.parse(response.body, symbolize_names: true)
141
+ else
142
+ Array([JSON.parse(response.body, symbolize_names: true)]).flatten
143
+ end
139
144
  end
140
145
  end
141
146
 
@@ -171,7 +176,14 @@ configuration = ROM::Configuration.new(:my_adapter, {
171
176
  })
172
177
 
173
178
  class Users < ROM::Relation[:my_adapter]
174
- dataset :users
179
+ schema(:users) do
180
+ attribute :id, ROM::Types::Int
181
+ attribute :name, ROM::Types::String
182
+ attribute :username, ROM::Types::String
183
+ attribute :email, ROM::Types::String
184
+ attribute :phone, ROM::Types::String
185
+ attribute :website, ROM::Types::String
186
+ end
175
187
 
176
188
  def by_id(id)
177
189
  with_path(id.to_s)
@@ -0,0 +1,154 @@
1
+ require 'inflecto'
2
+ require 'json'
3
+ require 'uri'
4
+ require 'net/http'
5
+ require 'rom-repository'
6
+
7
+ class RequestHandler
8
+ def call(dataset)
9
+ uri = URI(dataset.uri)
10
+ uri.path = dataset.absolute_path
11
+ uri.query = URI.encode_www_form(dataset.params)
12
+
13
+ http = Net::HTTP.new(uri.host, uri.port)
14
+ request_klass = Net::HTTP.const_get(Inflecto.classify(dataset.request_method))
15
+
16
+ request = request_klass.new(uri.request_uri)
17
+ dataset.headers.each_with_object(request) do |(header, value), request|
18
+ request[header.to_s] = value
19
+ end
20
+
21
+ response = http.request(request)
22
+ end
23
+ end
24
+
25
+ class ResponseHandler
26
+ def call(response, dataset)
27
+ if %i(post put patch).include?(dataset.request_method)
28
+ JSON.parse(response.body, symbolize_names: true)
29
+ else
30
+ Array([JSON.parse(response.body, symbolize_names: true)]).flatten
31
+ end
32
+ end
33
+ end
34
+
35
+ class Users < ROM::Relation[:http]
36
+ schema(:users) do
37
+ attribute :id, ROM::Types::Int.meta(primary_key: true)
38
+ attribute :name, ROM::Types::String
39
+ attribute :username, ROM::Types::String
40
+ attribute :email, ROM::Types::String
41
+ attribute :phone, ROM::Types::String
42
+ attribute :website, ROM::Types::String
43
+ end
44
+
45
+ def by_id(id)
46
+ with_path(id.to_s)
47
+ end
48
+ end
49
+
50
+ class Posts < ROM::Relation[:http]
51
+ schema(:posts) do
52
+ attribute :id, ROM::Types::Int.meta(primary_key: true)
53
+ attribute :userId, ROM::Types::Int.meta(alias: :user_id)
54
+ attribute :title, ROM::Types::String
55
+ attribute :body, ROM::Types::String
56
+ end
57
+
58
+ def by_id(id)
59
+ with_path(id.to_s)
60
+ end
61
+
62
+ def for_user(user)
63
+ with_options(
64
+ base_path: 'users',
65
+ path: "#{user.first[:id]}/posts"
66
+ )
67
+ end
68
+ end
69
+
70
+ class UserRepository < ROM::Repository[:users]
71
+ relations :posts
72
+
73
+ def find(id)
74
+ users.by_id(id).first
75
+ end
76
+
77
+ def find_with_posts(user_id)
78
+ users.by_id(user_id).combine_children(many: posts.for_user).first
79
+ end
80
+ end
81
+
82
+ configuration = ROM::Configuration.new(:http, {
83
+ uri: 'http://jsonplaceholder.typicode.com',
84
+ headers: {
85
+ Accept: 'application/json'
86
+ },
87
+ request_handler: RequestHandler.new,
88
+ response_handler: ResponseHandler.new
89
+ })
90
+ configuration.register_relation(Users)
91
+ configuration.register_relation(Posts)
92
+ container = ROM.container(configuration)
93
+
94
+ UserRepository.new(container).find_with_posts(1)
95
+ # =>
96
+ # #<ROM::Struct[User]
97
+ # id=1
98
+ # name="Leanne Graham"
99
+ # username="Bret"
100
+ # email="Sincere@april.biz"
101
+ # phone="1-770-736-8031 x56442"
102
+ # website="hildegard.org"
103
+ # posts=[
104
+ # #<ROM::Struct[Post]
105
+ # id=1
106
+ # user_id=1
107
+ # title="sunt aut facere repellat provident occaecati excepturi optio reprehenderit"
108
+ # body="quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto">,
109
+ # #<ROM::Struct[Post]
110
+ # id=2
111
+ # user_id=1
112
+ # title="qui est esse"
113
+ # body="est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla">,
114
+ # #<ROM::Struct[Post]
115
+ # id=3
116
+ # user_id=1
117
+ # title="ea molestias quasi exercitationem repellat qui ipsa sit aut"
118
+ # body="et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut">,
119
+ # #<ROM::Struct[Post]
120
+ # id=4
121
+ # user_id=1
122
+ # title="eum et est occaecati"
123
+ # body="ullam et saepe reiciendis voluptatem adipisci\nsit amet autem assumenda provident rerum culpa\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\nquis sunt voluptatem rerum illo velit">,
124
+ # #<ROM::Struct[Post]
125
+ # id=5
126
+ # user_id=1
127
+ # title="nesciunt quas odio"
128
+ # body="repudiandae veniam quaerat sunt sed\nalias aut fugiat sit autem sed est\nvoluptatem omnis possimus esse voluptatibus quis\nest aut tenetur dolor neque">,
129
+ # #<ROM::Struct[Post]
130
+ # id=6
131
+ # user_id=1
132
+ # title="dolorem eum magni eos aperiam quia"
133
+ # body="ut aspernatur corporis harum nihil quis provident sequi\nmollitia nobis aliquid molestiae\nperspiciatis et ea nemo ab reprehenderit accusantium quas\nvoluptate dolores velit et doloremque molestiae">,
134
+ # #<ROM::Struct[Post]
135
+ # id=7
136
+ # user_id=1
137
+ # title="magnam facilis autem"
138
+ # body="dolore placeat quibusdam ea quo vitae\nmagni quis enim qui quis quo nemo aut saepe\nquidem repellat excepturi ut quia\nsunt ut sequi eos ea sed quas">,
139
+ # #<ROM::Struct[Post]
140
+ # id=8
141
+ # user_id=1
142
+ # title="dolorem dolore est ipsam"
143
+ # body="dignissimos aperiam dolorem qui eum\nfacilis quibusdam animi sint suscipit qui sint possimus cum\nquaerat magni maiores excepturi\nipsam ut commodi dolor voluptatum modi aut vitae">,
144
+ # #<ROM::Struct[Post]
145
+ # id=9
146
+ # user_id=1
147
+ # title="nesciunt iure omnis dolorem tempora et accusantium"
148
+ # body="consectetur animi nesciunt iure dolore\nenim quia ad\nveniam autem ut quam aut nobis\net est aut quod aut provident voluptas autem voluptas">,
149
+ # #<ROM::Struct[Post]
150
+ # id=10
151
+ # user_id=1
152
+ # title="optio molestias id quia eum"
153
+ # body="quo et expedita modi cum officia vel magni\ndoloribus qui repudiandae\nvero nisi sit\nquos veniam quod sed accusamus veritatis error">
154
+ # ]>
@@ -13,7 +13,6 @@ module ROM
13
13
  def execute(tuples)
14
14
  Array([tuples]).flatten.map do |tuple|
15
15
  attributes = input[tuple]
16
- validator.call(attributes)
17
16
  relation.insert(attributes.to_h)
18
17
  end.to_a
19
18
  end
@@ -13,7 +13,6 @@ module ROM
13
13
  def execute(tuples)
14
14
  Array([tuples]).flatten.map do |tuple|
15
15
  attributes = input[tuple]
16
- validator.call(attributes)
17
16
  relation.update(attributes.to_h)
18
17
  end.to_a
19
18
  end
@@ -1,5 +1,4 @@
1
- require 'rom/http/dataset/response_transformers/schemad'
2
- require 'rom/http/dataset/response_transformers/schemaless'
1
+ require 'rom/initializer'
3
2
 
4
3
  module ROM
5
4
  module HTTP
@@ -9,17 +8,20 @@ module ROM
9
8
  #
10
9
  # @api public
11
10
  class Dataset
11
+ PATH_SEPARATOR = '/'.freeze
12
+ STRIP_PATH = ->(path) { path.sub(%r{\A/}, '') }.freeze
13
+
12
14
  include Enumerable
13
15
  include Dry::Equalizer(:config, :options)
14
- include ROM::Options
16
+ extend ::ROM::Initializer
15
17
 
16
- attr_reader :config
18
+ param :config
17
19
 
18
- option :projections, type: ::Array, default: [], reader: true
19
- option :request_method, type: ::Symbol, default: :get, reader: true
20
- option :path, type: ::String, default: ''
21
- option :params, type: ::Hash, default: {}, reader: true
22
- option :headers, type: ::Hash, default: {}
20
+ option :request_method, type: Types::Symbol, default: proc { :get }, reader: true
21
+ option :base_path, type: Types::String, default: proc { name }
22
+ option :path, type: Types::String, default: proc { '' }
23
+ option :params, type: Types::Hash, default: proc { {} }, reader: true
24
+ option :headers, type: Types::Hash, default: proc { {} }
23
25
 
24
26
  class << self
25
27
  def default_request_handler(handler = Undefined)
@@ -33,39 +35,6 @@ module ROM
33
35
  end
34
36
  end
35
37
 
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
49
- def initialize(config, options = {})
50
- @config = config
51
- @response_transformer = ResponseTransformers::Schemaless.new
52
- super(options)
53
- end
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
64
- def response_transformer(transformer = Undefined)
65
- return @response_transformer if Undefined === transformer
66
- @response_transformer = transformer
67
- end
68
-
69
38
  # Return the gateway's URI
70
39
  #
71
40
  # @return [String]
@@ -104,6 +73,19 @@ module ROM
104
73
  config[:name].to_s
105
74
  end
106
75
 
76
+ # Return the base path
77
+ #
78
+ # @example
79
+ # Dataset.new(config, base_path: '/users').base_path
80
+ # # => 'users'
81
+ #
82
+ # @return [String] the dataset path, without a leading slash
83
+ #
84
+ # @api public
85
+ def base_path
86
+ STRIP_PATH.call(super)
87
+ end
88
+
107
89
  # Return the dataset path
108
90
  #
109
91
  # @example
@@ -114,7 +96,7 @@ module ROM
114
96
  #
115
97
  # @api public
116
98
  def path
117
- options[:path].to_s.sub(%r{\A/}, '')
99
+ STRIP_PATH.call(join_path(base_path, super))
118
100
  end
119
101
 
120
102
  # Return the dataset path
@@ -127,7 +109,7 @@ module ROM
127
109
  #
128
110
  # @api public
129
111
  def absolute_path
130
- '/' + path
112
+ PATH_SEPARATOR + path
131
113
  end
132
114
 
133
115
  # Return a new dataset with given headers
@@ -177,24 +159,19 @@ module ROM
177
159
  __new__(config, options.merge(opts))
178
160
  end
179
161
 
180
- # Add a new set projection to the result set
162
+ # Return a new dataset with a different base path
181
163
  #
182
- # @param [Array, *args] projections the keys to add to the projections
164
+ # @param base_path [String] the new base request path
183
165
  #
184
166
  # @example
185
- # users = Dataset.new(config, projections: [:login])
186
- # users.project(:email, :name).projections
187
- # # => [:login, :email, :name]
167
+ # users.with_base_path('/profiles').base_path
168
+ # # => 'profiles'
188
169
  #
189
170
  # @return [Dataset]
190
171
  #
191
172
  # @api public
192
- def project(*args)
193
- projections = args.first.is_a?(::Array) ? args.first : args
194
-
195
- with_options(
196
- projections: (self.projections + projections)
197
- )
173
+ def with_base_path(base_path)
174
+ with_options(base_path: base_path)
198
175
  end
199
176
 
200
177
  # Return a new dataset with a different path
@@ -223,8 +200,8 @@ module ROM
223
200
  # @return [Dataset]
224
201
  #
225
202
  # @api public
226
- def append_path(path)
227
- with_options(path: options[:path] + '/' + path)
203
+ def append_path(append_path)
204
+ with_options(path: join_path(path, append_path))
228
205
  end
229
206
 
230
207
  # Return a new dataset with a different request method
@@ -316,10 +293,7 @@ module ROM
316
293
  #
317
294
  # @api public
318
295
  def response
319
- response_transformer.call(
320
- response_handler.call(request_handler.call(self), self),
321
- self
322
- )
296
+ response_handler.call(request_handler.call(self), self)
323
297
  end
324
298
 
325
299
  private
@@ -339,6 +313,10 @@ module ROM
339
313
  def __new__(*args, &block)
340
314
  self.class.new(*args, &block)
341
315
  end
316
+
317
+ def join_path(*paths)
318
+ paths.reject(&:empty?).join(PATH_SEPARATOR)
319
+ end
342
320
  end
343
321
  end
344
322
  end