{"id":13508868,"url":"https://github.com/sheharyarn/memento","last_synced_at":"2025-05-14T03:10:33.855Z","repository":{"id":42973393,"uuid":"142394543","full_name":"sheharyarn/memento","owner":"sheharyarn","description":"Simple + Powerful interface to the Mnesia Distributed Database 💾","archived":false,"fork":false,"pushed_at":"2025-01-14T23:48:58.000Z","size":266,"stargazers_count":773,"open_issues_count":5,"forks_count":26,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-05-11T05:16:35.573Z","etag":null,"topics":["cloud","cloud-native","database","distributed-systems","elixir","erlang","mnesia","otp","real-time"],"latest_commit_sha":null,"homepage":"http://hexdocs.pm/memento/","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sheharyarn.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-26T05:49:31.000Z","updated_at":"2025-04-25T00:45:47.000Z","dependencies_parsed_at":"2024-06-21T16:38:48.433Z","dependency_job_id":"f8edc4d3-322e-4e22-ab47-0b516be825aa","html_url":"https://github.com/sheharyarn/memento","commit_stats":{"total_commits":235,"total_committers":6,"mean_commits":"39.166666666666664","dds":"0.051063829787234005","last_synced_commit":"c9218ee3fcd1eaed4ee98219306402388ff225dd"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sheharyarn%2Fmemento","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sheharyarn%2Fmemento/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sheharyarn%2Fmemento/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sheharyarn%2Fmemento/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sheharyarn","download_url":"https://codeload.github.com/sheharyarn/memento/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254059512,"owners_count":22007769,"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":["cloud","cloud-native","database","distributed-systems","elixir","erlang","mnesia","otp","real-time"],"created_at":"2024-08-01T02:00:59.648Z","updated_at":"2025-05-14T03:10:28.831Z","avatar_url":"https://github.com/sheharyarn.png","language":"Elixir","funding_links":[],"categories":["ORM and Datamapping"],"sub_categories":[],"readme":"\u003c!-- Heading: Start --\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://hexdocs.pm/memento\"\u003e\n    \u003cimg alt=\"Memento\" src=\"media/logo.png\" width=\"450px\"/\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/sheharyarn/memento/actions/workflows/ci.yml\"\u003e\n    \u003cimg alt=\"CI Status\" src=\"https://github.com/sheharyarn/memento/actions/workflows/ci.yml/badge.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://hexdocs.pm/memento\"\u003e\n    \u003cimg alt=\"Coverage\" src=\"https://inch-ci.org/github/sheharyarn/memento.svg?branch=master\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://hex.pm/packages/memento\"\u003e\n    \u003cimg alt=\"Version\" src=\"https://img.shields.io/hexpm/v/memento.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://hex.pm/packages/memento\"\u003e\n    \u003cimg alt=\"Version\" src=\"https://img.shields.io/hexpm/dt/memento.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"./LICENSE\"\u003e\n    \u003cimg alt=\"License\" src=\"https://img.shields.io/hexpm/l/memento.svg\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cb\u003eSimple but Powerful Elixir interface to the Erlang Mnesia Database\u003c/b\u003e\u003c/br\u003e\n  \u003csub\u003eMnesia. Memento. \u003ca href=\"https://www.imdb.com/title/tt0209144/\"\u003eGet it?\u003c/a\u003e\u003c/sub\u003e\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\u003c!-- Heading: End --\u003e\n\n\n\n - 😀 **Easy to Use:** Provides a simple \u0026 intuitive API for working with [Mnesia][mnesia]\n - ⚡️ **Real-time:** Has extremely fast real-time data searches, even across many nodes\n - 💪 **Powerful Queries:** on top of Erlang's MatchSpec and QLC, that are much easier to use\n - 📓 **Detailed Documentation:** and examples for all methods on [HexDocs][docs]\n - 💾 **Persistent:** Schema can be coherently kept on disc \u0026 in memory\n - 🌐 **Distributed:** Data can easily be replicated on several nodes\n - 🌀 **Atomic:** A series of operations can be grouped in to a single atomic transaction\n - 🔍 **Focused:** Encourages good patterns by omitting dirty calls to the database\n - 🔧 **Mnesia Compatible:** You can still use Mnesia methods for Schemas and Tables created by Memento\n - ❄️  **No Dependencies:** Zero external dependencies; only uses the built-in Mnesia module\n - ⛅️ **MIT Licensed**: Free for personal and commercial use\n\n\u003cbr/\u003e\n\n\n\n**Memento** is an extremely easy-to-use and powerful wrapper in Elixir that makes it intuitive to work with\n[Mnesia][mnesia], the Erlang Distributed Realtime Database. The original Mnesia API in Erlang is convoluted, unorganized\nand combined with the complex `MatchSpec` and `QLC` query language, is hard to work with in Elixir, especially for\nbeginners. Memento attempts to define a simple API to work with schemas, removing the majority of complexity associated\nwith it.\n\n\u003cbr/\u003e\n\n\n\n\n## Installation\n\nAdd `:memento` to your list of dependencies in your Mix file:\n\n```elixir\ndef deps do\n  [{:memento, \"~\u003e 0.5.0\"}]\nend\n```\n\nIf your Elixir version is `1.3` or lower, also add it to your `applications` list:\n\n```elixir\ndef application do\n  [applications: [:memento]]\nend\n```\n\n_It's preferable to only add `:memento` and not `:mnesia` along with it._ This will ensure that that OTP calls to Mnesia\ngo through the Supervisor spec specified in Memento.\n\n\u003cbr/\u003e\n\n\n\n\n## Configuration\n\nIt is highly recommended that a custom path to the Mnesia database location is specified, even on the local `:dev`\nenvironment (You can add `.mnesia` to your `.gitignore`):\n\n```elixir\n# config/config.exs\nconfig :mnesia,\n  dir: '.mnesia/#{Mix.env}/#{node()}'        # Notice the single quotes\n```\n\n\u003cbr/\u003e\n\n\n\n\n## Usage\n\nYou start by defining a Module as a Memento Table by specifying its attributes, type and other options. At least two\nattributes are required, where the first one is the `primary-key` of the table. A simple definition looks like this:\n\n```elixir\ndefmodule Blog.Author do\n  use Memento.Table, attributes: [:username, :fullname]\nend\n```\n\nA slightly more complex definition that uses more options, could look like this:\n\n```elixir\ndefmodule Blog.Post do\n  use Memento.Table,\n    attributes: [:id, :title, :content, :status, :author],\n    index: [:status, :author],\n    type: :ordered_set,\n    autoincrement: true\n\n\n  # You can also define other methods\n  # or helper functions in the module\nend\n```\n\nOnce you have defined your schemas, you need to create them before you can interact with them:\n\n```elixir\nMemento.Table.create!(Blog.Author)\nMemento.Table.create!(Blog.Post)\n```\n\nSee the [`Memento.Table`][docs-table] documentation for detailed examples and more information about all the options.\n\n\u003cbr/\u003e\n\n\n\n\n## CRUD Operations \u0026 Queries\n\nOnce a Table has been created, you can perform read/write/delete operations on their records. An API for all of\nthese operations is exposed in the [`Memento.Query`][docs-query] module, but these methods can't be called directly.\nInstead, they must always be called inside a [`Memento.Transaction`][docs-transaction]:\n\n```elixir\nMemento.transaction! fn -\u003e\n  Memento.Query.all(Blog.Author)\nend\n\n# =\u003e [\n#  %Blog.Author{username: :sye,     fullname: \"Sheharyar Naseer\"},\n#  %Blog.Author{username: :jeanne,  fullname: \"Jeanne Bolding\"},\n#  %Blog.Author{username: :pshore,  fullname: \"Paul Shore\"},\n# ]\n```\n\n_For the sake of succinctness, transactions are ignored in most of the examples below, but they are still required._\nHere's a quick overview of all the basic operations:\n\n\n```elixir\n# Get all records in a Table\nMemento.Query.all(Post)\n\n# Get a specific record by its primary key\nMemento.Query.read(Post, id)\nMemento.Query.read(Author, username)\n\n# Write a record\nMemento.Query.write(%Author{username: :sarah, name: \"Sarah Molton\"})\n\n# Delete a record by primary key\nMemento.Query.delete(Post, id)\nMemento.Query.delete(Author, username)\n\n# Delete a record by passing the full object\nMemento.Query.delete_record(%Author{username: :pshore, name: \"Paul Shore\"})\n```\n\n\nFor more complex read operations, Memento exposes a [`select/3`][docs-query-select] method that lets you chain\nconditions using a simplified version of the Erlang MatchSpec. This is what some queries would look like for a\n`Movie` table:\n\n - Get all movies named \"Rush\":\n\n    ```elixir\n    Memento.Query.select(Movie, {:==, :title, \"Rush\"})\n    ```\n\n\n - Get all movies directed by Tarantino before the year 2000:\n\n    ```elixir\n    guards = [\n      {:==, :director, \"Quentin Tarantino\"},\n      {:\u003c, :year, 2000},\n    ]\n    Memento.Query.select(Movie, guards)\n    ```\n\nSee [`Query.select/3`][docs-query-select] for more information about the guard operators and detailed examples.\n\n\u003cbr/\u003e\n\n\n\n\n## Persisting to Disk\n\nSetting up disk persistence in `Mnesia` has always been a bit weird. It involves stopping the application, creating\nschemas on disk, restarting the application and then creating the tables with certain options. Here are the steps\nyou need to take to do all of that:\n\n```elixir\n# List of nodes where you want to persist\nnodes = [ node() ]\n\n# Create the schema\nMemento.stop\nMemento.Schema.create(nodes)\nMemento.start\n\n# Create your tables with disc_copies (only the ones you want persisted on disk)\nMemento.Table.create!(TableA, disc_copies: nodes)\nMemento.Table.create!(TableB, disc_copies: nodes)\nMemento.Table.create!(TableC)\n```\n\nThis needs to be done only once and not every time the application starts. It also makes sense to create a helper\nfunction or mix task that does this for you. You can see a [sample implementation here][que-persistence].\n\n\u003cbr/\u003e\n\n\n\n\n## Roadmap\n\n - [x] Memento\n    - [x] start/stop\n    - [x] info\n    - [x] system_info\n    - [ ] Application\n    - [ ] Config Vars\n - [x] Memento.Table\n    - [x] Create/Delete helpers\n    - [x] clear_table\n    - [x] table_info\n    - [x] wait\n    - [ ] Ecto-like DSL\n    - [ ] Migration Support\n - [x] Memento.Query\n    - [x] Integration with Memento.Table\n    - [x] match/select\n    - [x] read/write/delete\n    - [ ] first/next/prev/all_keys\n    - [ ] test matchspec\n    - [ ] continue/1 for select continuations\n    - [x] autoincrement\n    - [ ] Helper use macro\n - [x] Memento.Transaction\n    - [x] Simple/Synchronous\n    - [x] Bang versions\n    - [x] inside?\n    - [x] abort\n    - [ ] Lock Helpers\n - [x] Memento.Schema\n    - [x] create/delete\n    - [x] print (schema/1)\n - [ ] Memento.Collection\n    - [ ] Easy Helpers\n    - [ ] Custom DSL\n  - [ ] Mix Tasks\n\n\u003cbr/\u003e\n\n\n\n\n## FAQ\n\n\n\n#### 1. Why Memento/Mnesia?\n\nIn most applications, some kind of data storage mechanism is needed, but this usually means relying on some sort\nof external dependency or program. Memento should be used in situations when it might not always make sense in an\nApplication to do this (e.g. the data is ephemeral, the project needs to be kept light-weight, you need a simple\ndata store that persists across application restarts, data-code decoupling is not important etc.).\n\n\n#### 2. When shouldn't I use Memento/Mnesia?\n\nLike mentioned in the previous point, Memento/Mnesia has specific use-cases and it might not always make sense to\nuse it. This is usually when you don't want to couple your code and database, and want to allow independent or\nexternal accesses to transformation of your data. In such circumstances, you should always prefer using some other\ndatastore (like Redis, Postgres, etc.).\n\n\n#### 3. Isn't there already an 'Amnesia' library?\n\nI've been a long-time user of the [`Amnesia`][amnesia] package, but with the recent releases of Elixir (1.5 \u0026 above),\nthe library has started to show its age. Amnesia's dependence on the the `exquisite` package has caused a lot of\ncompilation problems, and it's complex macro-intensive structure hasn't made it easy to fix them either. The library\nitself doesn't even compile in Elixir 1.7+ so I finally decided to write my own after I desperately needed to update\nmy Mnesia-based projects.\n\nMemento is meant to be an extremely lightweight wrapper for Mnesia, providing a very easy set of helpers and forcing\ngood decisions by avoiding the \"dirty\" methods.\n\n\n#### 4. Are there any other projects that are using Memento?\n\nMemento is a new package so there aren't many Open Source examples available. [Que][que] is another library\nthat uses Memento for background job processing and storing the state of these Jobs. If your project uses\nMemento, feel free to send in a pull-request so it can be mentioned here.\n\n\u003cbr/\u003e\n\n\n\n\n## Contributing\n\n - [Fork][github-fork], Enhance, Send PR\n - Lock issues with any bugs or feature requests\n - Implement something from Roadmap\n - Spread the word :heart:\n\n\u003cbr\u003e\n\n\n\n\n## License\n\nThis package is available as open source under the terms of the [MIT License][license].\n\n\u003cbr\u003e\n\n\n\n\n\n  [logo]:                 media/logo.png\n  [shield-version]:       https://img.shields.io/hexpm/v/memento.svg\n  [shield-license]:       https://img.shields.io/hexpm/l/memento.svg\n  [shield-downloads]:     https://img.shields.io/hexpm/dt/memento.svg\n  [shield-travis]:        https://img.shields.io/travis/sheharyarn/memento/master.svg\n  [shield-inch]:          https://inch-ci.org/github/sheharyarn/memento.svg?branch=master\n\n  [travis-ci]:            https://travis-ci.org/sheharyarn/memento\n  [inch-ci]:              https://inch-ci.org/github/sheharyarn/memento\n\n  [license]:              ./LICENSE\n  [mnesia]:               http://erlang.org/doc/man/mnesia.html\n  [hexpm]:                https://hex.pm/packages/memento\n  [imdb-memento]:         https://www.imdb.com/title/tt0209144/\n  [que]:                  https://github.com/sheharyarn/que\n  [amnesia]:              https://github.com/meh/amnesia\n\n  [docs]:                 https://hexdocs.pm/memento\n  [docs-transaction]:     https://hexdocs.pm/memento/Memento.Transaction.html\n  [docs-table]:           https://hexdocs.pm/memento/Memento.Table.html\n  [docs-query]:           https://hexdocs.pm/memento/Memento.Query.html\n  [docs-query-select]:    https://hexdocs.pm/memento/Memento.Query.html#select/3\n\n  [github-fork]:          https://github.com/sheharyarn/memento/fork\n  [que-persistence]:      https://github.com/sheharyarn/que/blob/dc3764a27f8ce3e28b15a7bfafbca604fb424ecb/lib/que/persistence/mnesia/mnesia.ex#L90-L108\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsheharyarn%2Fmemento","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsheharyarn%2Fmemento","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsheharyarn%2Fmemento/lists"}