{"id":13508747,"url":"https://github.com/meh/amnesia","last_synced_at":"2025-10-17T08:21:46.721Z","repository":{"id":7900824,"uuid":"9281307","full_name":"meh/amnesia","owner":"meh","description":"Mnesia wrapper for Elixir.","archived":false,"fork":false,"pushed_at":"2022-09-07T22:19:49.000Z","size":239,"stargazers_count":701,"open_issues_count":28,"forks_count":67,"subscribers_count":21,"default_branch":"master","last_synced_at":"2025-04-14T15:02:55.804Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/meh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-04-07T18:43:12.000Z","updated_at":"2025-03-16T11:50:16.000Z","dependencies_parsed_at":"2022-09-26T20:40:55.707Z","dependency_job_id":null,"html_url":"https://github.com/meh/amnesia","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meh%2Famnesia","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meh%2Famnesia/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meh%2Famnesia/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meh%2Famnesia/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/meh","download_url":"https://codeload.github.com/meh/amnesia/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254310520,"owners_count":22049470,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T02:00:57.860Z","updated_at":"2025-10-17T08:21:41.687Z","avatar_url":"https://github.com/meh.png","language":"Elixir","funding_links":[],"categories":["ORM and Datamapping"],"sub_categories":[],"readme":"amnesia - mnesia wrapper for Elixir\n===================================\namnesia wraps everything exposed by mnesia, from fragments to fragment hash,\naccess and backup behaviors.\n\nIt provides a simplified table and database definition with some macros and\nallows you to use the nice `Enum` functions on tables by implementing the\n`Enum.Iterator` protocol.\n\nEverything is documented and specced, even the unspecced and undocumented parts\nof mnesia that have been wrapped.\n\nThe documentation often refers to mnesia functions, I strongly suggest you read\n[mnesia's documentation](http://erlang.org/doc/man/mnesia.html) too, since it has a lot of valuable information.\n\nDefining a database\n-------------------\nTo use amnesia you have to define a database and the tables of that database.\n\nYou can have multiple databases in the same amnesia instance, a database is\nactually just a way to group *mnesia* tables.\n\n```elixir\n# needed to get defdatabase and other macros\nuse Amnesia\n\n# defines a database called Database, it's basically a defmodule with\n# some additional magic\ndefdatabase Database do\n  # this is just a forward declaration of the table, otherwise you'd have\n  # to fully scope User.read in Message functions\n  deftable User\n\n  # this defines a table with an user_id key and a content attribute, and\n  # makes the table a bag; tables are basically records with a bunch of helpers\n  deftable Message, [:user_id, :content], type: :bag do\n    # this isn't required, but it's always nice to spec things\n    @type t :: %Message{user_id: integer, content: String.t}\n\n    # this defines a helper function to fetch the user from a Message record\n    def user(self) do\n      User.read(self.user_id)\n    end\n\n    # this does the same, but uses dirty operations\n    def user!(self) do\n      User.read!(self.user_id)\n    end\n  end\n\n  # this defines a table with other attributes as ordered set, and defines an\n  # additional index as email, this improves lookup operations\n  deftable User, [{ :id, autoincrement }, :name, :email], type: :ordered_set, index: [:email] do\n    # again not needed, but nice to have\n    @type t :: %User{id: non_neg_integer, name: String.t, email: String.t}\n\n    # this is a helper function to add a message to the user, using write\n    # on the created records makes it write to the mnesia table\n    def add_message(self, content) do\n      %Message{user_id: self.id, content: content} |\u003e Message.write\n    end\n\n    # like above, but again with dirty operations, the bang methods are used\n    # thorough amnesia to be the dirty counterparts of the bang-less functions\n    def add_message!(self, content) do\n      %Message{user_id: self.id, content: content} |\u003e Message.write!\n    end\n\n    # this is a helper to fetch all messages for the user\n    def messages(self) do\n      Message.read(self.id)\n    end\n\n    # like above, but with dirty operations\n    def messages!(self) do\n      Message.read!(self.id)\n    end\n  end\nend\n```\n\nCreating the database\n---------------------\nBefore using a database you have to create it, and before it a schema.\n\nTo do so, you can use the built-in mix task `amnesia.create` passing your\ndatabase module via the `--database` or `-d` options.\n\n```sh\nmix amnesia.create -d Database --disk\n```\n\nThe available options for creating the databases are:\n\n- `--database` or `-d`: the database module to create\n- `--no-schema`: to avoid creating the schema\n- `--memory`: to create the tables with memory copying on the current node\n- `--disk`: to create the tables with disc_copies on the current node\n- `--disk!`: to create the tables with disc_only_copies on the current node\n\nBy default it creates the schema and uses disc_copies.\n\nIf you want to drop the tables there is also a drop task you should use with\n__CAUTION__ as it will destroy all data. To use it just call:\n\n```sh\nmix amnesia.drop -d Database\n```\n\nThe options accepted by this task are:\n\n- `--database` or `-d`: same as with create. A database module to drop tables\n- `--schema`: drops the schema too. Defaults to false\n\nWriting to the database\n-----------------------\nOnce the database has been defined and created, you can start using the various\ntables.\n\n```elixir\n# You want to be in a transaction most of the time, this ensures the data\n# doesn't get corrupted and you get meaningful values back.\n#\n# Most operations won't work outside a transaction and will raise an exception.\nAmnesia.transaction do\n  # Every table is a record, so you can do everything you can do with records.\n  #\n  # Once you want to save the record, you have to call `.write` on it, this\n  # will write the record to the table.\n  #\n  # Since we defined the `User` table with an `autoincrement` id attribute it\n  # will be incremented internally on write, unless the id attribute is set, in\n  # that case it will be left as is.\n  #\n  # If you want to know the values of the autoincrement fields, `.write` always\n  # returns the updated record.\n  john = %User{name: \"John\", email: \"john@example.com\"} |\u003e User.write\n\n  # Let's create more users.\n  richard = %User{name: \"Richard\", email: \"richard@example.com\"} |\u003e User.write\n  linus   = %User{name: \"Linus\", email: \"linus@example.com\"} |\u003e User.write\n\n  # Now let's add some messages.\n\n  john |\u003e User.add_message %S\"\"\"\n  When we program a computer to make choices intelligently after determining\n  its options, examining their consequences, and deciding which is most\n  favorable or most moral or whatever, we must program it to take an attitude\n  towards its freedom of choice essentially isomorphic to that which a human\n  must take to his own.\n  \"\"\"\n\n  john |\u003e User.add_message %S\"\"\"\n  He who refuses to do arithmetic is doomed to talk nonsense.\"\n  \"\"\"\n\n  john |\u003e User.add_message %S\"\"\"\n  It's difficult to be rigorous about whether a machine really 'knows',\n  'thinks', etc., because we're hard put to define these things. We understand\n  human mental processes only slightly better than a fish understands swimming.\n  \"\"\"\n\n  richard |\u003e User.add_message %S\"\"\"\n  For personal reasons, I do not browse the web from my computer. (I also have\n  no net connection much of the time.) To look at page I send mail to a daemon\n  which runs wget and mails the page back to me. It is very efficient use of my\n  time, but it is slow in real time.\n  \"\"\"\n\n  richard |\u003e User.add_message %S\"\"\"\n  I am skeptical of the claim that voluntarily pedophilia harms children. The\n  arguments that it causes harm seem to be based on cases which aren't\n  voluntary, which are then stretched by parents who are horrified by the idea\n  that their little baby is maturing.\n  \"\"\"\n\n  linus |\u003e User.add_message %S\"\"\"\n  Portability is for people who cannot write new programs.\n  \"\"\"\n\n  linus |\u003e User.add_message %S\"\"\"\n  Really, I'm not out to destroy Microsoft. That will just be a completely\n  unintentional side effect.\n  \"\"\"\n\n  linus |\u003e User.add_message %S\"\"\"\n  Modern PCs are horrible. ACPI is a complete design disaster in every way. But\n  we're kind of stuck with it. If any Intel people are listening to this and\n  you had anything to do with ACPI, shoot yourself now, before you reproduce.\n  \"\"\"\nend\n```\n\nReading from the database\n-------------------------\nOnce there's something written to the database you can start reading back\nrecords from it.\n\n```elixir\nAmnesia.transaction do\n  # The simplest way to read a record is using the key of the record (by\n  # default the first attribute)\n  #\n  # Since we wrote the John, Richard and Linus in this order and the id is\n  # defined as *autoincrement*, the first `User` will be John.\n  john = User.read(1)\n\n  # Now let's read his messages and print them all.\n  john |\u003e User.messages |\u003e Enum.each \u0026IO.puts(\u00261.content)\n\n  # You can also use an Exquisite selector to fetch records.\n  selection = Message.where user_id == 1 or user_id == 2,\n    select: content\n\n  # Get the values in the selector and print them.\n  selection |\u003e Amnesia.Selection.values |\u003e Enum.each \u0026IO.puts(\u00261.content)\nend\n```\n\nOther documentation\n-------------------\nAll the code has `@spec` and `@doc`, so you can either go around the source and\nread the `@docs`, use the REPL and `h/1` or generate the documentation with\n`ex_doc`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeh%2Famnesia","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmeh%2Famnesia","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeh%2Famnesia/lists"}