How best to extract value from mnesia query

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

How best to extract value from mnesia query

Lloyd R. Prentice-2
Hello,

The result of a mnesia read transaction looks like this:

   {atomic, Results} where result is either a populated list [value1, ... valueN] or, an empty list [].

If the table is initialized as set, then the returned list will contain at most one value, e.g:

  [value].

If I want to use of the value in a function or to populate another record, I need to extract the value from the list.

I've tried various ways to do this, but they all seem clumsy:

E.g.

[MyValue]

hd[vlaue]

confirm([]) ->
    not_found;
confirm([Value]) ->
    Value;
confirm(Value) ->
    Value.

Does there happen to be a preferred/conventional/best-practices way to do this?

Many thanks,

LRP






_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: How best to extract value from mnesia query

Jesper Louis Andersen-2
I usually do something like:

Txn = fun() -> ... end,
case mnesia:transaction(Txn) of
    {atomic, []} ->
       not_found;
    {atomic, [V]} ->
       <One_Value_Case>
    {atomic, L = [_|_]} ->
        <Multi_Value_Case>
end.

Some times, if there are a bunch of cases, I tend to use a function such as your confirm/1 function, passing the result on and writing down the case split at the top level, but it depends a bit on wether I like that code flow or not in that particular case. In general I prefer matching and binding values over projection functions such as hd/1, because hd/1 doesn't work on all lists, only the non-empty ones.

Another common trick is that if your Results are lists, then you can often avoid using a not_found atom, but handle the [] case naturally. Consider that

[] = lists:map(F, [])

which is true for a lot of functions working on lists. This suggests you can avoid having multiple data flows in this case, and use [] as a degenerate case which "skips" computations in a natural way. This can sometimes turn a code flow which case-splits its control flow all the time into a flow that just has one path. Flow with a single path tend to be far easier to handle in the long run in my experience.

Also, if you really do expect there to be a value, then I use

{atomic, [Value]} = mnesia:transaction(Txn),

and crash the code if it is violated. Defensive code is often a mistake in Erlang because we can just use the standard crash semantics to recover. Many other languages doesn't fare so well here.


On Wed, Nov 15, 2017 at 9:04 PM <[hidden email]> wrote:
Hello,

The result of a mnesia read transaction looks like this:

   {atomic, Results} where result is either a populated list [value1, ... valueN] or, an empty list [].

If the table is initialized as set, then the returned list will contain at most one value, e.g:

  [value].

If I want to use of the value in a function or to populate another record, I need to extract the value from the list.

I've tried various ways to do this, but they all seem clumsy:

E.g.

[MyValue]

hd[vlaue]

confirm([]) ->
    not_found;
confirm([Value]) ->
    Value;
confirm(Value) ->
    Value.

Does there happen to be a preferred/conventional/best-practices way to do this?

Many thanks,

LRP






_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: How best to extract value from mnesia query

Robert Raschke
In reply to this post by Lloyd R. Prentice-2
If I know that I shall only receive a single value result, I write

{atomic, [Value]} = mnesia:transaction(...)

This has the side effect of neatly terminating the process if we didn't get exactly one value back as a result. And that allows me to catch the error and decide what to do about it.

If you want to write defensively, then something that discriminates between the results may be appropriate. 

case mnesia:transaction(...) of
    {aborted, Reason} -> ...;
    {atomic, []} -> ...;
    {atomic, [Value]} -> ...;
    {atomic, Values} -> ...
end

Cheers,
Robby


On 15 Nov 2017 21:04, <[hidden email]> wrote:
Hello,

The result of a mnesia read transaction looks like this:

   {atomic, Results} where result is either a populated list [value1, ... valueN] or, an empty list [].

If the table is initialized as set, then the returned list will contain at most one value, e.g:

  [value].

If I want to use of the value in a function or to populate another record, I need to extract the value from the list.

I've tried various ways to do this, but they all seem clumsy:

E.g.

[MyValue]

hd[vlaue]

confirm([]) ->
    not_found;
confirm([Value]) ->
    Value;
confirm(Value) ->
    Value.

Does there happen to be a preferred/conventional/best-practices way to do this?

Many thanks,

LRP






_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: How best to extract value from mnesia query

Lloyd R. Prentice-2
In reply to this post by Jesper Louis Andersen-2
Hi Jesper,

Thank you!

Lloyd

-----Original Message-----
From: "Jesper Louis Andersen" <[hidden email]>
Sent: Wednesday, November 15, 2017 4:44pm
To: [hidden email]
Cc: "Erlang" <[hidden email]>
Subject: Re: [erlang-questions] How best to extract value from mnesia query

I usually do something like:

Txn = fun() -> ... end,
case mnesia:transaction(Txn) of
    {atomic, []} ->
       not_found;
    {atomic, [V]} ->
       <One_Value_Case>
    {atomic, L = [_|_]} ->
        <Multi_Value_Case>
end.

Some times, if there are a bunch of cases, I tend to use a function such as
your confirm/1 function, passing the result on and writing down the case
split at the top level, but it depends a bit on wether I like that code
flow or not in that particular case. In general I prefer matching and
binding values over projection functions such as hd/1, because hd/1 doesn't
work on all lists, only the non-empty ones.

Another common trick is that if your Results are lists, then you can often
avoid using a not_found atom, but handle the [] case naturally. Consider
that

[] = lists:map(F, [])

which is true for a lot of functions working on lists. This suggests you
can avoid having multiple data flows in this case, and use [] as a
degenerate case which "skips" computations in a natural way. This can
sometimes turn a code flow which case-splits its control flow all the time
into a flow that just has one path. Flow with a single path tend to be far
easier to handle in the long run in my experience.

Also, if you really do expect there to be a value, then I use

{atomic, [Value]} = mnesia:transaction(Txn),

and crash the code if it is violated. Defensive code is often a mistake in
Erlang because we can just use the standard crash semantics to recover.
Many other languages doesn't fare so well here.


On Wed, Nov 15, 2017 at 9:04 PM <[hidden email]> wrote:

> Hello,
>
> The result of a mnesia read transaction looks like this:
>
>    {atomic, Results} where result is either a populated list [value1, ...
> valueN] or, an empty list [].
>
> If the table is initialized as set, then the returned list will contain at
> most one value, e.g:
>
>   [value].
>
> If I want to use of the value in a function or to populate another record,
> I need to extract the value from the list.
>
> I've tried various ways to do this, but they all seem clumsy:
>
> E.g.
>
> [MyValue]
>
> hd[vlaue]
>
> confirm([]) ->
>     not_found;
> confirm([Value]) ->
>     Value;
> confirm(Value) ->
>     Value.
>
> Does there happen to be a preferred/conventional/best-practices way to do
> this?
>
> Many thanks,
>
> LRP
>
>
>
>
>
>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions
>


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: How best to extract value from mnesia query

Lloyd R. Prentice-2
In reply to this post by Robert Raschke
Hi Robby,

Much appreciate your helpful response.

Lloyd

-----Original Message-----
From: "Robert Raschke" <[hidden email]>
Sent: Wednesday, November 15, 2017 4:46pm
To: [hidden email]
Cc: "Erlang Questions" <[hidden email]>
Subject: Re: [erlang-questions] How best to extract value from mnesia query

If I know that I shall only receive a single value result, I write

{atomic, [Value]} = mnesia:transaction(...)

This has the side effect of neatly terminating the process if we didn't get
exactly one value back as a result. And that allows me to catch the error
and decide what to do about it.

If you want to write defensively, then something that discriminates between
the results may be appropriate.

case mnesia:transaction(...) of
    {aborted, Reason} -> ...;
    {atomic, []} -> ...;
    {atomic, [Value]} -> ...;
    {atomic, Values} -> ...
end

Cheers,
Robby


On 15 Nov 2017 21:04, <[hidden email]> wrote:

Hello,

The result of a mnesia read transaction looks like this:

   {atomic, Results} where result is either a populated list [value1, ...
valueN] or, an empty list [].

If the table is initialized as set, then the returned list will contain at
most one value, e.g:

  [value].

If I want to use of the value in a function or to populate another record,
I need to extract the value from the list.

I've tried various ways to do this, but they all seem clumsy:

E.g.

[MyValue]

hd[vlaue]

confirm([]) ->
    not_found;
confirm([Value]) ->
    Value;
confirm(Value) ->
    Value.

Does there happen to be a preferred/conventional/best-practices way to do
this?

Many thanks,

LRP






_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions