The 'key' to Amnesia queries?

I am trying to get a handle on how to use Amnesia in lieu of Mnesia queries. But the documentation out there leaves a lot to be desired. I wonder if anyone can shed some light?

I have defined this table …

deftable Todo_lists, [:name, :list], type: :bag do
 @type date :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}
 @type t :: %Todo_lists{name: {String.t, date}, list: [%{date: date, title: String.t}]}
end

and added some records:

iex(n1@127.0.0.1)9> :mnesia.transaction(fn ->  
 ...(n1@127.0.0.1)9> :mnesia.match_object({Todo_lists, :_, :_})
...(n1@127.0.0.1)9> end)


 {:atomic,
  [{Database1.Todo_lists, {"Patricia", {2017, 2, 12}},
    [%{date: {2017, 2, 12}, title: "Market"}]},
   {Database1.Todo_lists, {"Bill", {2017, 2, 11}},
    [%{date: {2017, 2, 11}, title: "walk dog"}]},
   {Database1.Todo_lists, {"Richard", {2017, 2, 11}},
    [%{date: {2017, 2, 11}, title: "playtime"}]}]}

Now I can get some basic Amnesia queries to work:

iex(n1@127.0.0.1)7> use Database1
[Amnesia, Amnesia.Fragment, Exquisite, Database1, Database1.Todo_lists,
 Database1.Todo_lists, Database1.User, Database1.User, Database1.Message,
 Database1.Message]
iex(n1@127.0.0.1)8> use Amnesia
Amnesia.Helper
iex(n1@127.0.0.1)11> Amnesia.transaction do                                
...(n1@127.0.0.1)11> Todo_lists.read({"Patricia", {2017, 2, 12}})          
...(n1@127.0.0.1)11> end
[%Database1.Todo_lists{list: [%{date: {2017, 2, 12}, title: "Market"}],
  name: {"Patricia", {2017, 2, 12}}}]
iex(n1@127.0.0.1)16> Amnesia.transaction do   
...(n1@127.0.0.1)16> r = Todo_lists.where(name == {"Patricia", {2017, 2, 12}}) 
...(n1@127.0.0.1)16> r |> Amnesia.Selection.values |> Enum.each(&IO.inspect(&1)) 
...(n1@127.0.0.1)16> end

%Database1.Todo_lists{list: [%{date: {2017, 2, 12}, title: "Market"}],
 name: {"Patricia", {2017, 2, 12}}}
:ok

Ok, great. But now I want to do something like this but in Amnesia:

iex(n1@127.0.0.1)17> :mnesia.transaction(fn ->
...(n1@127.0.0.1)17> :mnesia.match_object({Todo_lists, {"Patricia", :_}, :_})
...(n1@127.0.0.1)17> end)

{:atomic,
 [{Database1.Todo_lists, {"Patricia", {2017, 2, 12}},
   [%{date: {2017, 2, 12}, title: "Market"}]}]}

In other words, how do I specify a wild card query using Amnesia?
I tried using Todo_lists.match, but I can’t even guess at the syntax.
Using help on this tells me to refer to mnesia.match, but that doesn’t really help.

I think Amnesia could be really cool if someone would just provide some basic documentation. That someone could be me if I could just figure out some basics.
(rant over :slight_smile:)

Thanks

1 Like

Honestly I’m not sure that I would use Amnesia. It’s basically its own syntax which wildly limits the resources available to you for help. If you use :mnesia and its regular tools then anyone who has used mnesia or any existing mnesia docs are helpful. If you use Amnesia you’re limited to other people who use Amnesia.

1 Like

Yes, I had come to that same conclusion last week. And the Elixir app I am currently developing is using straight mnesia. But I have been running into other query challenges with elixir-mnesia as well –

http://stackoverflow.com/questions/42213446/how-can-i-get-mnesia-select-to-work-in-elixir

– so I decided to give Amnesia another go. After messing around for a couple of hours, and numerous Google searches, I decided to ask the forum.

I see there is a Qlc library out there that may help. I don’t mind using Erlang list comprehensions/syntax to get what I need so I may try that route next. Ecto is not really an option for me because my app uses it’s own cache.

If you have any other suggestions I would love to hear them. I am anxious to move on.

Many thanks for your input.

1 Like

I’ve been futzing around with this briefly this morning.

It appears you can interop a little bit back and forth with Amnesia but one would need to dig into library internals to insure something like the following is always kosher,

iex(43)> Amnesia.Fragment.transaction do                                                                                                          
...(43)> %Amnesia.Table.Select{coerce: AMNESIA_TABLE, continuation: nil, values:                                  
...(43)> (:mnesia.match_object({ AMNESIA_TABLE, :_, { {:ref, 2010001, REPO}, :_}, :_, :_}))
...(43)> } end |> Amnesia.Selection.values    

in the above i’m pattern matching on an object that contains the tuple {{:ref, 2010001, REPO}, :_} and wrapping the results in the structure Amnesia uses to avoid the need to manually reconstruct the struct.

If I were performing a select i’d have to catch the continuation
Amnesia.transaction do
{values, continuation} = :mnesia.select …
%Amnesia.Table.Select{coerce: AMNESIA_TABLE, continuation: continuation, values: values}
end |> Amnesia.Selection.values

completely tangential, REPO here is a repository class in my codebase that that will return the referenced object when one calls REPO.get(2010001). So I am filtering by an entry associated with what is essentially another record in another table.

1 Like

https://github.com/meh/amnesia/blob/211d98275c085a9e3049ccb8db8d29f76b3ffbfc/test/amnesia/database_test.exs#L242-L253 appears to be a match type query.

1 Like

Here you go,

The below built in match method seems to work exactly as needed for the following query against a calendar entry with a date tuple of format {year, month, week, day}

match = [date: {year, month, iso_week,  :_}]
Calendar.Entries.match(match)

https://github.com/meh/amnesia/issues/62

1 Like