alula-ruby 0.50.1

Sign up to get free protection for your applications and to get access to all the features.
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