lhs 0.3.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 +7 -0
- data/.gitignore +38 -0
- data/Gemfile +11 -0
- data/README.md +67 -0
- data/Rakefile +26 -0
- data/docs/collections.md +28 -0
- data/docs/data.md +39 -0
- data/docs/examples/claim_no_include.json +16 -0
- data/docs/examples/claim_with_include.json +47 -0
- data/docs/items.md +55 -0
- data/docs/service.jpg +0 -0
- data/docs/service.pdf +649 -3
- data/docs/services.md +191 -0
- data/lhs.gemspec +31 -0
- data/lib/lhs.rb +6 -0
- data/lib/lhs/collection.rb +78 -0
- data/lib/lhs/concerns/data/json.rb +12 -0
- data/lib/lhs/concerns/item/destroy.rb +15 -0
- data/lib/lhs/concerns/item/save.rb +29 -0
- data/lib/lhs/concerns/item/update.rb +24 -0
- data/lib/lhs/concerns/service/all.rb +24 -0
- data/lib/lhs/concerns/service/batch.rb +37 -0
- data/lib/lhs/concerns/service/build.rb +17 -0
- data/lib/lhs/concerns/service/create.rb +26 -0
- data/lib/lhs/concerns/service/endpoints.rb +82 -0
- data/lib/lhs/concerns/service/find.rb +36 -0
- data/lib/lhs/concerns/service/find_by.rb +35 -0
- data/lib/lhs/concerns/service/first.rb +19 -0
- data/lib/lhs/concerns/service/includes.rb +21 -0
- data/lib/lhs/concerns/service/mapping.rb +23 -0
- data/lib/lhs/concerns/service/model.rb +16 -0
- data/lib/lhs/concerns/service/request.rb +96 -0
- data/lib/lhs/concerns/service/where.rb +16 -0
- data/lib/lhs/data.rb +103 -0
- data/lib/lhs/errors.rb +86 -0
- data/lib/lhs/item.rb +83 -0
- data/lib/lhs/proxy.rb +26 -0
- data/lib/lhs/service.rb +20 -0
- data/lib/lhs/version.rb +3 -0
- data/script/ci/build.sh +19 -0
- data/spec/collection/meta_data_spec.rb +54 -0
- data/spec/collection/respond_to_spec.rb +19 -0
- data/spec/collection/without_object_items_spec.rb +26 -0
- data/spec/data/collection_spec.rb +36 -0
- data/spec/data/item_spec.rb +44 -0
- data/spec/data/merge_spec.rb +32 -0
- data/spec/data/raw_spec.rb +39 -0
- data/spec/data/respond_to_spec.rb +26 -0
- data/spec/data/root_spec.rb +25 -0
- data/spec/data/to_json_spec.rb +39 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +14 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +34 -0
- data/spec/dummy/config/environments/production.rb +75 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/assets.rb +8 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +9 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +56 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/item/destroy_spec.rb +39 -0
- data/spec/item/getter_spec.rb +24 -0
- data/spec/item/respond_to_spec.rb +29 -0
- data/spec/item/save_errors_spec.rb +48 -0
- data/spec/item/save_spec.rb +58 -0
- data/spec/item/setter_spec.rb +38 -0
- data/spec/item/update_spec.rb +56 -0
- data/spec/proxy/load_spec.rb +47 -0
- data/spec/rails_helper.rb +9 -0
- data/spec/service/all_spec.rb +31 -0
- data/spec/service/build_spec.rb +25 -0
- data/spec/service/create_spec.rb +81 -0
- data/spec/service/creation_failed_spec.rb +54 -0
- data/spec/service/endpoint_misconfiguration_spec.rb +26 -0
- data/spec/service/endpoint_options_spec.rb +23 -0
- data/spec/service/endpoints_spec.rb +57 -0
- data/spec/service/find_by_spec.rb +49 -0
- data/spec/service/find_each_spec.rb +47 -0
- data/spec/service/find_in_batches_spec.rb +68 -0
- data/spec/service/find_spec.rb +71 -0
- data/spec/service/first_spec.rb +39 -0
- data/spec/service/includes_spec.rb +61 -0
- data/spec/service/mapping_spec.rb +72 -0
- data/spec/service/model_name_spec.rb +17 -0
- data/spec/service/request_spec.rb +22 -0
- data/spec/service/where_spec.rb +33 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/support/cleanup_configuration.rb +17 -0
- data/spec/support/cleanup_services.rb +20 -0
- data/spec/support/fixtures/json/feedback.json +11 -0
- data/spec/support/fixtures/json/feedbacks.json +174 -0
- data/spec/support/fixtures/json/localina_content_ad.json +23 -0
- data/spec/support/load_json.rb +3 -0
- metadata +346 -0
data/docs/services.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
Services
|
|
2
|
+
===
|
|
3
|
+
|
|
4
|
+
A LHS::Service makes data available using multiple endpoints.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
## Endpoints
|
|
9
|
+
|
|
10
|
+
You setup a service by configure one or multiple backend endpoints.
|
|
11
|
+
You can also add request options for an endpoint (see following example).
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
class Feedback < LHS::Service
|
|
15
|
+
|
|
16
|
+
endpoint ':datastore/v2/content-ads/:campaign_id/feedbacks'
|
|
17
|
+
endpoint ':datastore/v2/feedbacks', cache: true, cache_expires_in: 1.day
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
If you try to setup a service with clashing endpoints it will immediately raise an exception.
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
class Feedback < LHS::Service
|
|
26
|
+
|
|
27
|
+
endpoint ':datastore/v2/reviews'
|
|
28
|
+
endpoint ':datastore/v2/feedbacks'
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
# raises: Clashing endpoints.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Find multiple records
|
|
36
|
+
|
|
37
|
+
You can query the services by using `where`.
|
|
38
|
+
|
|
39
|
+
```ruby
|
|
40
|
+
Feedback.where(has_reviews: true) #<LHS::Data @_proxy=#<LHS::Collection>>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This uses the `:datastore/v2/feedbacks` endpoint, cause `:campaign_id` was not provided.
|
|
44
|
+
In addition it would add `?has_reviews=true` to the get parameters.
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
Feedback.where(campaign_id: 'fq-a81ngsl1d') #<LHS::Data @_proxy=#<LHS::Collection>>
|
|
48
|
+
```
|
|
49
|
+
Uses the `:datastore/v2/content-ads/:campaign_id/feedbacks` endpoint.
|
|
50
|
+
|
|
51
|
+
→ [Read more about collections](collections.md)
|
|
52
|
+
|
|
53
|
+
## Find single records
|
|
54
|
+
|
|
55
|
+
`find` finds a unique item by uniqe identifier (usualy id).
|
|
56
|
+
|
|
57
|
+
If no record is found an error is raised.
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
Feedback.find('z12f-3asm3ngals') #<LHS::Data @_proxy=#<LHS::Item>>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`find` can also be used to find a single uniqe item with parameters:
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
Feedback.find(campaign_id: 123, id: 456)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`find_by` finds the first record matching the specified conditions.
|
|
70
|
+
|
|
71
|
+
If no record is found, `nil` is returned.
|
|
72
|
+
|
|
73
|
+
`find_by!` raises LHC::NotFound if nothing was found.
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
Feedback.find_by(id: 'z12f-3asm3ngals') #<LHS::Data @_proxy=#<LHS::Item>>
|
|
77
|
+
Feedback.find_by(id: 'doesntexist') # nil
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`first` is a alias for finding the first of a service without parameters.
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
Feedback.first
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
If no record is found, `nil` is returned.
|
|
87
|
+
|
|
88
|
+
`first!` raises LHC::NotFound if nothing was found.
|
|
89
|
+
|
|
90
|
+
→ [Read more about items](items.md)
|
|
91
|
+
|
|
92
|
+
## Batch processing
|
|
93
|
+
|
|
94
|
+
** Be carefull using methods for batch processing. They could result in a lot of HTTP requests! **
|
|
95
|
+
|
|
96
|
+
`all` fetches all records from the backend by doing multiple requests if necessary.
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
data = Feedback.all #<LHS::Data @_proxy=#<LHS::Collection>>
|
|
100
|
+
data.count # 998
|
|
101
|
+
data.total # 998
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
→ [Read more about collections](collections.md)
|
|
105
|
+
|
|
106
|
+
`find_each` is a more fine grained way to process single records that are fetched in batches.
|
|
107
|
+
|
|
108
|
+
```ruby
|
|
109
|
+
Feedback.find_each(start: 50, batch_size: 20, params: { has_reviews: true }) do |feedback|
|
|
110
|
+
# Iterates over each record. Starts with record nr. 50 and fetches 20 records each batch.
|
|
111
|
+
feedback #<LHS::Data @_proxy=#<LHS::Item>>
|
|
112
|
+
end
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`find_in_batches` is used by `find_each` and processes batches.
|
|
116
|
+
```ruby
|
|
117
|
+
Feedback.find_in_batches(start: 50, batch_size: 20, params: { has_reviews: true }) do |feedbacks|
|
|
118
|
+
# Iterates over multiple records (batch size is 20). Starts with record nr. 50 and fetches 20 records each batch.
|
|
119
|
+
feedbacks #<LHS::Data @_proxy=#<LHS::Collection>>
|
|
120
|
+
end
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Create records
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
feedback = Feedback.create(
|
|
127
|
+
recommended: true,
|
|
128
|
+
source_id: 'aaa',
|
|
129
|
+
content_ad_id: '1z-5r1fkaj'
|
|
130
|
+
) #<LHS::Data @_proxy=#<LHS::Item>>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
When creation fails, the object contains errors in its `errors` attribute:
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
feedback.errors #<LHS::Errors>
|
|
137
|
+
feedback.errors.include?(:ratings) # true
|
|
138
|
+
feedback.errors[:ratings] # ['REQUIRED_PROPERTY_VALUE']
|
|
139
|
+
record.errors.messages # {:ratings=>["REQUIRED_PROPERTY_VALUE"], :recommended=>["REQUIRED_PROPERTY_VALUE"]}
|
|
140
|
+
record.errors.message # ratings must be set when review or name or review_title is set | The property value is required; it cannot be null, empty, or blank."
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Build new records
|
|
144
|
+
|
|
145
|
+
Build and persist new items from scratch.
|
|
146
|
+
|
|
147
|
+
```ruby
|
|
148
|
+
feedback = Feedback.build(recommended: true)
|
|
149
|
+
feedback.save
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
→ [Read more about items](items.md)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
## Include linked resources
|
|
156
|
+
|
|
157
|
+
A service lets you specify in advance all the linked resources that you want to include in the results. With includes, a service ensures that all matching and explicitly linked resources are loaded and merged.
|
|
158
|
+
|
|
159
|
+
The implementation is heavily influenced by [http://guides.rubyonrails.org/active_record_querying](http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations)
|
|
160
|
+
and you should read it to understand this feature in all its glory.
|
|
161
|
+
|
|
162
|
+
### One-Level `includes`
|
|
163
|
+
|
|
164
|
+
```ruby
|
|
165
|
+
# a claim has a localch_account
|
|
166
|
+
claims = Claims.includes(:localch_account).where(place_id: 'huU90mB_6vAfUdVz_uDoyA')
|
|
167
|
+
claims.first.localch_account.email # 'test@email.com'
|
|
168
|
+
```
|
|
169
|
+
* [see the JSON without include](examples/claim_no_include.json)
|
|
170
|
+
* [see the JSON with include](examples/claim_with_include.json)
|
|
171
|
+
|
|
172
|
+
### Two-Level `includes`
|
|
173
|
+
|
|
174
|
+
```ruby
|
|
175
|
+
# a feedback has a campaign, which has an entry
|
|
176
|
+
feedbacks = Feedback.includes(campaign: :entry).where(has_reviews: true)
|
|
177
|
+
feedbacks.first.campaign.entry.name # 'Casa Ferlin'
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Map data
|
|
181
|
+
|
|
182
|
+
To influence how data is accessed/provied, you can use mapping to either map deep nested data or to manipulate data when its accessed:
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
class LocalEntry < LHS::Service
|
|
186
|
+
endpoint ':datastore/v2/local-entries'
|
|
187
|
+
|
|
188
|
+
map :name, ->(entry){ entry.addresses.first.business.identities.first.name }
|
|
189
|
+
|
|
190
|
+
end
|
|
191
|
+
```
|
data/lhs.gemspec
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
2
|
+
|
|
3
|
+
# Maintain your gem's version:
|
|
4
|
+
require "lhs/version"
|
|
5
|
+
|
|
6
|
+
# Describe your gem and declare its dependencies:
|
|
7
|
+
Gem::Specification.new do |s|
|
|
8
|
+
s.name = "lhs"
|
|
9
|
+
s.version = LHS::VERSION
|
|
10
|
+
s.authors = ['local.ch']
|
|
11
|
+
s.email = ['ws-operations@local.ch']
|
|
12
|
+
s.homepage = 'https://github.com/local-ch/lhs'
|
|
13
|
+
s.summary = 'LocalHttpServices'
|
|
14
|
+
s.description = 'Rails gem providing an easy interface to use http services here at local'
|
|
15
|
+
|
|
16
|
+
s.files = `git ls-files`.split("\n")
|
|
17
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
|
18
|
+
s.require_paths = ['lib']
|
|
19
|
+
|
|
20
|
+
s.requirements << 'Ruby >= 1.9.2'
|
|
21
|
+
s.required_ruby_version = '>= 1.9.2'
|
|
22
|
+
|
|
23
|
+
s.add_dependency 'lhc', '>= 0.2.0'
|
|
24
|
+
s.add_dependency 'lhc-core-interceptors', '>= 0.1.0'
|
|
25
|
+
|
|
26
|
+
s.add_development_dependency 'rspec-rails', '>= 3.0.0'
|
|
27
|
+
s.add_development_dependency 'rails', '>= 4.0.0'
|
|
28
|
+
s.add_development_dependency 'webmock'
|
|
29
|
+
s.add_development_dependency 'geminabox'
|
|
30
|
+
s.add_development_dependency 'pry'
|
|
31
|
+
end
|
data/lib/lhs.rb
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require File.join(__dir__, 'proxy.rb')
|
|
2
|
+
|
|
3
|
+
# A collection is a special type of data
|
|
4
|
+
# that contains multiple items
|
|
5
|
+
class LHS::Collection < LHS::Proxy
|
|
6
|
+
|
|
7
|
+
def total
|
|
8
|
+
_data._raw['total']
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def limit
|
|
12
|
+
_data._raw['limit']
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def offset
|
|
16
|
+
_data._raw['offset']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def href
|
|
20
|
+
_data._raw['href']
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def _collection
|
|
24
|
+
raw = _data._raw if _data._raw.is_a?(Array)
|
|
25
|
+
raw ||= _data._raw['items']
|
|
26
|
+
Collection.new(raw, _data, _data._service)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def _raw
|
|
30
|
+
_data._raw
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
protected
|
|
34
|
+
|
|
35
|
+
def method_missing(name, *args, &block)
|
|
36
|
+
value = _collection.send(name, *args, &block)
|
|
37
|
+
if value.is_a? Hash
|
|
38
|
+
data = LHS::Data.new(value, _data)
|
|
39
|
+
item = LHS::Item.new(data)
|
|
40
|
+
LHS::Data.new(item, _data)
|
|
41
|
+
else
|
|
42
|
+
value
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def respond_to_missing?(name, include_all = false)
|
|
47
|
+
_collection.respond_to?(name, include_all)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
# The internal collection class that includes enumerable
|
|
53
|
+
# and insures to return LHS::Items in case of iterating items
|
|
54
|
+
class Collection
|
|
55
|
+
include Enumerable
|
|
56
|
+
|
|
57
|
+
attr_accessor :raw
|
|
58
|
+
|
|
59
|
+
def initialize(raw, parent, service)
|
|
60
|
+
self.raw = raw
|
|
61
|
+
@parent = parent
|
|
62
|
+
@service = service
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def each(&block)
|
|
66
|
+
raw.each do |item|
|
|
67
|
+
if item.is_a? Hash
|
|
68
|
+
yield LHS::Data.new(item, @parent, @service)
|
|
69
|
+
else
|
|
70
|
+
yield item
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
delegate :sample, to: :raw
|
|
76
|
+
delegate :[], to: :raw
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'active_support'
|
|
2
|
+
require File.dirname(__FILE__) + '/../../proxy'
|
|
3
|
+
|
|
4
|
+
class LHS::Item < LHS::Proxy
|
|
5
|
+
|
|
6
|
+
module Destroy
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
def destroy
|
|
10
|
+
service_instance = _data._root._service.instance
|
|
11
|
+
_data._request = service_instance.request(method: :delete, url: href)._request
|
|
12
|
+
_data
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'active_support'
|
|
2
|
+
require File.dirname(__FILE__) + '/../../proxy'
|
|
3
|
+
|
|
4
|
+
class LHS::Item < LHS::Proxy
|
|
5
|
+
|
|
6
|
+
module Save
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
def save
|
|
10
|
+
save!
|
|
11
|
+
rescue LHC::Error => e
|
|
12
|
+
self.errors = LHS::Errors.new(e.response)
|
|
13
|
+
false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def save!
|
|
17
|
+
service = _data._root._service
|
|
18
|
+
data = _data._raw.dup
|
|
19
|
+
url = if href.present?
|
|
20
|
+
href
|
|
21
|
+
else
|
|
22
|
+
service.instance.find_endpoint(data).compile(data)
|
|
23
|
+
end
|
|
24
|
+
response = service.instance.request(method: :post, url: url, body: data.to_json, headers: {'Content-Type' => 'application/json'})
|
|
25
|
+
self._data.merge!(response)
|
|
26
|
+
true
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'active_support'
|
|
2
|
+
require File.dirname(__FILE__) + '/../../proxy'
|
|
3
|
+
|
|
4
|
+
class LHS::Item < LHS::Proxy
|
|
5
|
+
|
|
6
|
+
module Update
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
def update(params)
|
|
10
|
+
update!(params)
|
|
11
|
+
rescue LHC::Error => e
|
|
12
|
+
self.errors = LHS::Errors.new(e.response)
|
|
13
|
+
false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def update!(params)
|
|
17
|
+
service = _data._root._service
|
|
18
|
+
data = _data._raw.dup
|
|
19
|
+
response = service.instance.request(method: :post, url: href, body: data.merge(params).to_json, headers: {'Content-Type' => 'application/json'})
|
|
20
|
+
self._data.merge!(response)
|
|
21
|
+
true
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'active_support'
|
|
2
|
+
|
|
3
|
+
class LHS::Service
|
|
4
|
+
|
|
5
|
+
module All
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
|
|
10
|
+
def all(params = {})
|
|
11
|
+
all = []
|
|
12
|
+
data = instance.request(params: params.merge(limit: 100))
|
|
13
|
+
all.concat(data._raw['items'])
|
|
14
|
+
total_left = data._raw['total'] - data.count
|
|
15
|
+
requests = total_left / data._raw['limit']
|
|
16
|
+
requests.times do |i|
|
|
17
|
+
offset = data._raw['limit'] * (i+1) + 1
|
|
18
|
+
all.concat instance.request(params: params.merge(limit: data._raw['limit'], offset: offset))._raw['items']
|
|
19
|
+
end
|
|
20
|
+
LHS::Data.new(all, nil, self)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'active_support'
|
|
2
|
+
|
|
3
|
+
class LHS::Service
|
|
4
|
+
|
|
5
|
+
module Batch
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
|
|
10
|
+
# Process single entries fetched in batches
|
|
11
|
+
def find_each(options = {})
|
|
12
|
+
find_in_batches(options) do |data|
|
|
13
|
+
data.each do |record|
|
|
14
|
+
item = LHS::Item.new(LHS::Data.new(record, data, self.class))
|
|
15
|
+
yield LHS::Data.new(item, data, self.class)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Process batches of entries
|
|
21
|
+
def find_in_batches(options = {})
|
|
22
|
+
fail 'No block given' unless block_given?
|
|
23
|
+
start = options[:start] || 1
|
|
24
|
+
batch_size = options[:batch_size] || 100
|
|
25
|
+
params = options[:params] || {}
|
|
26
|
+
loop do # as suggested by Matz
|
|
27
|
+
data = instance.request(params: params.merge(limit: batch_size, offset: start))
|
|
28
|
+
batch_size = data._raw['limit']
|
|
29
|
+
left = data._raw['total'].to_i - data._raw['offset'].to_i - data._raw['limit'].to_i
|
|
30
|
+
yield data
|
|
31
|
+
break if left <= 0
|
|
32
|
+
start += batch_size
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|