alula-ruby 0.50.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +14 -0
  3. data/.env.example +8 -0
  4. data/.github/workflows/gem-push.yml +45 -0
  5. data/.gitignore +23 -0
  6. data/.rspec +3 -0
  7. data/.travis.yml +7 -0
  8. data/Dockerfile +6 -0
  9. data/Gemfile +12 -0
  10. data/Guardfile +42 -0
  11. data/README.md +423 -0
  12. data/Rakefile +6 -0
  13. data/VERSION.md +84 -0
  14. data/alula-docker-compose.yml +80 -0
  15. data/alula.gemspec +38 -0
  16. data/bin/console +15 -0
  17. data/bin/docparse +36 -0
  18. data/bin/genresource +79 -0
  19. data/bin/setup +8 -0
  20. data/bin/testauth +24 -0
  21. data/bin/testprep +9 -0
  22. data/data/docs/Alula_API_Documentation_2021-04-06.html +16240 -0
  23. data/docker-compose.yml +11 -0
  24. data/lib/alula/alula_response.rb +20 -0
  25. data/lib/alula/api_operations/delete.rb +52 -0
  26. data/lib/alula/api_operations/list.rb +45 -0
  27. data/lib/alula/api_operations/request.rb +44 -0
  28. data/lib/alula/api_operations/save.rb +81 -0
  29. data/lib/alula/api_resource.rb +196 -0
  30. data/lib/alula/client.rb +142 -0
  31. data/lib/alula/errors.rb +169 -0
  32. data/lib/alula/filter_builder.rb +271 -0
  33. data/lib/alula/helpers/device_attribute_translations.rb +68 -0
  34. data/lib/alula/list_object.rb +64 -0
  35. data/lib/alula/meta.rb +16 -0
  36. data/lib/alula/monkey_patches.rb +24 -0
  37. data/lib/alula/oauth.rb +118 -0
  38. data/lib/alula/pagination.rb +25 -0
  39. data/lib/alula/procedures/dealer_device_stats_proc.rb +16 -0
  40. data/lib/alula/procedures/dealer_restore_proc.rb +25 -0
  41. data/lib/alula/procedures/dealer_suspend_proc.rb +25 -0
  42. data/lib/alula/procedures/device_assign_proc.rb +23 -0
  43. data/lib/alula/procedures/device_cellular_history_proc.rb +33 -0
  44. data/lib/alula/procedures/device_rateplan_get_proc.rb +21 -0
  45. data/lib/alula/procedures/device_register_proc.rb +31 -0
  46. data/lib/alula/procedures/device_signal_add_proc.rb +42 -0
  47. data/lib/alula/procedures/device_signal_delivered_proc.rb +31 -0
  48. data/lib/alula/procedures/device_signal_update_proc.rb +32 -0
  49. data/lib/alula/procedures/device_unassign_proc.rb +16 -0
  50. data/lib/alula/procedures/device_unregister_proc.rb +21 -0
  51. data/lib/alula/procedures/upload_touchpad_branding_proc.rb +24 -0
  52. data/lib/alula/procedures/user_plansvideo_price_get.rb +21 -0
  53. data/lib/alula/procedures/user_transfer_accept.rb +19 -0
  54. data/lib/alula/procedures/user_transfer_authorize.rb +18 -0
  55. data/lib/alula/procedures/user_transfer_cancel.rb +18 -0
  56. data/lib/alula/procedures/user_transfer_deny.rb +19 -0
  57. data/lib/alula/procedures/user_transfer_reject.rb +19 -0
  58. data/lib/alula/procedures/user_transfer_request.rb +19 -0
  59. data/lib/alula/query_interface.rb +142 -0
  60. data/lib/alula/rate_limit.rb +11 -0
  61. data/lib/alula/relationship_attributes.rb +107 -0
  62. data/lib/alula/resource_attributes.rb +206 -0
  63. data/lib/alula/resources/admin_user.rb +207 -0
  64. data/lib/alula/resources/billing_program.rb +41 -0
  65. data/lib/alula/resources/dealer.rb +218 -0
  66. data/lib/alula/resources/dealer_account_transfer.rb +172 -0
  67. data/lib/alula/resources/dealer_address.rb +89 -0
  68. data/lib/alula/resources/dealer_branding.rb +226 -0
  69. data/lib/alula/resources/dealer_program.rb +75 -0
  70. data/lib/alula/resources/dealer_suspension_log.rb +49 -0
  71. data/lib/alula/resources/device.rb +716 -0
  72. data/lib/alula/resources/device_cellular_status.rb +134 -0
  73. data/lib/alula/resources/device_charge.rb +70 -0
  74. data/lib/alula/resources/device_event_log.rb +167 -0
  75. data/lib/alula/resources/device_program.rb +54 -0
  76. data/lib/alula/resources/event_trigger.rb +75 -0
  77. data/lib/alula/resources/event_webhook.rb +47 -0
  78. data/lib/alula/resources/feature_bysubject.rb +74 -0
  79. data/lib/alula/resources/feature_plan.rb +57 -0
  80. data/lib/alula/resources/feature_planvideo.rb +54 -0
  81. data/lib/alula/resources/feature_price.rb +46 -0
  82. data/lib/alula/resources/receiver_connection.rb +95 -0
  83. data/lib/alula/resources/receiver_group.rb +74 -0
  84. data/lib/alula/resources/revision.rb +91 -0
  85. data/lib/alula/resources/self.rb +61 -0
  86. data/lib/alula/resources/station.rb +130 -0
  87. data/lib/alula/resources/token_exchange.rb +34 -0
  88. data/lib/alula/resources/user.rb +229 -0
  89. data/lib/alula/resources/user_address.rb +121 -0
  90. data/lib/alula/resources/user_phone.rb +116 -0
  91. data/lib/alula/resources/user_preferences.rb +57 -0
  92. data/lib/alula/resources/user_pushtoken.rb +75 -0
  93. data/lib/alula/resources/user_videoprofile.rb +38 -0
  94. data/lib/alula/rest_resource.rb +17 -0
  95. data/lib/alula/rpc_resource.rb +40 -0
  96. data/lib/alula/rpc_response.rb +14 -0
  97. data/lib/alula/singleton_rest_resource.rb +26 -0
  98. data/lib/alula/util.rb +107 -0
  99. data/lib/alula/version.rb +5 -0
  100. data/lib/alula.rb +135 -0
  101. data/lib/parser.rb +199 -0
  102. metadata +282 -0
@@ -0,0 +1,11 @@
1
+ version: "3"
2
+ services:
3
+ alula-ruby:
4
+ build: ./
5
+ image: alula-ruby
6
+ volumes:
7
+ - .:/workdir
8
+ working_dir: /workdir
9
+ environment:
10
+ - API_URL=http://172.17.0.1:8800
11
+ - ALULA_SWARM_TEST_HELPER_URL=http://172.17.0.1:8850
@@ -0,0 +1,20 @@
1
+ module Alula
2
+ class AlulaResponse
3
+ attr_accessor :data, :http_body, :http_headers, :http_status, :raw, :rate_limit
4
+
5
+ def ok?
6
+ (200..299).cover?(self.http_status)
7
+ end
8
+
9
+ def self.from_httparty_response(response)
10
+ resp = AlulaResponse.new
11
+ resp.data = response.parsed_response
12
+ resp.http_body = response.body
13
+ resp.http_headers = response.headers
14
+ resp.rate_limit = Alula::RateLimit.new(response.headers)
15
+ resp.http_status = response.code
16
+ resp.raw = response
17
+ resp
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,52 @@
1
+ module Alula
2
+ module ApiOperations
3
+ module Delete
4
+ def self.extended(base)
5
+ base.include(InstanceMethods)
6
+ end
7
+
8
+ module InstanceMethods
9
+ def delete
10
+ # payload = {
11
+ # data: {
12
+ # id: id,
13
+ # attributes: as_patchable_json
14
+ # }
15
+ # }
16
+
17
+ response = Alula::Client.request(:delete, resource_url)
18
+
19
+ return true if response.ok?
20
+
21
+ handle_errors(response)
22
+ end
23
+
24
+ private
25
+
26
+ def handle_errors(response)
27
+ # Should never see a 300-range response code
28
+ if (300..399).cover?(response.http_status)
29
+ raise Alula::UnknownError, "The Alula-Ruby gem encountered a response code of #{response.code}, that should not happen"
30
+
31
+ # Server errors, malformed crap, etc
32
+ elsif (500..599).cover?(response.http_status)
33
+ return AlulaError.for_response(response)
34
+
35
+ # Validation errors usually
36
+ elsif (400..499).cover?(response.http_status)
37
+ model_errors = Util.model_errors_from_response(response)
38
+
39
+ if model_errors
40
+ annotate_errors(model_errors)
41
+ return false
42
+ else
43
+ return AlulaError.for_response(response)
44
+ end
45
+ else
46
+ raise Alula::UnknownError, "Unknown HTTP response code, aborting. Code: #{response.http_status}"
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,45 @@
1
+ module Alula
2
+ module ApiOperations
3
+ module List
4
+ def self.extended(base)
5
+ base.include(InstanceMethods)
6
+ end
7
+
8
+ def method_missing(method, *args, &block)
9
+ QueryInterface.new(self).send(method, *args, &block)
10
+ end
11
+
12
+ def list(filters = {}, opts = {})
13
+ response = Alula::Client.request(:get, resource_url, filters, opts)
14
+ if response.ok?
15
+ list = ListObject.construct_from_response(self, response, opts)
16
+ list = build_and_merge_list_relationships(list, response.data['included']) if response.data['included']
17
+ list
18
+ else
19
+ error_class = AlulaError.for_response(response)
20
+ raise error_class
21
+ end
22
+ end
23
+
24
+ def build_and_merge_list_relationships(collection, relations)
25
+ relations.each do |relation|
26
+ model = Alula.class_from_resource_type(relation['type'])
27
+ model = model.new.construct_from(relation)
28
+ key = { type: model.get_type, id: model.id }.freeze
29
+
30
+ #
31
+ # TODO: Remove this line. This makes us ignore unknown relationships
32
+ unless get_relationship(model.get_type).nil?
33
+ collection.select{ |m| m.link_matchers.include?(key) }
34
+ .each { |m| m.add_model_to_relationship(model) }
35
+ end
36
+ end
37
+
38
+ collection
39
+ end
40
+
41
+ module InstanceMethods
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,44 @@
1
+ module Alula
2
+ module ApiOperations
3
+ module Request
4
+ def self.extended(base)
5
+ base.include(InstanceMethods)
6
+ end
7
+
8
+ # Load a single model by ID
9
+ def retrieve(id, built_filters = {})
10
+ response = Alula::Client.request(:get, self.resource_url(id), built_filters, {})
11
+ if response.ok?
12
+ item = self.new.construct_from(response.data['data'])
13
+ item = build_and_merge_item_relationships(item, response.data['included']) if response.data['included']
14
+ item.rate_limit = response.rate_limit
15
+ item
16
+ else
17
+ error_class = AlulaError.for_response(response)
18
+ raise error_class
19
+ end
20
+ end
21
+
22
+ def build_and_merge_item_relationships(item, relations)
23
+ relations.each do |relation|
24
+ model = Alula.class_from_resource_type(relation['type'])
25
+ model = model.new.construct_from(relation)
26
+
27
+ #
28
+ # TODO: Remove this line. This makes us ignore unknown relationships
29
+ unless get_relationship(model.get_type).nil?
30
+ item.add_model_to_relationship(model)
31
+ end
32
+ end
33
+
34
+ item
35
+ end
36
+
37
+ module InstanceMethods
38
+ def request(method, url, params, opts)
39
+ Alula::Client.request(method, url, params, opts)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,81 @@
1
+ module Alula
2
+ module ApiOperations
3
+ module Save
4
+ def self.extended(base)
5
+ base.include(InstanceMethods)
6
+ end
7
+
8
+ module InstanceMethods
9
+ def save
10
+ payload = {
11
+ data: {
12
+ id: id,
13
+ attributes: as_patchable_json
14
+ }
15
+ }
16
+
17
+ response = Alula::Client.request(:patch, resource_url, payload, {})
18
+
19
+ if response.ok?
20
+ construct_from(response.data['data'])
21
+ return true
22
+ end
23
+
24
+ handle_errors(response)
25
+ end
26
+
27
+ def create
28
+ data = {
29
+ attributes: as_patchable_json
30
+ }
31
+ #
32
+ # Most creations _won't_ have an ID, but the Alula API utlizes a shared GUID strategy for a few resources
33
+ # We need to conditionally include this ID in the data array even though the record 'doesnt exist'
34
+ #
35
+ # - Dealer Branding shares the same primary ID as the Dealer record
36
+ # - Dealer Contact info shares the same primary ID as the Dealer record
37
+ data[:id] = id if id
38
+
39
+ payload = {
40
+ data: data
41
+ }
42
+
43
+ response = Alula::Client.request(:post, self.class.resource_url, payload, {})
44
+
45
+ if response.ok?
46
+ construct_from(response.data['data'])
47
+ return true
48
+ end
49
+
50
+ handle_errors(response)
51
+ end
52
+
53
+ private
54
+
55
+ def handle_errors(response)
56
+ # Should never see a 300-range response code
57
+ if (300..399).cover?(response.http_status)
58
+ raise Alula::UnknownError, "The Alula-Ruby gem encountered a response code of #{response.code}, that should not happen"
59
+
60
+ # Server errors, malformed crap, etc
61
+ elsif (500..599).cover?(response.http_status)
62
+ return AlulaError.for_response(response)
63
+
64
+ # Validation errors usually
65
+ elsif (400..499).cover?(response.http_status)
66
+ model_errors = Util.model_errors_from_response(response)
67
+
68
+ if model_errors
69
+ annotate_errors(model_errors)
70
+ return false
71
+ else
72
+ return AlulaError.for_response(response)
73
+ end
74
+ else
75
+ raise Alula::UnknownError, "Unknown HTTP response code, aborting. Code: #{response.http_status}"
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,196 @@
1
+ module Alula
2
+ # Parent class for all API objects
3
+ class ApiResource
4
+ attr_accessor :id, :raw_data, :values, :dirty_attributes, :errors, :links, :link_matchers, :rate_limit
5
+
6
+ def self.class_name
7
+ name.split("::")[-1]
8
+ end
9
+
10
+ def initialize(id = nil, attributes = {})
11
+ @raw_data = {}
12
+ @values = {}
13
+ @dirty_attributes = Set.new
14
+ @errors = ModelErrors.new(self.class)
15
+
16
+ construct_from(
17
+ 'id' => id,
18
+ 'attributes' => attributes
19
+ )
20
+ end
21
+
22
+ #
23
+ # Construct a new resource, ready to receive attributes, with
24
+ # empty values for all attrs.
25
+ # Useful for making New resources
26
+ # TODO: This will need testing and probably more work when we
27
+ # actually use it, at the moment we're only retrieving and
28
+ # modifying existing models.
29
+ def self.build
30
+ fields = self.get_fields.keys.map{ |k| Util.camelize(k) }
31
+ empty_shell = fields.each_with_object({}) { |f, obj| obj[f] = nil }
32
+ self.new(nil, empty_shell)
33
+ end
34
+
35
+ def construct_from(json_object)
36
+ @raw_data = json_object.dup
37
+ @values = json_object['attributes']
38
+
39
+ self.id = json_object['id'] unless [nil, ''].include?(json_object['id'])
40
+
41
+ @dirty_attributes = Set.new
42
+ @errors = ModelErrors.new(self.class)
43
+
44
+ @related_models = {}
45
+ cache_links(json_object['relationships'] || {})
46
+
47
+ self
48
+ end
49
+
50
+ #
51
+ # Take a hash of attributes and apply them to the model
52
+ def apply_attributes(attributes)
53
+ attributes.each do |key, value|
54
+ self.send("#{key}=", value)
55
+ end
56
+ end
57
+
58
+ def reconstruct_from(json_object)
59
+ construct_from(json_object)
60
+ end
61
+
62
+ def dirty?(attribute_name = nil)
63
+ return @dirty_attributes.any? if attribute_name.nil?
64
+
65
+ @dirty_attributes.include? attribute_name.to_sym
66
+ end
67
+
68
+ def errors?
69
+ @errors.any?
70
+ end
71
+
72
+ def refresh
73
+ response = Alula::Client.request(:get, resource_url, {}, {})
74
+ if response.ok?
75
+ model = construct_from(response.data['data'])
76
+ model.rate_limit = response.rate_limit
77
+ model
78
+ else
79
+ error_class = AlulaError.for_response(response)
80
+ raise error_class
81
+ end
82
+ end
83
+
84
+ #
85
+ # Fetch known attributes out of the object, collected into a Hash in camelCase format
86
+ # Intended for eventually making its way back up to the API
87
+ def as_json
88
+ self.field_names.each_with_object({}) do |ruby_key, obj|
89
+ key = Util.camelize(ruby_key)
90
+ val = self.send(ruby_key)
91
+
92
+ if self.date_fields.include?(ruby_key) && ![nil, ''].include?(val)
93
+ if val.respond_to? :strftime
94
+ obj[key] = val.strftime('%Y-%m-%dT%H:%M:%S.%L%z')
95
+ else
96
+ obj[key] = val.to_s
97
+ end
98
+ else
99
+ obj[key] = val
100
+ end
101
+ end
102
+ end
103
+
104
+ #
105
+ # Reduce as_json to a set that can be updated, removing any fields
106
+ # that are not patchable by the user
107
+ def as_patchable_json
108
+ values = as_json.each_pair.each_with_object({}) do |(key, value), collector|
109
+ ruby_key = Util.underscore(key).to_sym
110
+ collector[key] = value if !read_only_attributes.include?(ruby_key) && dirty?(ruby_key)
111
+ end
112
+
113
+ # Remove blank values if creating a new record
114
+ values = values.select{ |k, v| !v.nil? } unless persisted?
115
+ values
116
+ end
117
+
118
+ def annotate_errors(model_errors)
119
+ @errors = ModelErrors.new(self.class)
120
+ model_errors.each_pair do |field_name, error|
121
+ errors.add(field_name, error)
122
+ end
123
+ end
124
+
125
+ #
126
+ # Links are hashes that identify any included models, they are used to
127
+ # distribute included models when also including relationships
128
+ # See list.rb#build_and_merge_relationships for details on usage
129
+ def cache_links(links)
130
+ @links = links
131
+
132
+ @link_matchers = links.each_pair.each_with_object([]) do |(type, link), collection|
133
+ data = link['data']
134
+ next if data.nil?
135
+
136
+ if data.is_a?(Array)
137
+ data.each do |nested_link|
138
+ collection << { type: nested_link['type'], id: nested_link['id'] }.freeze
139
+ end
140
+ else
141
+ collection << { type: data['type'], id: data['id'] }.freeze
142
+ end
143
+ end
144
+ end
145
+
146
+ #
147
+ # Return an instance of QueryEngine annotated with the correct model attributes
148
+ def filter_builder
149
+ Alula::FilterBuilder.new(self.class)
150
+ end
151
+ alias fb filter_builder
152
+
153
+ def model_name
154
+ self.class
155
+ end
156
+
157
+ private
158
+
159
+ class ModelErrors
160
+ include Enumerable
161
+
162
+ def initialize(model_class)
163
+ @model_class = model_class
164
+ @details = {}
165
+ end
166
+
167
+ def each
168
+ @details.each do |field, error|
169
+ yield({ field => error })
170
+ end
171
+ end
172
+
173
+ def any?
174
+ @details.any?
175
+ end
176
+
177
+ def add(field_name, error_message)
178
+ @details[field_name] = error_message
179
+ end
180
+
181
+ def [](field_name)
182
+ @details[field_name.to_sym]
183
+ end
184
+
185
+ def full_messages
186
+ @details.map { |field, error| "#{field}: #{error}" }
187
+ end
188
+
189
+ def full_messages_for(attribute_name)
190
+ return nil unless @details[attribute_name.to_sym].present?
191
+
192
+ "#{attribute_name}: #{@details[attribute_name.to_sym]}"
193
+ end
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,142 @@
1
+ require 'httparty'
2
+ require 'alula/monkey_patches'
3
+
4
+ module Alula
5
+ class Client
6
+ include HTTParty
7
+ class << self
8
+ # Has pseudo accessors :api_key, :api_url, :user_agent, :debug
9
+ DEFAULT_CUSTOM_OPTIONS = {
10
+ omitRelationships: true
11
+ }
12
+
13
+ def request(http_method, resource_path, filters = {}, opts = {})
14
+ ensure_api_key_set
15
+ ensure_role_set if %i[patch post put].include? http_method
16
+ ensure_method_allowable(http_method)
17
+
18
+ raise Alula::NotConfiguredError, 'did you forget to set the Alula::Client.api_url config option?' unless api_url
19
+
20
+ request_opts = {
21
+ headers: {
22
+ 'Authorization': "Bearer #{api_key}",
23
+ 'User-Agent': "#{user_agent || 'No Agent Set'}/alula-ruby v#{Alula::VERSION}"
24
+ }
25
+ }.merge(opts)
26
+
27
+ request_opts[:headers]['Content-Type'] = 'application/json' unless opts[:multipart]
28
+ case http_method
29
+ when :patch,
30
+ :post
31
+ request_opts[:body] = opts[:multipart] ? filters : JSON.generate(filters)
32
+ when :get
33
+ if resource_path.match(%r{^/rest})
34
+ request_opts = request_opts.merge build_rest_options(filters)
35
+ elsif resource_path.match(%r{^/rpc})
36
+ request_opts = request_opts.merge build_rest_options(filters)
37
+ end
38
+ when :delete
39
+ # Nothing special
40
+ end
41
+
42
+ if debug == true
43
+ request_opts[:debug_output] = Alula.logger
44
+ logger Alula.logger, :info
45
+ end
46
+
47
+ # TODO: Handle network failures
48
+ response = make_request(http_method, api_url + resource_path, request_opts)
49
+
50
+ begin
51
+ resp = AlulaResponse.from_httparty_response(response)
52
+ rescue JSON::ParserError
53
+ # TODO: Should be able to send better info up with this
54
+ raise 'Unable to decode JSON'
55
+ end
56
+
57
+ resp
58
+ end
59
+
60
+ def make_request(http_method, full_url, request_opts)
61
+ send(http_method, full_url, request_opts)
62
+ end
63
+
64
+ #
65
+ # Using RequestStore so we're thread safe even with our non-thread-safe architecture :(
66
+ %i[api_key api_url user_agent debug].each do |prop|
67
+ define_method(prop) do
68
+ RequestStore.store["alula_#{prop}"]
69
+ end
70
+
71
+ define_method("#{prop}=") do |value|
72
+ RequestStore.store["alula_#{prop}"] = value
73
+ end
74
+ end
75
+
76
+ #
77
+ # Stash the user type as a role for us to infer from later
78
+ # You can set a symbolized role via role = :user, or provide the string userType
79
+ # We cast to a symbolized role for ease of use in consumers.
80
+ def role=(user_type)
81
+ unless user_type.is_a?(Symbol) || user_type.is_a?(String)
82
+ raise Alula::InvalidRoleError, 'Role must be symbol or string'
83
+ end
84
+
85
+ RequestStore.store['alula_role'] = Util.underscore(user_type).to_sym
86
+ end
87
+
88
+ def role
89
+ RequestStore.store['alula_role']
90
+ end
91
+
92
+ def ensure_api_key_set
93
+ if api_key.nil?
94
+ raise Alula::NotConfiguredError,
95
+ 'Set your API access token before making requests with Alula::Client.api_key = {access_token}'
96
+ end
97
+ end
98
+
99
+ def ensure_method_allowable(http_method)
100
+ unless %i[get post put patch delete].include?(http_method)
101
+ raise "Unable to send a request with #{http_method} http method in #{self::OBJECT_NAME} class"
102
+ end
103
+ end
104
+
105
+ def ensure_role_set
106
+ if role.nil?
107
+ message = 'User role not configured! You must set '\
108
+ 'Alula::Client.role '\
109
+ 'before attempting to save any resources'
110
+
111
+ raise Alula::NotConfiguredError, message
112
+ end
113
+ end
114
+
115
+ private
116
+
117
+ def build_rest_options(filters)
118
+ request_opts = {}
119
+
120
+ custom_options = filters.delete(:customOptions)
121
+ pagination = filters.delete(:page)
122
+ relationships = filters.delete(:include)
123
+ sort = filters.delete(:sort)
124
+
125
+ request_opts[:query] = {
126
+ filter: filters
127
+ }
128
+
129
+ request_opts[:query][:customOptions] = Util.deep_merge(DEFAULT_CUSTOM_OPTIONS, custom_options)
130
+ request_opts[:query][:page] = pagination if pagination
131
+ request_opts[:query][:include] = relationships if relationships
132
+ request_opts[:query][:sort] = sort if sort
133
+
134
+ request_opts
135
+ end
136
+
137
+ def build_rpc_options(filters)
138
+ filters
139
+ end
140
+ end
141
+ end
142
+ end