Skip to content

Instantly share code, notes, and snippets.

@thiagoa
Last active May 22, 2024 05:08
Show Gist options
  • Save thiagoa/3d09fa38455273b4b885533bd3de1390 to your computer and use it in GitHub Desktop.
Save thiagoa/3d09fa38455273b4b885533bd3de1390 to your computer and use it in GitHub Desktop.
require "json"
require "faraday"
# Configure before using or execute this code as-is
# and get a 401
module Configuration
class << self
attr_accessor :organization_id, :api_key
end
end
module ResultChainable
attr_reader :next_result
def initialize(next_result: nil, **attrs)
super(**attrs)
@next_result = next_result
end
def chain_result(next_result)
attrs = {
status: next_result.status,
next_result: next_result
}
self.class.new(**to_h, **attrs)
end
end
Result = Struct.new(:status, :error_code, :id, keyword_init: true) do
include ResultChainable
def success?
status == :ok
end
def error?
!success?
end
end
class LineItemRequest
BASE_URL = "https://app.moderntreasury.com/api/"
HEADERS = {"Content-Type" => "application/json"}.freeze
def self.execute(params)
response = client.post("ledger_transactions", JSON.dump(params))
if response.status == 200
Result.new(status: :ok, id: response.body["id"])
else
Result.new(status: :error, error_code: response.status)
end
end
def self.rollback(result, _params)
return if result.nil?
patch_params = {status: "archived"}
client.patch "ledger_transactions/#{result.id}", JSON.dump(patch_params)
end
private_class_method def self.client
Faraday.new(url: BASE_URL, headers: HEADERS) do |client|
org_id = Configuration.organization_id
api_key = Configuration.api_key
client.response :json
client.request :authorization, :basic, org_id, api_key
end
end
end
class RequestRunner
def self.execute(request, params)
result = request.execute(params)
if block_given? && result.success?
begin
next_result = yield(result)
rescue => e
request.rollback(result, params)
raise e
end
if next_result.respond_to?(:chain_result)
result = result.chain_result(next_result)
if next_result.error?
request.rollback(result, params)
end
end
end
result
end
end
class TransactionalRequestRunner
def self.execute(array_of_arguments)
request, params, on_success = array_of_arguments.shift
request.execute(params) do |result|
on_success.call result if on_success
unless array_of_arguments.empty?
execute array_of_arguments
end
end
end
end
def main
# Fake params here. Replace with real ones.
params_1 = {id: "request-one"}
params_2 = {id: "request-two"}
params_3 = {id: "request-three"}
# Different types of requests can be used here
RequestRunner.execute LineItemRequest, params_1 do |_result_1|
RequestRunner.execute LineItemRequest, params_2 do |_result_2|
RequestRunner.execute LineItemRequest, params_3 do |_result_3|
puts "All successful!"
end
end
end
end
def main_with_transactional_request_runner
# Fake params here. Replace with real ones.
params_1 = {id: "request-one"}
params_2 = {id: "request-two"}
params_3 = {id: "request-three"}
array_of_arguments = [
[LineItemRequest, params_1],
[LineItemRequest, params_2],
[LineItemRequest, params_3, ->(_result_3) { puts "All successful!" }]
]
TransactionalRequestRunner.execute(array_of_arguments)
end
# Choose "main" or "main_with_transactional_request_runner"
result = main
p result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment