gbaird

gbaird

Using Postgrex and SQL for bank transfers in PostgreSQL. epgsql erlang as alternative

I am trying to code a bank transfer service using Elixir/Erlang, Postgrex and PostgreSQL.

Erlang v 26
Elixir v 1.16.0
Postgrex v 0.17.4

The logic I am trying to build is the following, wrapped in a transaction BEGIN - COMMIT.

Party A seeks to transfer $50 from his account to Party B, her account. Think a Venmo transfer from Party A to Party B for $50.

Initialize

  1. Store the transfer amount in an Elixir variable *transfer_amount
  2. Store the from account UID in an Elixir variable from_account
  3. Store the to account UID in an Elixir Variable to_account
  4. Store the authorization token in an Elixir variable auth_token

BEGIN the transaction

  1. Read the master token value from the authorization data table and if the auth_token = master_token, then continue, else quit
  2. Read the balance from Party A’s account using the from_account UID
  3. If from_account** balance is >= than transfer_amount, then continue, else quit
  4. Update from_account balance by subtracting transfer_amount
  5. Update to_account balance by adding transfer_amount to balance
    COMMIT the transaction

What I tried is wrapping the SQL statement built from the above into a query and then use Postgrex.query - see below. The code returns an error.

My question for the group is this the correct/best design pattern to try and accomplish the objective - a P2P bank transfer, to wrap the SQL logic into a SQL statement that has a series of “reads” and then a “read / write” using Postgrex.query! Does Postgres support “Transaction” syntax? Can the read, write, comparisons all be included into a single statement and then sent using Postgrex.query?

24)> Postgrex.query!(pid3, "BEGIN; SELECT token_masterid FROM token; IF token_id = master_token THEN SELECT from_account, balance_avail FROM main_account … [note not……; COMMIT", [])

** (Postgrex.Error) ERROR 42601 

A more simple version produces this error

iex(14)> Postgrex.query!(pid3, "BEGIN transaction; SELECT * FROM account; COMMIT;", [])
** (Postgrex.Error) ERROR 42601 (syntax_error) cannot insert multiple commands into a prepared statement

    iex(14)> Postgrex.query!(pid3, "BEGIN transaction; SELECT * FROM account; COMMIT;", [])
** (Postgrex.Error) ERROR 42601 (syntax_error) cannot insert multiple commands into a prepared statement

Thank you in advance any thoughts and help !!

Most Liked

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Hi @gbaird this seems more to do with a general comfort level with how Elixir works. All functions will only return one value, that isn’t related to Postgrex. If you want to return the information from multiple queries, bind each result to a variable and return a tuple:

{:ok, res} = Postgrex.transaction(pid3, fn(pid3) ->
  result1 = Postgrex.query!(pid3, "SELECT owner_id, balance_avail FROM account", [])
  result2 = Postgrex.query!(pid3, "SELECT owner_id, balance_book FROM account", [])
  {result1, result2}
end)

Keep in mind with Postgres that transactions are by default merely READ COMMITTED. Your use case may require stricter transaction modes.

sbuttgereit

sbuttgereit

Actually, should be possible to use a DO block (PostgreSQL: Documentation: 18: DO); this is effectively treated as a single SQL statement even though we may be doing more (possibly much more) work than that.

This is not so different than the stored procedure route, except that the DO block is implicitly ephemeral; no need to change the schema.

al2o3cr

al2o3cr

I don’t think multistatement queries like the above are supported - see also:

If you’re absolutely 100% required to do it SQL-side, you could make a stored procedure and then call that with Postgrex.query in a single statement.

The more-idiomatic approach would be to use Postgrex.transaction and then do the steps you’ve described using Elixir (and more DB queries) inside that transaction block.

Where Next?

Popular in Questions Top

chokchit
** (DBConnection.ConnectionError) connection not available and request was dropped from queue after 2733ms. You can configure how long re...
New
nobody
How to bind a phoenix app to a specific ip address? could not find anything about that, nowhere, unfortunately, but for me this is quite...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New

Other popular topics Top

hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52673 488
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 127089 1222
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement