Current section

Files

Jump to
nuamnesia lib amnesia database.ex
Raw

lib/amnesia/database.ex

# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# Version 2, December 2004
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
#
# 0. You just DO WHAT THE FUCK YOU WANT TO.
defmodule Amnesia.Database do
@doc false
defmacro __using__(_opts) do
quote do
import Amnesia.Database
# this is needed to populate the tables present in the database
# definition
Module.register_attribute __MODULE__, :tables, accumulate: true
end
end
@doc false
def defdatabase!(name, do: block) do
quote do
defmodule unquote(name) do
use Amnesia.Database
alias Amnesia.Metadata
unquote(block)
@doc """
Alias all the table names in the current scope and require what's
needed.
"""
defmacro __using__(_opts) do
[ quote(do: require Amnesia),
quote(do: require Amnesia.Fragment),
quote(do: require Exquisite),
quote(do: alias unquote(__MODULE__)),
Enum.map(@tables, fn module ->
to = Module.split(module)
|> Enum.drop(Module.split(__MODULE__) |> length)
to = if length(to) > 1 do
Module.concat(__MODULE__, to |> hd)
else
module
end
[ quote(do: alias unquote(to)),
quote(do: require unquote(module)) ]
end) ] |> List.flatten
end
@doc """
List of atoms of the defined tables in the database.
"""
@spec tables :: [atom]
def tables do
@tables
end
@doc """
Create the database, it calls `.create` on every defined table.
"""
@spec create :: [Amnesia.Table.o]
@spec create(Amnesia.Table.c) :: [Amnesia.Table.o]
def create(copying \\ []) do
[ metadata() |> Metadata.create(copying: copying) |
Enum.map(@tables, fn(table) ->
table.create(copying)
end) ]
end
@doc """
Create the database, it calls `.create` on every defined table, raises
in case of error.
"""
@spec create! :: [Amnesia.Table.o]
@spec create!(Amnesia.Table.c) :: [Amnesia.Table.o]
def create!(copying \\ []) do
metadata() |> Metadata.create!(copying: copying)
Enum.each @tables, fn(table) ->
table.create!(copying)
end
end
@doc """
Destroy the database, it calls `.destroy` on every defined table.
"""
@spec destroy :: [Amnesia.Table.o]
def destroy do
[ metadata() |> Metadata.destroy |
Enum.map(@tables, fn(table) ->
table.destroy()
end) ]
end
@doc """
Destroy the database, it calls `.destroy` on every defined table,
raises in case of error.
"""
@spec destroy! :: [Amnesia.Table.o]
def destroy! do
metadata() |> Metadata.destroy!
Enum.each @tables, fn(table) ->
table.destroy!()
end
end
@spec metadata :: Metadata.t
def metadata do
Metadata.for(__MODULE__)
end
@doc """
Wait for the database to be loaded.
"""
@spec wait :: :ok | { :timeout, [atom] } | { :error, atom }
@spec wait(integer | :infinity) :: :ok | { :timeout, [atom] } | { :error, atom }
def wait(timeout \\ :infinity) do
Amnesia.Table.wait(@tables, timeout)
end
end
end
end
@doc """
Define a table in the database with the given name, attributes and options.
If only a name is given, it will forward declare a table.
The created table will actually be a record, so you can define functions on
it like you would normally do for a record, various helper methods are added
by default.
## Options
* `:indices` specifies a list of additional indices to use instead of the
first attribute.
* `:type` specifies the type of the table, it can be `:set`, `:ordered_set`
and `:bag`, the default is `:set`
* `:mode` specifies the access mode, it can be `:both` and `:read!`, the
default is `:both`
* `:majority` specifies the majority of the table, the default is `false`
* `:priority` specifies the load priority of the table
* `:local` specifies if the table is local, default is `false`
## Example
use Amnesia
defdatabase Foo do
deftable Bar, [:id, :a], type: :bag
deftable Baz, [:id, :a, :b] do
def foo(self)
42
end
end
end
"""
@spec deftable(atom) :: none
@spec deftable(atom, [atom | { atom, any }]) :: none
@spec deftable(atom, [atom | { atom, any }], Keyword.t) :: none
@spec deftable(atom, [atom | { atom, any }], Keyword.t, Keyword.t) :: none
defmacro deftable(name, attributes \\ nil, opts \\ [], do_block \\ []) do
if attributes do
[ Amnesia.Table.Definition.define(__CALLER__.module, name, attributes, Keyword.merge(opts, do_block)),
# add the defined table to the list
quote do: @tables unquote(name) ]
else
quote do
alias __MODULE__.unquote(name)
end
end
end
end