• Stars
    star
    682
  • Rank 66,240 (Top 2 %)
  • Language
    Elixir
  • Created over 11 years ago
  • Updated about 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Mnesia wrapper for Elixir.

amnesia - mnesia wrapper for Elixir

amnesia wraps everything exposed by mnesia, from fragments to fragment hash, access and backup behaviors.

It provides a simplified table and database definition with some macros and allows you to use the nice Enum functions on tables by implementing the Enum.Iterator protocol.

Everything is documented and specced, even the unspecced and undocumented parts of mnesia that have been wrapped.

The documentation often refers to mnesia functions, I strongly suggest you read mnesia's documentation too, since it has a lot of valuable information.

Defining a database

To use amnesia you have to define a database and the tables of that database.

You can have multiple databases in the same amnesia instance, a database is actually just a way to group mnesia tables.

# needed to get defdatabase and other macros
use Amnesia

# defines a database called Database, it's basically a defmodule with
# some additional magic
defdatabase Database do
  # this is just a forward declaration of the table, otherwise you'd have
  # to fully scope User.read in Message functions
  deftable User

  # this defines a table with an user_id key and a content attribute, and
  # makes the table a bag; tables are basically records with a bunch of helpers
  deftable Message, [:user_id, :content], type: :bag do
    # this isn't required, but it's always nice to spec things
    @type t :: %Message{user_id: integer, content: String.t}

    # this defines a helper function to fetch the user from a Message record
    def user(self) do
      User.read(self.user_id)
    end

    # this does the same, but uses dirty operations
    def user!(self) do
      User.read!(self.user_id)
    end
  end

  # this defines a table with other attributes as ordered set, and defines an
  # additional index as email, this improves lookup operations
  deftable User, [{ :id, autoincrement }, :name, :email], type: :ordered_set, index: [:email] do
    # again not needed, but nice to have
    @type t :: %User{id: non_neg_integer, name: String.t, email: String.t}

    # this is a helper function to add a message to the user, using write
    # on the created records makes it write to the mnesia table
    def add_message(self, content) do
      %Message{user_id: self.id, content: content} |> Message.write
    end

    # like above, but again with dirty operations, the bang methods are used
    # thorough amnesia to be the dirty counterparts of the bang-less functions
    def add_message!(self, content) do
      %Message{user_id: self.id, content: content} |> Message.write!
    end

    # this is a helper to fetch all messages for the user
    def messages(self) do
      Message.read(self.id)
    end

    # like above, but with dirty operations
    def messages!(self) do
      Message.read!(self.id)
    end
  end
end

Creating the database

Before using a database you have to create it, and before it a schema.

To do so, you can use the built-in mix task amnesia.create passing your database module via the --database or -d options.

mix amnesia.create -d Database --disk

The available options for creating the databases are:

  • --database or -d: the database module to create
  • --no-schema: to avoid creating the schema
  • --memory: to create the tables with memory copying on the current node
  • --disk: to create the tables with disc_copies on the current node
  • --disk!: to create the tables with disc_only_copies on the current node

By default it creates the schema and uses disc_copies.

If you want to drop the tables there is also a drop task you should use with CAUTION as it will destroy all data. To use it just call:

mix amnesia.drop -d Database

The options accepted by this task are:

  • --database or -d: same as with create. A database module to drop tables
  • --schema: drops the schema too. Defaults to false

Writing to the database

Once the database has been defined and created, you can start using the various tables.

# You want to be in a transaction most of the time, this ensures the data
# doesn't get corrupted and you get meaningful values back.
#
# Most operations won't work outside a transaction and will raise an exception.
Amnesia.transaction do
  # Every table is a record, so you can do everything you can do with records.
  #
  # Once you want to save the record, you have to call `.write` on it, this
  # will write the record to the table.
  #
  # Since we defined the `User` table with an `autoincrement` id attribute it
  # will be incremented internally on write, unless the id attribute is set, in
  # that case it will be left as is.
  #
  # If you want to know the values of the autoincrement fields, `.write` always
  # returns the updated record.
  john = %User{name: "John", email: "[email protected]"} |> User.write

  # Let's create more users.
  richard = %User{name: "Richard", email: "[email protected]"} |> User.write
  linus   = %User{name: "Linus", email: "[email protected]"} |> User.write

  # Now let's add some messages.

  john |> User.add_message %S"""
  When we program a computer to make choices intelligently after determining
  its options, examining their consequences, and deciding which is most
  favorable or most moral or whatever, we must program it to take an attitude
  towards its freedom of choice essentially isomorphic to that which a human
  must take to his own.
  """

  john |> User.add_message %S"""
  He who refuses to do arithmetic is doomed to talk nonsense."
  """

  john |> User.add_message %S"""
  It's difficult to be rigorous about whether a machine really 'knows',
  'thinks', etc., because we're hard put to define these things. We understand
  human mental processes only slightly better than a fish understands swimming.
  """

  richard |> User.add_message %S"""
  For personal reasons, I do not browse the web from my computer. (I also have
  no net connection much of the time.) To look at page I send mail to a daemon
  which runs wget and mails the page back to me. It is very efficient use of my
  time, but it is slow in real time.
  """

  richard |> User.add_message %S"""
  I am skeptical of the claim that voluntarily pedophilia harms children. The
  arguments that it causes harm seem to be based on cases which aren't
  voluntary, which are then stretched by parents who are horrified by the idea
  that their little baby is maturing.
  """

  linus |> User.add_message %S"""
  Portability is for people who cannot write new programs.
  """

  linus |> User.add_message %S"""
  Really, I'm not out to destroy Microsoft. That will just be a completely
  unintentional side effect.
  """

  linus |> User.add_message %S"""
  Modern PCs are horrible. ACPI is a complete design disaster in every way. But
  we're kind of stuck with it. If any Intel people are listening to this and
  you had anything to do with ACPI, shoot yourself now, before you reproduce.
  """
end

Reading from the database

Once there's something written to the database you can start reading back records from it.

Amnesia.transaction do
  # The simplest way to read a record is using the key of the record (by
  # default the first attribute)
  #
  # Since we wrote the John, Richard and Linus in this order and the id is
  # defined as *autoincrement*, the first `User` will be John.
  john = User.read(1)

  # Now let's read his messages and print them all.
  john |> User.messages |> Enum.each &IO.puts(&1.content)

  # You can also use an Exquisite selector to fetch records.
  selection = Message.where user_id == 1 or user_id == 2,
    select: content

  # Get the values in the selector and print them.
  selection |> Amnesia.Selection.values |> Enum.each &IO.puts(&1.content)
end

Other documentation

All the code has @spec and @doc, so you can either go around the source and read the @docs, use the REPL and h/1 or generate the documentation with ex_doc.

More Repositories

1

elixir-socket

Socket wrapping for Elixir.
Elixir
679
star
2

ruby-tesseract-ocr

A Ruby wrapper library to the tesseract-ocr API.
Ruby
627
star
3

ruby-thread

Various extensions to the base thread library.
Ruby
525
star
4

rust-ffmpeg

Safe FFmpeg wrapper.
Rust
454
star
5

rust-tun

TUN device creation and handling.
Rust
215
star
6

elixir-datastructures

Datastructures for Elixir.
Elixir
212
star
7

rust-ffmpeg-sys

moved to meh/rust-ffmpeg
Rust
146
star
8

cancer

It's terminal.
Rust
129
star
9

urna

REST in peace.
Elixir
95
star
10

smart-referer

MOVED to GitLab: https://gitlab.com/smart-referer/smart-referer/
JavaScript
94
star
11

reagent

You need more reagents to conjure this server.
Elixir
92
star
12

dux

DUX MEA LUX
Rust
89
star
13

exquisite

LINQ-like match_spec generation for Elixir.
Elixir
78
star
14

rust-packet

Network packet handling for Rust.
Rust
76
star
15

cauldron

I wonder what kind of Elixir is boiling in there.
Elixir
74
star
16

jazz

Yet another library to handle JSON in Elixir.
Elixir
61
star
17

rorschach

And I'll look down and whisper "GNO."
Rust
59
star
18

screenruster

X11 screen saver and locker.
Rust
53
star
19

miserve

Servo based minimal browser.
PostScript
48
star
20

blender

Blend in the crowd by faking to be the most common Firefox browser version, operating system and other stuff.
Ruby
42
star
21

rust-terminfo

Terminal information for Rust.
Rust
40
star
22

rust-uinput

Linux uinput wrapper.
Rust
39
star
23

lissio

E vai col lissio!
Ruby
39
star
24

cesso

CSV handling library for Elixir.
Elixir
26
star
25

rust-xcb-util

Rust bindings and wrappers for XCB utility functions.
Rust
26
star
26

ruby-mbox

A Ruby mbox parser.
Ruby
23
star
27

steamy

Steam controller handling.
Rust
21
star
28

ruby-threadpool

A simple no-wasted-resources thread pool implementation.
Ruby
21
star
29

ruby-x11

X11 bindings for Ruby
Ruby
20
star
30

wrong

The most wrong build system and package manager for C and C++.
Makefile
19
star
31

elixir-benchmark

Elixir benchmark utilities.
Elixir
18
star
32

mad

Managers & Developers
18
star
33

rust-mailbox

MBOX reader.
Rust
17
star
34

rust-hid

HID access library.
Rust
15
star
35

moc

Mirror of the moc project, with some of my own changes
C
15
star
36

rust-shmem

Shared memory for Rust.
Rust
14
star
37

ruby-clj

Like json, but with clojure sexps.
Ruby
14
star
38

NetCommander

NetCommander - An easy to use arp spoofing tool.
Python
14
star
39

miniLOL

Not just a CMS.
JavaScript
12
star
40

derp

Elixir error logger.
Elixir
12
star
41

continuum

Spaaaaceeeeeeeeeeeee.
Elixir
12
star
42

nucular

A reactor in D.
D
12
star
43

ruby-torchat

Torchat implementation in Ruby, event-driven EventMachine based library.
Ruby
12
star
44

rust-sixel

Sixel encoder/decoder for Rust.
Rust
11
star
45

ruby-ffi-inline

Inline C/C++ in Ruby easily and cleanly.
Ruby
11
star
46

rust-lzma

LZMA handling library.
Rust
10
star
47

fag

Forums Are Gay.
Ruby
10
star
48

clj.js

parse/dump Clojure like you'd do with JSON
JavaScript
10
star
49

vimmeh

Vim Script
9
star
50

rust-bdf

BDF format handling.
Rust
9
star
51

bitlbee-omegle

Omegle plugin for BitlBee.
C
9
star
52

neovimmeh

Fennel
8
star
53

elixir-operators

Ever wanted operators which are as slow as can be? Now you can!
Elixir
8
star
54

arpoon

Man the harpoons, kill the spoofer!
Ruby
8
star
55

lulzKey

lulzKey. Let's close those effin Windows so penguins won't enter.
C++
8
star
56

exts

Elixir Terms Storage, ets wrapper.
Elixir
8
star
57

failirc

Fail IRC library in Ruby.
Ruby
7
star
58

lulzhttpd

A C++ web server.
C++
7
star
59

screenruster-saver

Helper library to create screen savers.
Rust
7
star
60

rust-uinput-sys

Linux uinput definitions.
Rust
7
star
61

elixir-managed_process

Garbage collected processes.
Elixir
7
star
62

npapi-mumble-link

Mumble Link wrapped as an NPAPI plugin.
C
7
star
63

expo

XPosed for Kotlin.
Kotlin
7
star
64

opentyrian

opentyrian mirror with some of my own changes
C
7
star
65

rust-picto

Image handling library for Rust.
Rust
6
star
66

shumei

Shumei brings an actor system and other concurrency plumbing primitives to the web.
TypeScript
6
star
67

random

Random codes.
Assembly
6
star
68

ruby-fuse

Bindings and wrapper for FUSE with FFI.
Ruby
6
star
69

elixir-finalizer

Define finalizers using the cool NIF hack.
Elixir
6
star
70

httprot

Prot prot prot.
Elixir
6
star
71

screenruster-saver-laughing_man

I thought what I'd do was, I'd pretend I was one of those deaf-mutes.
Rust
6
star
72

ruby-call-me

Various calling things, overload, pattern matching, memoization and such.
Ruby
6
star
73

rust-openal

OpenAL wrapper
Rust
6
star
74

orgasm

ORGanized ASseMbly: a Ruby (dis)?assembler library (NOT a (dis)?assembler FOR Ruby, a (dis)?assembler IN Ruby)
Ruby
6
star
75

llvm-lol

LOLCODE LLVM implementation.
C++
5
star
76

decimex

erlang-decimal wrapper for Elixir
Elixir
5
star
77

ruby-glyr

Ruby wrapper for glyr.
Ruby
5
star
78

nohomo

Homoglyphs begone!
Vim Script
5
star
79

clj-sockets

POSIX sockets for Clojure.
Clojure
5
star
80

rust-hwaddr

MAC address handling.
Rust
5
star
81

colorb

Colorify your strings
Ruby
5
star
82

rust-xkb

Rusty wrapper to libxkbcommon.
Rust
5
star
83

boolean-expression

A simple library to evaluate boolean expressions.
Ruby
5
star
84

bitlbee-torchat

Bitlbee plugin for using torchat.
C
5
star
85

amirite

Include and forget testing framework for C++11
C++
5
star
86

dexts

Disk Elixir Terms Storage, dest wrapper.
Elixir
5
star
87

nokku

Knock knock knock, hitori bocchi.
Rust
4
star
88

rust-xkbcommon-sys

Bindings to libxkbcommon.
Rust
4
star
89

screenruster-saver-hacks

ScreenRuster support for XScreenSaver hacks.
Rust
4
star
90

libcss

A library to parse and work with CSS
C
4
star
91

ela

Embedded Linear Algebra
C++
4
star
92

faildns

Fail DNS library in Ruby
Ruby
4
star
93

rust-curses-sys

Rust
3
star
94

ruby-clit

Simple library to make nice themeable CLI output.
Ruby
3
star
95

rft

Shitty Rust FFT implementation.
Rust
3
star
96

fagadget

New cross-toolkit and cross-platform desktop-gadget prototype.
C++
3
star
97

zwm

Shell
3
star
98

cryptsetup

Mirror of cryptsetup with some of my own changes
C
3
star
99

LOLastfm

LOL it's a scrobbler.
Ruby
3
star
100

parsepples

A parslet-like parser for C++
C++
3
star