lockstep_rails 0.3.22
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/MIT-LICENSE +20 -0
- data/README.md +216 -0
- data/Rakefile +31 -0
- data/app/assets/config/lockstep_rails_manifest.js +0 -0
- data/app/concepts/lockstep/active_records/association.rb +78 -0
- data/app/concepts/lockstep/api_record.rb +1118 -0
- data/app/concepts/lockstep/api_records/scopes.rb +20 -0
- data/app/concepts/lockstep/client.rb +162 -0
- data/app/concepts/lockstep/error.rb +50 -0
- data/app/concepts/lockstep/exceptions.rb +4 -0
- data/app/concepts/lockstep/query.rb +409 -0
- data/app/concepts/lockstep/query_methods.rb +75 -0
- data/app/concepts/lockstep/relation_array.rb +100 -0
- data/app/helpers/types.rb +3 -0
- data/app/models/lockstep/account.rb +15 -0
- data/app/models/lockstep/connection.rb +19 -0
- data/app/models/lockstep/contact.rb +9 -0
- data/app/models/lockstep/customer_summary.rb +6 -0
- data/app/models/lockstep/invoice.rb +7 -0
- data/app/models/lockstep/invoice_summary.rb +6 -0
- data/app/models/lockstep/invoices/address.rb +24 -0
- data/app/models/lockstep/note.rb +7 -0
- data/app/models/lockstep/payment.rb +7 -0
- data/app/models/lockstep/payment_summary.rb +6 -0
- data/app/models/lockstep/user.rb +10 -0
- data/app/platform_api/model_template.rb.erb +27 -0
- data/app/platform_api/schema/action_result.rb +15 -0
- data/app/platform_api/schema/activity.rb +141 -0
- data/app/platform_api/schema/activity_fetch_result.rb +26 -0
- data/app/platform_api/schema/activity_stream_item.rb +58 -0
- data/app/platform_api/schema/activity_x_ref.rb +37 -0
- data/app/platform_api/schema/aging.rb +24 -0
- data/app/platform_api/schema/api_key.rb +71 -0
- data/app/platform_api/schema/api_key_fetch_result.rb +26 -0
- data/app/platform_api/schema/app_enrollment.rb +88 -0
- data/app/platform_api/schema/app_enrollment_custom_field.rb +67 -0
- data/app/platform_api/schema/app_enrollment_custom_field_fetch_result.rb +26 -0
- data/app/platform_api/schema/app_enrollment_fetch_result.rb +26 -0
- data/app/platform_api/schema/application.rb +89 -0
- data/app/platform_api/schema/application_fetch_result.rb +26 -0
- data/app/platform_api/schema/ar_aging_header_info.rb +47 -0
- data/app/platform_api/schema/ar_header_info.rb +118 -0
- data/app/platform_api/schema/assembly.rb +68 -0
- data/app/platform_api/schema/at_risk_invoice_summary.rb +90 -0
- data/app/platform_api/schema/at_risk_invoice_summary_fetch_result.rb +26 -0
- data/app/platform_api/schema/attachment.rb +92 -0
- data/app/platform_api/schema/attachment_fetch_result.rb +26 -0
- data/app/platform_api/schema/attachment_header_info.rb +41 -0
- data/app/platform_api/schema/batch_sync.rb +18 -0
- data/app/platform_api/schema/bulk_currency_conversion.rb +19 -0
- data/app/platform_api/schema/cashflow_report.rb +35 -0
- data/app/platform_api/schema/code_definition.rb +58 -0
- data/app/platform_api/schema/code_definition_fetch_result.rb +26 -0
- data/app/platform_api/schema/company.rb +243 -0
- data/app/platform_api/schema/company_fetch_result.rb +26 -0
- data/app/platform_api/schema/company_sync.rb +142 -0
- data/app/platform_api/schema/connector_info.rb +27 -0
- data/app/platform_api/schema/constructor_info.rb +128 -0
- data/app/platform_api/schema/contact.rb +148 -0
- data/app/platform_api/schema/contact_fetch_result.rb +26 -0
- data/app/platform_api/schema/contact_sync.rb +109 -0
- data/app/platform_api/schema/country.rb +62 -0
- data/app/platform_api/schema/country_fetch_result.rb +26 -0
- data/app/platform_api/schema/credit_memo_applied.rb +104 -0
- data/app/platform_api/schema/credit_memo_applied_fetch_result.rb +26 -0
- data/app/platform_api/schema/credit_memo_applied_sync.rb +67 -0
- data/app/platform_api/schema/credit_memo_invoice.rb +77 -0
- data/app/platform_api/schema/currency.rb +31 -0
- data/app/platform_api/schema/currency_fetch_result.rb +26 -0
- data/app/platform_api/schema/currency_rate.rb +28 -0
- data/app/platform_api/schema/custom_attribute_data.rb +18 -0
- data/app/platform_api/schema/custom_attribute_named_argument.rb +24 -0
- data/app/platform_api/schema/custom_attribute_typed_argument.rb +16 -0
- data/app/platform_api/schema/custom_field_definition.rb +76 -0
- data/app/platform_api/schema/custom_field_definition_fetch_result.rb +26 -0
- data/app/platform_api/schema/custom_field_sync.rb +71 -0
- data/app/platform_api/schema/custom_field_value.rb +75 -0
- data/app/platform_api/schema/custom_field_value_fetch_result.rb +26 -0
- data/app/platform_api/schema/customer_details.rb +98 -0
- data/app/platform_api/schema/customer_details_payment.rb +60 -0
- data/app/platform_api/schema/customer_summary.rb +88 -0
- data/app/platform_api/schema/customer_summary_fetch_result.rb +26 -0
- data/app/platform_api/schema/daily_sales_outstanding_report.rb +25 -0
- data/app/platform_api/schema/developer_account_submit.rb +23 -0
- data/app/platform_api/schema/email.rb +160 -0
- data/app/platform_api/schema/email_fetch_result.rb +26 -0
- data/app/platform_api/schema/erp.rb +23 -0
- data/app/platform_api/schema/erp_fetch_result.rb +26 -0
- data/app/platform_api/schema/erp_info.rb +18 -0
- data/app/platform_api/schema/erp_info_data.rb +23 -0
- data/app/platform_api/schema/event_info.rb +59 -0
- data/app/platform_api/schema/exception.rb +41 -0
- data/app/platform_api/schema/field_info.rb +105 -0
- data/app/platform_api/schema/financial_account.rb +90 -0
- data/app/platform_api/schema/financial_account_balance_history.rb +90 -0
- data/app/platform_api/schema/financial_account_balance_history_fetch_result.rb +26 -0
- data/app/platform_api/schema/financial_account_fetch_result.rb +26 -0
- data/app/platform_api/schema/financial_year_setting.rb +74 -0
- data/app/platform_api/schema/financial_year_setting_fetch_result.rb +26 -0
- data/app/platform_api/schema/invite.rb +25 -0
- data/app/platform_api/schema/invite_data.rb +18 -0
- data/app/platform_api/schema/invite_submit.rb +15 -0
- data/app/platform_api/schema/invoice.rb +226 -0
- data/app/platform_api/schema/invoice_address.rb +97 -0
- data/app/platform_api/schema/invoice_fetch_result.rb +29 -0
- data/app/platform_api/schema/invoice_history.rb +188 -0
- data/app/platform_api/schema/invoice_history_fetch_result.rb +26 -0
- data/app/platform_api/schema/invoice_line.rb +142 -0
- data/app/platform_api/schema/invoice_line_sync.rb +208 -0
- data/app/platform_api/schema/invoice_payment_detail.rb +65 -0
- data/app/platform_api/schema/invoice_summary.rb +85 -0
- data/app/platform_api/schema/invoice_summary_fetch_result.rb +26 -0
- data/app/platform_api/schema/invoice_sync.rb +280 -0
- data/app/platform_api/schema/lead.rb +32 -0
- data/app/platform_api/schema/member_info.rb +36 -0
- data/app/platform_api/schema/method_base.rb +128 -0
- data/app/platform_api/schema/method_info.rb +137 -0
- data/app/platform_api/schema/module.rb +44 -0
- data/app/platform_api/schema/module_handle.rb +15 -0
- data/app/platform_api/schema/note.rb +72 -0
- data/app/platform_api/schema/note_fetch_result.rb +26 -0
- data/app/platform_api/schema/parameter_info.rb +64 -0
- data/app/platform_api/schema/payment.rb +147 -0
- data/app/platform_api/schema/payment_applied.rb +95 -0
- data/app/platform_api/schema/payment_applied_fetch_result.rb +26 -0
- data/app/platform_api/schema/payment_applied_sync.rb +74 -0
- data/app/platform_api/schema/payment_detail.rb +110 -0
- data/app/platform_api/schema/payment_detail_fetch_result.rb +26 -0
- data/app/platform_api/schema/payment_detail_header.rb +43 -0
- data/app/platform_api/schema/payment_fetch_result.rb +26 -0
- data/app/platform_api/schema/payment_summary.rb +79 -0
- data/app/platform_api/schema/payment_summary_fetch_result.rb +26 -0
- data/app/platform_api/schema/payment_sync.rb +112 -0
- data/app/platform_api/schema/problem_details.rb +31 -0
- data/app/platform_api/schema/property_info.rb +60 -0
- data/app/platform_api/schema/provisioning.rb +28 -0
- data/app/platform_api/schema/provisioning_finalize_request.rb +28 -0
- data/app/platform_api/schema/provisioning_response.rb +42 -0
- data/app/platform_api/schema/risk_rate.rb +57 -0
- data/app/platform_api/schema/runtime_field_handle.rb +13 -0
- data/app/platform_api/schema/runtime_method_handle.rb +13 -0
- data/app/platform_api/schema/runtime_type_handle.rb +13 -0
- data/app/platform_api/schema/state.rb +22 -0
- data/app/platform_api/schema/state_fetch_result.rb +26 -0
- data/app/platform_api/schema/status.rb +72 -0
- data/app/platform_api/schema/struct_layout_attribute.rb +16 -0
- data/app/platform_api/schema/sync_entity_result.rb +34 -0
- data/app/platform_api/schema/sync_request.rb +71 -0
- data/app/platform_api/schema/sync_request_fetch_result.rb +26 -0
- data/app/platform_api/schema/sync_submit.rb +15 -0
- data/app/platform_api/schema/test_argument_exception.rb +41 -0
- data/app/platform_api/schema/test_timeout_exception.rb +41 -0
- data/app/platform_api/schema/transfer_owner.rb +16 -0
- data/app/platform_api/schema/transfer_owner_submit.rb +15 -0
- data/app/platform_api/schema/type.rb +278 -0
- data/app/platform_api/schema/type_info.rb +287 -0
- data/app/platform_api/schema/uri.rb +15 -0
- data/app/platform_api/schema/user_account.rb +152 -0
- data/app/platform_api/schema/user_account_fetch_result.rb +26 -0
- data/app/platform_api/schema/user_role.rb +50 -0
- data/app/platform_api/schema/user_role_fetch_result.rb +26 -0
- data/app/platform_api/schema/webhook.rb +96 -0
- data/app/platform_api/schema/webhook_fetch_result.rb +26 -0
- data/app/platform_api/schema/webhook_history_table_storage.rb +64 -0
- data/app/platform_api/schema/webhook_history_table_storage_fetch_result.rb +26 -0
- data/app/platform_api/swagger.json +22056 -0
- data/config/routes.rb +2 -0
- data/lib/lockstep_rails/engine.rb +4 -0
- data/lib/lockstep_rails/version.rb +3 -0
- data/lib/lockstep_rails.rb +5 -0
- data/lib/tasks/lockstep_rails_tasks.rake +4 -0
- data/lib/tasks/update_api_schema.rake +159 -0
- metadata +230 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
module Lockstep::ApiRecords::Scopes
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
class_methods do
|
5
|
+
def scopes
|
6
|
+
@scopes ||= {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def default_scope(&block)
|
10
|
+
scopes[:default_scope] = block if block_given?
|
11
|
+
scopes[:default_scope]
|
12
|
+
end
|
13
|
+
|
14
|
+
def scope(name, block)
|
15
|
+
scopes[name] = block
|
16
|
+
define_singleton_method name, &block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'openssl'
|
3
|
+
require 'uri'
|
4
|
+
require 'socket'
|
5
|
+
|
6
|
+
module Lockstep
|
7
|
+
class Client
|
8
|
+
|
9
|
+
|
10
|
+
def self.set_bearer_token(token)
|
11
|
+
RequestStore.store[:lockstep_bearer_token] = token
|
12
|
+
RequestStore.store[:lockstep_api_key] = nil
|
13
|
+
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.bearer_token
|
18
|
+
RequestStore.store[:lockstep_bearer_token]
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.set_api_key(key)
|
22
|
+
RequestStore.store[:lockstep_api_key] = key
|
23
|
+
RequestStore.store[:lockstep_bearer_token] = nil
|
24
|
+
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.api_key
|
29
|
+
RequestStore.store[:lockstep_api_key]
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
##
|
34
|
+
# Construct a new Lockstep API client targeting the specified server.
|
35
|
+
#
|
36
|
+
# @param env [string] Either "sbx", "prd", or the URI of the server, ending in a slash (/)
|
37
|
+
def initialize(env)
|
38
|
+
@version = "2022.4.32.0"
|
39
|
+
@env = case env
|
40
|
+
when "sbx"
|
41
|
+
"https://api.sbx.lockstep.io/"
|
42
|
+
when "prd"
|
43
|
+
"https://api.lockstep.io/"
|
44
|
+
else
|
45
|
+
env
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Configure this API client to use API key authentication
|
51
|
+
#
|
52
|
+
# @param api_key [string] The [Lockstep Platform API key](https://developer.lockstep.io/docs/api-keys) to use for authentication
|
53
|
+
def with_api_key(api_key)
|
54
|
+
self.class.set_api_key(api_key)
|
55
|
+
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Configure this API client to use JWT Bearer Token authentication
|
61
|
+
#
|
62
|
+
# @param bearer_token [string] The [JWT Bearer Token](https://developer.lockstep.io/docs/jwt-bearer-tokens) to use for authentication
|
63
|
+
def with_bearer_token(token)
|
64
|
+
self.class.set_bearer_token(token)
|
65
|
+
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
def bearer_token
|
70
|
+
self.class.bearer_token
|
71
|
+
end
|
72
|
+
|
73
|
+
def api_key
|
74
|
+
self.class.api_key
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Configure this API to use an application name
|
79
|
+
#
|
80
|
+
# @param app_name [string] The name of the application
|
81
|
+
def with_app_name(app_name)
|
82
|
+
@app_name = app_name
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# Send a request to the API and return the results
|
87
|
+
#
|
88
|
+
# Sends a request to the
|
89
|
+
def request(method, path, body, params)
|
90
|
+
|
91
|
+
url = URI(@env + path)
|
92
|
+
if !params.nil?
|
93
|
+
url.query = URI.encode_www_form(params)
|
94
|
+
end
|
95
|
+
|
96
|
+
http = Net::HTTP.new(url.host, url.port)
|
97
|
+
http.use_ssl = true
|
98
|
+
|
99
|
+
request = case method
|
100
|
+
when :get
|
101
|
+
Net::HTTP::Get.new(url)
|
102
|
+
when :post
|
103
|
+
Net::HTTP::Post.new(url)
|
104
|
+
when :patch
|
105
|
+
Net::HTTP::Patch.new(url)
|
106
|
+
when :put
|
107
|
+
Net::HTTP::Put.new(url)
|
108
|
+
when :delete
|
109
|
+
Net::HTTP::Delete.new(url)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Set headers and body for request
|
113
|
+
request["Accept"] = 'application/json'
|
114
|
+
request["Content-Type"] = 'application/*+json'
|
115
|
+
request["SdkType"] = 'Ruby'
|
116
|
+
request["SdkVersion"] = '2022.4.32.0'
|
117
|
+
request["MachineName"] = Socket.gethostname
|
118
|
+
body = body.to_json unless body.is_a?(String)
|
119
|
+
request.body = body
|
120
|
+
|
121
|
+
# If there is an application name
|
122
|
+
if @app_name != nil
|
123
|
+
request["ApplicationName"] = @app_name
|
124
|
+
end
|
125
|
+
|
126
|
+
# Which authentication are we using?
|
127
|
+
if api_key != nil
|
128
|
+
request["Api-Key"] = api_key
|
129
|
+
end
|
130
|
+
if bearer_token != nil
|
131
|
+
request["Authorization"] = 'Bearer ' + bearer_token
|
132
|
+
end
|
133
|
+
|
134
|
+
# Send the request
|
135
|
+
http.request(request)
|
136
|
+
end
|
137
|
+
|
138
|
+
def get(path, params: {})
|
139
|
+
request(:get, path, nil, params)
|
140
|
+
end
|
141
|
+
|
142
|
+
def post(path, body: {}, params: {})
|
143
|
+
request(:post, path, body, params)
|
144
|
+
end
|
145
|
+
|
146
|
+
def patch(path, body: {}, params: {})
|
147
|
+
request(:patch, path, body, params)
|
148
|
+
end
|
149
|
+
|
150
|
+
def put(path, body: {}, params: {})
|
151
|
+
request(:put, path, body, params)
|
152
|
+
end
|
153
|
+
|
154
|
+
def delete(path)
|
155
|
+
request(:delete, path, {}, {})
|
156
|
+
end
|
157
|
+
|
158
|
+
def with_logger(&block)
|
159
|
+
block.call
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class Lockstep::Error
|
2
|
+
# ParseError actually represents both HTTP & parse.com error codes. If the
|
3
|
+
# HTTP response is 400, one can inspect the first element of the error
|
4
|
+
# converted to_array for the HTTP error code and the 2nd element for the
|
5
|
+
# parse error response.
|
6
|
+
attr_accessor :msg, :code, :error
|
7
|
+
|
8
|
+
# @param [String] an error code, e.g. "400"
|
9
|
+
# @param [Object] an optional error mesg/object.
|
10
|
+
def initialize(code, msg="")
|
11
|
+
@msg = msg
|
12
|
+
@code = code
|
13
|
+
case code.to_s
|
14
|
+
when "111"
|
15
|
+
@error = "Invalid type."
|
16
|
+
when "135"
|
17
|
+
@error = "Unknown device type."
|
18
|
+
when "202"
|
19
|
+
@error = "Username already taken."
|
20
|
+
when "203"
|
21
|
+
@error = "Email already taken."
|
22
|
+
when "400"
|
23
|
+
@error = "Bad Request: The request cannot be fulfilled due to bad syntax."
|
24
|
+
when "401"
|
25
|
+
@error = "Unauthorized: Check your App ID & Master Key."
|
26
|
+
when "403"
|
27
|
+
@error = "Forbidden: You do not have permission to access or modify this."
|
28
|
+
when "408"
|
29
|
+
@error = "Request Timeout: The request was not completed within the time the server was prepared to wait."
|
30
|
+
when "415"
|
31
|
+
@error = "Unsupported Media Type"
|
32
|
+
when "500"
|
33
|
+
@error = "Internal Server Error"
|
34
|
+
when "502"
|
35
|
+
@error = "Bad Gateway"
|
36
|
+
when "503"
|
37
|
+
@error = "Service Unavailable"
|
38
|
+
when "508"
|
39
|
+
@error = "Loop Detected"
|
40
|
+
else
|
41
|
+
@error = "Unknown Error"
|
42
|
+
raise "Parse error #{code}: #{@error} #{@msg}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_array
|
47
|
+
[ @code, @msg ]
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,409 @@
|
|
1
|
+
class Lockstep::Query
|
2
|
+
def initialize(klass)
|
3
|
+
@klass = klass
|
4
|
+
end
|
5
|
+
|
6
|
+
def model
|
7
|
+
@klass
|
8
|
+
end
|
9
|
+
|
10
|
+
# Clone is used as return object as it messes with the OR query in situations like these
|
11
|
+
# unscoped = Lockstep::Connection.unscoped
|
12
|
+
# unscoped.where(a: 1).or(unscoped.where(b: 1))
|
13
|
+
# both the where conditions in the above scenario is modifying the same object causing stack-overflow
|
14
|
+
def clone
|
15
|
+
c = Lockstep::Query.new(@klass)
|
16
|
+
c.criteria.deep_merge!(self.criteria.deep_dup)
|
17
|
+
c
|
18
|
+
end
|
19
|
+
|
20
|
+
def with_clone(&block)
|
21
|
+
c = clone
|
22
|
+
c.instance_exec(&block)
|
23
|
+
c
|
24
|
+
end
|
25
|
+
|
26
|
+
def criteria
|
27
|
+
@criteria ||= { :conditions => [] }
|
28
|
+
end
|
29
|
+
|
30
|
+
def or(query)
|
31
|
+
with_clone do
|
32
|
+
criteria[:conditions] << { type: "or", query: query }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def none
|
37
|
+
with_clone do
|
38
|
+
criteria[:none] = true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def where(args)
|
43
|
+
if args.is_a?(Hash)
|
44
|
+
args.each do |k, v|
|
45
|
+
return none if v.is_a?(Array) and v.blank?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
with_clone do
|
50
|
+
criteria[:conditions] << convert_arg(args)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def convert_arg(arg)
|
55
|
+
return arg.to_pointer if arg.is_a?(Lockstep::ApiRecord)
|
56
|
+
return Lockstep::ApiRecord.to_date_object(arg) if arg.is_a?(Time) || arg.is_a?(Date)
|
57
|
+
if arg.is_a?(Hash)
|
58
|
+
arg.keys.each do |key|
|
59
|
+
@klass.valid_attribute?(key, raise_exception: true)
|
60
|
+
end
|
61
|
+
return arg.update(arg) { |key, inner_arg| convert_arg(inner_arg) }
|
62
|
+
end
|
63
|
+
|
64
|
+
arg
|
65
|
+
end
|
66
|
+
|
67
|
+
def limit(limit)
|
68
|
+
with_clone do
|
69
|
+
# If > 1000, set chunking, because large queries over 1000 need it with Parse
|
70
|
+
# criteria[:chunk] = 1000 if limit > 1000
|
71
|
+
criteria[:limit] = limit
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def page(page_number)
|
76
|
+
with_clone do
|
77
|
+
criteria[:page_number] = page_number
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def include_object(*objects)
|
82
|
+
with_clone do
|
83
|
+
criteria[:include] ||= []
|
84
|
+
criteria[:include] += objects
|
85
|
+
criteria[:include].uniq!
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# attr: {customer_name: :desc}
|
90
|
+
def order(*attr)
|
91
|
+
with_clone do
|
92
|
+
criteria[:order] ||= []
|
93
|
+
attr.each do |item|
|
94
|
+
if item.is_a?(Hash)
|
95
|
+
item.each do |k, v|
|
96
|
+
criteria[:order] << "#{k.to_s.camelize.upcase} #{v}"
|
97
|
+
end
|
98
|
+
elsif item.is_a?(String)
|
99
|
+
criteria[:order] << item
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# attr: {customer_name: :desc}
|
106
|
+
def reorder(attr)
|
107
|
+
with_clone do
|
108
|
+
criteria[:order] = []
|
109
|
+
order(attr)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Divides the query into multiple chunks if you're running into RestClient::BadRequest errors.
|
114
|
+
def chunk(count = 100)
|
115
|
+
with_clone do
|
116
|
+
criteria[:chunk] = count
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# def related_to(obj, key)
|
121
|
+
# query = { "$relatedTo" => { "object" => obj.to_pointer, "key" => key } }
|
122
|
+
# criteria[:conditions].merge!(query)
|
123
|
+
# clone
|
124
|
+
# end
|
125
|
+
|
126
|
+
def build_filter
|
127
|
+
filter = ""
|
128
|
+
criteria[:conditions].each do |condition|
|
129
|
+
if condition.is_a?(Hash)
|
130
|
+
if condition[:type] == "or"
|
131
|
+
filter = build_filter_condition(filter, "OR", condition[:query].build_filter)
|
132
|
+
else
|
133
|
+
condition.each do |key, value|
|
134
|
+
filter = build_filter_condition(filter, "AND", build_filter_query(key, value))
|
135
|
+
end
|
136
|
+
end
|
137
|
+
elsif condition.is_a?(String)
|
138
|
+
filter = build_filter_condition(filter, "AND", condition)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
filter
|
142
|
+
end
|
143
|
+
|
144
|
+
def build_filter_condition(filter, merge_predicate, condition)
|
145
|
+
if filter.present?
|
146
|
+
filter = "(#{filter}) #{merge_predicate} (#{condition})"
|
147
|
+
else
|
148
|
+
filter += condition
|
149
|
+
end
|
150
|
+
filter
|
151
|
+
end
|
152
|
+
|
153
|
+
PREDICATES = {
|
154
|
+
_not_eq: "NE",
|
155
|
+
_eq: "EQ",
|
156
|
+
_gteq: "GE",
|
157
|
+
_gt: "GT",
|
158
|
+
_lteq: "LE",
|
159
|
+
_lt: "LT",
|
160
|
+
_in: "IN",
|
161
|
+
_contains: "CONTAINS",
|
162
|
+
_starts_with: "STARTSWITH",
|
163
|
+
_ends_with: "ENDSWITH",
|
164
|
+
_is: "IS",
|
165
|
+
}.with_indifferent_access
|
166
|
+
|
167
|
+
def build_filter_query(key, value)
|
168
|
+
key = key.to_s unless key.is_a?(String)
|
169
|
+
predicate = "eq" # default
|
170
|
+
PREDICATES.each do |k, p|
|
171
|
+
if key.ends_with?(k)
|
172
|
+
key = key.gsub(k, "")
|
173
|
+
predicate = p
|
174
|
+
break
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# Build value
|
179
|
+
if value.is_a?(Array)
|
180
|
+
value = "(#{value.map { |v| v.is_a?(String) ? "'#{v}'" : v }.join(",")})"
|
181
|
+
predicate = "in" if predicate == "eq"
|
182
|
+
elsif value.is_a?(String) and !["NULL", "NOT NULL"].include?(value)
|
183
|
+
value = "'#{value}'"
|
184
|
+
elsif value.nil?
|
185
|
+
predicate = "IS" if predicate == "eq"
|
186
|
+
value = "NULL"
|
187
|
+
end
|
188
|
+
|
189
|
+
"#{key.camelize(:lower)} #{predicate} #{value}"
|
190
|
+
end
|
191
|
+
|
192
|
+
def build_params
|
193
|
+
params = {}
|
194
|
+
params.merge!({ :filter => build_filter }) if criteria[:conditions]
|
195
|
+
# Lockstep Platform API does not support a page size of 1
|
196
|
+
params.merge!({ :pageSize => (criteria[:limit] == 1 ? 2 : criteria[:limit]) }) if criteria[:limit]
|
197
|
+
params.merge!({ :pageNumber => criteria[:page_number] }) if criteria[:page_number]
|
198
|
+
params.merge!({ :include => criteria[:include].join(",") }) if criteria[:include]
|
199
|
+
params.merge!({ :order => criteria[:order].join(",") }) if criteria[:order]
|
200
|
+
params.merge!({ :pageSize => 2 }) if criteria[:count]
|
201
|
+
params.reject! { |k, v| v.blank? }
|
202
|
+
params
|
203
|
+
end
|
204
|
+
|
205
|
+
def execute
|
206
|
+
return [] if criteria[:none]
|
207
|
+
# This code automatically adds all related objects
|
208
|
+
#
|
209
|
+
# if @klass.has_many_relations
|
210
|
+
# relations = @klass.has_many_relations.select {|k, val| val[:included]}.keys.map { |relation| relation.to_s }
|
211
|
+
# include_object(*relations)
|
212
|
+
# end
|
213
|
+
|
214
|
+
params = build_params
|
215
|
+
|
216
|
+
return chunk_results(params) if criteria[:chunk]
|
217
|
+
|
218
|
+
get_results(params)
|
219
|
+
end
|
220
|
+
|
221
|
+
def get_results(params = {})
|
222
|
+
resp = @klass.resource.get(@klass.query_path, :params => params)
|
223
|
+
|
224
|
+
return [] if %w(404).include?(resp.code.to_s)
|
225
|
+
# TODO handle non 200 response code. Throwing an exception for now
|
226
|
+
raise StandardError.new("#{resp.code} error while fetching: #{resp.body}") unless %w(201 200).include?(resp.code.to_s)
|
227
|
+
|
228
|
+
if criteria[:count]
|
229
|
+
results = JSON.parse(resp.body)["totalCount"]
|
230
|
+
return results.to_i
|
231
|
+
else
|
232
|
+
results = JSON.parse(resp.body)["records"]
|
233
|
+
results = results[0..(criteria[:limit] - 1)] if criteria[:limit]
|
234
|
+
get_relation_objects results.map { |r|
|
235
|
+
# Convert camelcase to snake-case
|
236
|
+
r = r.transform_keys { |key| key.underscore }
|
237
|
+
@klass.model_name.to_s.constantize.new(r, false)
|
238
|
+
}
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def get_relation_objects(objects)
|
243
|
+
return objects if criteria[:include].blank?
|
244
|
+
|
245
|
+
included_objects = criteria[:include].map { |item| item.to_s.downcase }
|
246
|
+
|
247
|
+
if @klass.has_many_relations
|
248
|
+
objects.each do |item|
|
249
|
+
@klass.has_many_relations.each do |relation, relation_config|
|
250
|
+
next unless included_objects.include?(relation.to_s.downcase)
|
251
|
+
|
252
|
+
if !item.attributes.has_key?(relation.to_s)
|
253
|
+
item.attributes[relation.to_s] = Lockstep::RelationArray.new(@klass, [], relation, relation_config[:class_name])
|
254
|
+
elsif !item.attributes[relation].is_a?(Lockstep::RelationArray)
|
255
|
+
item.attributes[relation.to_s] = Lockstep::RelationArray.new(@klass, item.attributes[relation], relation, relation_config[:class_name])
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
objects.each do |item|
|
262
|
+
item.attributes.each do |key, value|
|
263
|
+
if value.is_a?(Array)
|
264
|
+
relation = @klass.has_many_relations[key]
|
265
|
+
next if relation.blank? or !included_objects.include?(key.to_s.downcase)
|
266
|
+
|
267
|
+
value.each do |relation_hash|
|
268
|
+
relation_obj = turn_relation_hash_into_object(relation, relation_hash)
|
269
|
+
value[value.index(relation_hash)] = relation_obj
|
270
|
+
end
|
271
|
+
elsif value.is_a?(Hash)
|
272
|
+
relation = @klass.belongs_to_relations[key]
|
273
|
+
next if relation.blank?
|
274
|
+
|
275
|
+
relation_hash = value
|
276
|
+
relation_obj = turn_relation_hash_into_object(relation, relation_hash)
|
277
|
+
item.attributes[key] = relation_obj
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
objects
|
282
|
+
end
|
283
|
+
|
284
|
+
def chunk_results(params = {})
|
285
|
+
page = criteria[:page] || 0
|
286
|
+
limit = criteria[:limit] || 0
|
287
|
+
# completed = false
|
288
|
+
records = []
|
289
|
+
loop do
|
290
|
+
params[:pageNumber] = page
|
291
|
+
params[:pageSize] = limit > 0 ? [limit - records.size, criteria[:chunk]].min : criteria[:chunk]
|
292
|
+
break if params[:pageSize] == 0
|
293
|
+
|
294
|
+
results = get_results(params)
|
295
|
+
break unless results.present?
|
296
|
+
|
297
|
+
records += results
|
298
|
+
break if limit > 0 and records.size >= limit
|
299
|
+
|
300
|
+
page += 1
|
301
|
+
end
|
302
|
+
|
303
|
+
records
|
304
|
+
end
|
305
|
+
|
306
|
+
def first
|
307
|
+
limit(1)
|
308
|
+
execute.first
|
309
|
+
end
|
310
|
+
|
311
|
+
def all
|
312
|
+
execute
|
313
|
+
end
|
314
|
+
|
315
|
+
def count
|
316
|
+
criteria[:count] = true
|
317
|
+
execute
|
318
|
+
end
|
319
|
+
|
320
|
+
# Find a Lockstep::ApiRecord object by ID
|
321
|
+
#
|
322
|
+
# @param [String] id the ID of the Parse object you want to find.
|
323
|
+
# @return [Lockstep::ApiRecord] an object that subclasses Lockstep::ApiRecord.
|
324
|
+
def find(id)
|
325
|
+
raise Lockstep::Exceptions::RecordNotFound, "Couldn't find #{name} without an ID" if id.blank?
|
326
|
+
record = where(@klass.id_ref => id).first
|
327
|
+
raise Lockstep::Exceptions::RecordNotFound, "Couldn't find #{name} with id: #{id}" if record.blank?
|
328
|
+
record
|
329
|
+
end
|
330
|
+
|
331
|
+
def method_missing(meth, *args, &block)
|
332
|
+
method_name = method_name.to_s
|
333
|
+
if method_name.start_with?("find_by_")
|
334
|
+
attrib = method_name.gsub(/^find_by_/, "")
|
335
|
+
finder_name = "find_all_by_#{attrib}"
|
336
|
+
|
337
|
+
define_singleton_method(finder_name) do |target_value|
|
338
|
+
where({ attrib.to_sym => target_value }).first
|
339
|
+
end
|
340
|
+
|
341
|
+
send(finder_name, args[0])
|
342
|
+
elsif method_name.start_with?("find_all_by_")
|
343
|
+
attrib = method_name.gsub(/^find_all_by_/, "")
|
344
|
+
finder_name = "find_all_by_#{attrib}"
|
345
|
+
|
346
|
+
define_singleton_method(finder_name) do |target_value|
|
347
|
+
where({ attrib.to_sym => target_value }).all
|
348
|
+
end
|
349
|
+
|
350
|
+
send(finder_name, args[0])
|
351
|
+
end
|
352
|
+
|
353
|
+
if @klass.scopes[meth].present?
|
354
|
+
instance_exec *args, &@klass.scopes[meth]
|
355
|
+
elsif Array.method_defined?(meth)
|
356
|
+
all.send(meth, *args, &block)
|
357
|
+
else
|
358
|
+
super
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
def respond_to?(meth)
|
363
|
+
if Array.method_defined?(meth)
|
364
|
+
true
|
365
|
+
else
|
366
|
+
super
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
def unscoped
|
371
|
+
Lockstep::Query.new(@klass)
|
372
|
+
end
|
373
|
+
|
374
|
+
private
|
375
|
+
|
376
|
+
def turn_relation_hash_into_object(relation, hash)
|
377
|
+
return nil if hash == nil
|
378
|
+
relation_klass = relation[:class_name].to_s.constantize
|
379
|
+
relation_object = relation_klass.new
|
380
|
+
hash.each do |key, value|
|
381
|
+
class_name_in_a_hash = false
|
382
|
+
if value.is_a?(Array)
|
383
|
+
value.each do |item|
|
384
|
+
if item and item.is_a?(Hash)
|
385
|
+
class_name_in_a_hash = true if relation_klass.has_many_relations[key].present?
|
386
|
+
break
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
if value.is_a?(Array) and class_name_in_a_hash
|
392
|
+
value.each do |object_in_array|
|
393
|
+
fresh_object = turn_relation_hash_into_object(relation_klass.has_many_relations[key][:class_name], object_in_array)
|
394
|
+
value[value.index(object_in_array)] = fresh_object
|
395
|
+
end
|
396
|
+
# Convert key from camelcase to snake-case
|
397
|
+
relation_object.attributes[key.underscore] = value
|
398
|
+
elsif value.is_a?(Hash) and relation_klass.belongs_to_relations[key].present?
|
399
|
+
# Convert key from camelcase to snake-case
|
400
|
+
relation_object.attributes[key.underscore] = turn_relation_hash_into_object(relation_klass.belongs_to_relations[key][:class_name], value)
|
401
|
+
else
|
402
|
+
# Convert key from camelcase to snake-case
|
403
|
+
relation_object.attributes[key.underscore] = value if key.to_s != "__type" and key.to_s != "className"
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
relation_object
|
408
|
+
end
|
409
|
+
end
|