This is not a traditional, boring tutorial. You'll get an ebook (epub or mobi) as well as 3 hours worth of tightly-edited, lovingly produced Elixir content. You'll learn Elixir while doing Elixir, helping me out at my new fictional job as development lead at Red:4 Aerospace.
I don't really know what I'm doing. I'm trying to learn Elixir and I'm having so much fun doing it that I thought I would share what I'm learning. So ... here goes. The code for the stuff I'm writing is up at Github - feel free to drop over.
In my last post, Ayende Rahien mad a great comment:
Excellent question (of course)! At the time I was just hacking things and wanted to see a result - I didn't worry too much about errors.
That said, let's see how we can handle this better. And please, if you know of a better please share in the comments!
Case And Pattern Matching
A better way to execute the query for our call would be to use case
:
def register({email, password}) do
{:ok, pid} = Membership.connect()
sql = "select * from membership.register($1, $2);"
case Postgrex.Connection.query(pid, sql, [email, password]) do
{:ok, res} ->
cols = res.columns
[first_row | _] = res.rows
[new_id, validation_token, auth_token, success, message] = first_row
{:ok, %RegistrationResult{
success: success,
message: message,
new_id: new_id,
authentication_token: auth_token,
validation_token: validation_token
}}
{:error, err} -> {:error, err}
end
end
Case statements are pretty standard for programming languages, and this one essentially operates the same way. Here, we're evaluating the return of the query and matching against that return. If all is OK, the Postgrex
driver will match against {:ok, %Postgrex.Result}
, otherwise it will match against {:error, %Postgrex.Error}
.
This matching thing is really head-twisty. The nice part is, however, that we only need to think about the atoms (:ok
and :error
) here, Elixir will see that the second argument is a variable and will bind to it - making the match work out.
Crazy stuff.
So, back to the case
statement. If a match is made on :ok
, I'll return the struct I was returning before using an anonymous function (the ->
operator). If things aren't OK and we match on :error
, I'll just pass the error on.
Using This
I can now use this in my test for a cleaner error response if something goes wrong, or just handle it as needed, again, using a case
statement:
setup do
{:ok, pid} = Postgrex.Connection.start_link(database: "bigmachine")
case Membership.Registration.register({"test@test.com", "password"}) do
{:ok, res} -> {:ok, [res: res]}
{:error, err} -> raise err
end
end
test "Registration with valid credentials", %{res: res} do
assert res.success,res.message
end
This statement
evaluates what comes back from register
and if it's OK, returns a tuple that gets set as the test context, which I use down below.
If things aren't OK, I raise. I could log here as well, or do other things - for now raising works.
Also - I should mention if you haven't figured it out that the last line in any function is the return value, just like in Ruby.
Case statements return values - you can bind a variable if you like or you can have them as the last operation, as I'm doing here.
Join over 15,000 programmers just like you and me
I have a problem when it comes to trying new things and learning about computer science stuff. I'm self-taught, so it's imperative I keep up with what's going on. I love sharing, so sign up and I'll send along what I've learned right to your inbox.