Skip to content

Feature: Separating the Memento.Table struct from the underlying mnesia table #40

@Bentheburrito

Description

@Bentheburrito

Hi! I really like how Memento casts table results into the Memento.Table module's struct, though I've run into a couple situations where I need to sacrifice distinct struct fields to take advantage of partial key-matching. For example, I have some ordered_set Tables that look a bit like this:

defmodule MyApp.Message do
  use Memento.Table,
    # where :room_id_and_sent_at is stored as a tuple, {room_id, sent_at}
    attributes: [:room_id_and_sent_at, :content, :sender],
    type: :ordered_set
end

If I want to query messages in a particular room by sent_at, I've learned that by grouping those two columns into a tuple, I can write a match spec that limits the search space to a particular constant room ID like this:

match_head = 
  MyApp.Message.__info__().query_base
  |> put_elem(1, {"some_room_id", :_})

match_spec = [{match_head, [], [:"$_"]}]

Memento.transaction!(fn -> Memento.Query.select_raw(MyApp.Message, match_spec) end)

The downside is that, what could be separate :room_id and :sent_at fields on the struct, have to be combined into one field, and accessing them becomes a bit of a pain. I think the DX could be improved, though I wanted to see if you have thoughts on what that might look like. One idea I had was to adjust the :attributes option in use Memento.Table to take a nested list, like this:

defmodule MyApp.Message do
  use Memento.Table,
    attributes: [[:room_id, :sent_at], :content, :sender],
    type: :ordered_set
end

I believe that would give Query.Data.load/1 + dump/1 enough context to know how to "nest" those fields in the records, and "unnest" them when casting to the struct.

Another path might be to define a @behaviour for Memento.Table with optional encode/decode callbacks that would take the place of Query.Data.load/1 + dump/1 if the user implements them. I like this option less because users have to do more work, though it's more flexible and could accommodate many use-cases (e.g. calculating "virtual fields" from the record data to add to the struct might be neat)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions