Lethe (Lethe v0.5.0) View Source

Lethe

Lethe is a user-friendly query DSL for Mnesia. Currently, Lethe is focused on providing a sane API for reads, but I might add support for writes later.

The default options are:

  • Select all fields (Lethe.select_all)
  • Read lock (:read)
  • Select all values (Lethe.limit(:all))

Querying

Querying is started with Lethe.new/1. This function takes a table name as its sole argument, and returns a new Lethe.Query. Querying is controlled with:

Link to this section Summary

Types

An Elixir expression. Used for where clauses.

The fields being returned by the query. These are the names of the fields, not Mnesia's numeric selectors or anything of the like.

The limit of values to return. If the limit is 0, it is converted to :all internally.

The type of table lock to use.

A boolean function that can be invoked in a matchspec. These functions are used for operating on the values being queried over, such as

The first tuple() is a {table(), result() | matchspec_any(), ...}

The name of the Mnesia table to query against

A result of an Mnesia transaction.

A failed transaction result. The inner term is the error returned by Mnesia.

A successful transaction result.

Functions

Compiles the query into a tuple containing all the information needed to run it against an Mnesia database.

Limit the number of results returned. The number is a non-negative integer, or the special atom :all to indicate all results being returned. Providing a limit of 0 is functionally equivalent to providing a limit of :all.

Create a new query on the specified table. The names of the table attributes will be automatically loaded.

Runs the query against Mnesia, ensuring that results are properly limited.

List specific fields to be selected from the table. Either a single atom or a list of atoms may be provided.

Select all fields from the table. This is essentially Mnesia's :"$$" selector.

Adds a guard to the query. Guards are roughly analogous to WHERE clauses in SQL, but can operate on all the Elixir data types. Instead of needing to write out guards yourself, or suffer through the scary mess defined in Lethe.Ops, you can instead just write normal Elixir in your where calls, and Lethe will convert them into guard form. For example

Link to this section Types

Specs

compiled_query() :: {table(), matchspec(), limit(), lock()}

Specs

expression() :: term()

An Elixir expression. Used for where clauses.

Specs

field() :: atom()

The fields being returned by the query. These are the names of the fields, not Mnesia's numeric selectors or anything of the like.

Specs

field_or_guard() :: field() | matchspec_guard()

Specs

limit() :: :all | non_neg_integer()

The limit of values to return. If the limit is 0, it is converted to :all internally.

Specs

lock() :: :read | :write

The type of table lock to use.

Specs

matchspec() :: [matchspec_element()]

Specs

matchspec_all() :: :"$$"

Specs

matchspec_any() :: :_

Specs

matchspec_bool_func() ::
  :is_atom
  | :is_float
  | :is_integer
  | :is_list
  | :is_number
  | :is_pid
  | :is_port
  | :is_reference
  | :is_tuple
  | :is_map
  | :map_is_key
  | :is_binary
  | :is_function
  | :is_record
  | :and
  | :or
  | :not
  | :xor
  | :andalso
  | :orelse

A boolean function that can be invoked in a matchspec. These functions are used for operating on the values being queried over, such as:

  • "is X a pid?"
  • "is Y a key in X?"

Specs

matchspec_condition() :: matchspec_variable() | matchspec_guard()

Specs

matchspec_element() :: {tuple(), [matchspec_condition()], results()}

The first tuple() is a {table(), result() | matchspec_any(), ...}

Specs

Link to this type

matchspec_guard_func()

View Source

Specs

matchspec_guard_func() ::
  matchspec_bool_func()
  | :abs
  | :element
  | :hd
  | :length
  | :map_get
  | :map_size
  | :node
  | :round
  | :size
  | :bit_size
  | :tl
  | :trunc
  | :+
  | :-
  | :*
  | :div
  | :rem
  | :band
  | :bor
  | :bxor
  | :bnot
  | :bsl
  | :bsr
  | :>
  | :>=
  | :<
  | :"=<"
  | :"=:="
  | :==
  | :"=/="
  | :"/="
  | :self

Specs

matchspec_variable() :: result() | matchspec_any() | matchspec_all()

Specs

result() :: atom()

Specs

results() :: [result()]

Specs

table() :: atom()

The name of the Mnesia table to query against

Specs

transaction(res) :: transaction_success(res) | transaction_failure()

A result of an Mnesia transaction.

Specs

transaction_failure() :: {:error, {:transaction_aborted, term()}}

A failed transaction result. The inner term is the error returned by Mnesia.

Link to this type

transaction_success(res)

View Source

Specs

transaction_success(res) :: {:ok, res}

A successful transaction result.

Link to this section Functions

Specs

compile(Lethe.Query.t()) :: compiled_query()

Compiles the query into a tuple containing all the information needed to run it against an Mnesia database.

Link to this function

field_to_var(query, field)

View Source

Specs

limit(Lethe.Query.t(), limit()) :: Lethe.Query.t()

Limit the number of results returned. The number is a non-negative integer, or the special atom :all to indicate all results being returned. Providing a limit of 0 is functionally equivalent to providing a limit of :all.

Specs

new(table()) :: Lethe.Query.t()

Create a new query on the specified table. The names of the table attributes will be automatically loaded.

Specs

Runs the query against Mnesia, ensuring that results are properly limited.

Specs

select(Lethe.Query.t(), field() | [field()]) :: Lethe.Query.t()

List specific fields to be selected from the table. Either a single atom or a list of atoms may be provided.

Specs

select_all(Lethe.Query.t()) :: Lethe.Query.t()

Select all fields from the table. This is essentially Mnesia's :"$$" selector.

Link to this macro

where(query, operation)

View Source (macro)

Specs

Adds a guard to the query. Guards are roughly analogous to WHERE clauses in SQL, but can operate on all the Elixir data types. Instead of needing to write out guards yourself, or suffer through the scary mess defined in Lethe.Ops, you can instead just write normal Elixir in your where calls, and Lethe will convert them into guard form. For example:

# ...
|> Lethe.where(:field_name * 2 <= 10)
|> Lethe.where(:field_two == 7 and :field_three != "test")
# ...

Lethe where expressions are normal Elixir code. Some operators are rewritten from Elixir form to Mnesia form at compile time; for example, Elixir's and operator is rewritten to an :andalso Mnesia guard.

However, Lethe where expressions differ from normal Elixir expressions in one major way: You cannot use external variables directly, but instead must pin them, or, in other words, use the ^ operator. For example:

i = 0
# ...
# Note the pin (`^`) operator. This wil not work as expected otherwise,
# and may return invalid results
|> Lethe.where(:value == ^i * 2)

A list of all available functions can be found here: https://erlang.org/doc/apps/erts/match_spec.html#grammar