add create sell and buy crypto order mutations

This commit is contained in:
João Geonizeli
2021-08-15 01:59:59 -03:00
parent 4b1341677f
commit a3d32ee13a
25 changed files with 688 additions and 15 deletions

View File

@@ -0,0 +1,7 @@
# frozen_string_literal: true
module Inputs
class CreateBuyCryptoOrderAttributesInput < Types::BaseInputObject
argument :currency_id, ID, required: true
argument :amount_cents, Integer, "Amount to be paid", required: true
end
end

View File

@@ -0,0 +1,7 @@
# frozen_string_literal: true
module Inputs
class CreateSellCryptoOrderAttributesInput < Types::BaseInputObject
argument :currency_id, ID, required: true
argument :amount, String, "Amount to be paid", required: true
end
end

View File

@@ -6,8 +6,16 @@ module Mutations
input_object_class Types::BaseInputObject
object_class Types::BaseObject
field :errors, [String],
field :errors, [Types::RecordInvalidType],
null: true,
description: "Errors encountered during execution of the mutation."
def current_user
context[:current_user]
end
def decode_id(encoded_id)
GraphQL::Schema::UniqueWithinType.decode(encoded_id).last
end
end
end

View File

@@ -0,0 +1,26 @@
# frozen_string_literal: true
module Mutations
class CreateBuyCryptoOrder < BaseMutation
field :order, Types::BuyCryptoOrderType, null: true
argument :order, Inputs::CreateBuyCryptoOrderAttributesInput, required: true
def resolve(order:)
currency_id = decode_id(order[:currency_id])
ActiveRecord::Base.transaction do
current_user.fiat_balance.withdrawal!(order[:amount_cents])
record = BuyCryptoOrder.create!(
paid_amount_cents: order[:amount_cents],
currency_id: currency_id,
user_id: current_user.id,
)
{ order: record }
rescue ActiveRecord::RecordInvalid => e
{ errors: Resolvers::ModelErrors.from_active_record_model(e.record) }
end
end
end
end

View File

@@ -0,0 +1,28 @@
# frozen_string_literal: true
module Mutations
class CreateSellCryptoOrder < BaseMutation
field :order, Types::SellCryptoOrderType, null: true
argument :order, Inputs::CreateSellCryptoOrderAttributesInput, required: true
def resolve(order:)
currency_id = decode_id(order[:currency_id])
amount = BigDecimal(order[:amount])
ActiveRecord::Base.transaction do
current_user.balances.find_by!(currency_id: currency_id)
.withdrawal!(amount)
record = SellCryptoOrder.create(
paid_amount: amount,
currency_id: currency_id,
user_id: current_user.id,
)
{ order: record }
rescue ActiveRecord::RecordInvalid => e
{ errors: Resolvers::ModelErrors.from_active_record_model(e.record) }
end
end
end
end

View File

@@ -0,0 +1,39 @@
# frozen_string_literal: true
module Resolvers
class ModelErrors
attr_reader :full_messages, :field_name, :messages, :path
def initialize(args)
@full_messages = args[:full_messages]
@field_name = args[:field_name]
@messages = args[:messages]
@path = args[:path]
end
def self.from_active_record_model(model)
return if model&.errors.blank?
model.errors.messages.map do |field, messages|
new(
full_messages: model.errors.full_messages_for(field),
field_name: field,
messages: messages,
path: ["attributes", field]
)
end
end
def self.from_active_record_model_errors(errors)
return if errors.blank?
errors.messages.map do |field, messages|
new(
full_messages: errors.full_messages_for(field),
field_name: field,
messages: messages,
path: ["attributes", field]
)
end
end
end
end

View File

@@ -0,0 +1,22 @@
# frozen_string_literal: true
module Types
class BuyCryptoOrderType < Types::BaseObject
implements GraphQL::Types::Relay::Node
global_id_field :id
graphql_name "BuyCryptoOrder"
field :id, ID, null: false
field :currency, CurrencyType, null: false
def currency
dataloader.with(Dataloader::Source, Currency).load(object.currency_id)
end
field :status, ProcessStatusEnum, null: false
field :paid_amount_cents, Integer, null: false
field :received_amount, String, null: true
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
end
end

View File

@@ -9,7 +9,5 @@ module Types
field :id, ID, null: false
field :amount_cents, Integer, null: false
field :amount_currency, String, null: false
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
end
end

View File

@@ -1,5 +1,7 @@
# frozen_string_literal: true
module Types
class MutationType < Types::BaseObject
field :create_sell_crypto_order, mutation: Mutations::CreateSellCryptoOrder
field :create_buy_crypto_order, mutation: Mutations::CreateBuyCryptoOrder
end
end

View File

@@ -0,0 +1,10 @@
# frozen_string_literal: true
module Types
class ProcessStatusEnum < Types::BaseEnum
graphql_name "ProcessStatus"
value "PROCESSING", value: "processing"
value "COMPLETED", value: "completed"
value "CANCELED", value: "canceled"
end
end

View File

@@ -18,5 +18,15 @@ module Types
def fiat_balances
Pundit.policy_scope(current_user, FiatBalance)
end
field :sell_crypto_orders, SellCryptoOrderType.connection_type, null: false
def sell_crypto_orders
[]
end
field :buy_crypto_orders, BuyCryptoOrderType.connection_type, null: false
def buy_crypto_orders
[]
end
end
end

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
module Types
class RecordInvalidType < Types::BaseObject
graphql_name "RecordInvalid"
field :full_messages, [String], null: false
field :field_name, String, null: true
field :messages, [String], null: true
field :path, [String], null: true
end
end

View File

@@ -0,0 +1,22 @@
# frozen_string_literal: true
module Types
class SellCryptoOrderType < Types::BaseObject
implements GraphQL::Types::Relay::Node
global_id_field :id
graphql_name "SellCryptoOrder"
field :id, ID, null: false
field :currency, CurrencyType, null: false
def currency
dataloader.with(Dataloader::Source, Currency).load(object.currency_id)
end
field :status, ProcessStatusEnum, null: false
field :paid_amount, String, null: false
field :received_amount_cents, Integer, null: true
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
end
end

View File

@@ -1,6 +1,6 @@
# frozen_string_literal: true
class XStakeSchema < GraphQL::Schema
# mutation(Types::MutationType)
mutation(Types::MutationType)
query(Types::QueryType)
use GraphQL::Dataloader