View Source Changelog

All notable changes to ActiveMemory are documented here. Versions follow Semantic Versioning; while the package is pre-1.0 a minor bump may carry a behavior change, and those are called out below.

0-8-0

0.8.0

Ecto compatibility. A Table can now be typed or defined as an Ecto schema, and the read API covers what Ecto.Repo offers.

added

Added

  • field/3 in an attributes block takes an optional Ecto type — field :name, :string — defaulting to :any. Types are not enforced on write; they power Ecto.Changeset casting and validation. Available as __attributes__(:types).
  • A Table can skip attributes entirely and define an Ecto embedded_schema. All table metadata is derived from the schema, so the module is a real Ecto schema and every changeset function works on it.
  • Autogenerated schema fields are honored on write: an :id/:binary_id primary key, a custom key such as @primary_key {:uuid, Ecto.UUID, autogenerate: true}, and timestamps().
  • write/1 accepts an Ecto.Changeset as well as a struct, like Ecto.Repo.insert/2. An invalid changeset returns {:error, changeset} with its action set to :insert, which is what a Phoenix form needs to render errors.
  • get/1, get!/1, get_by/1, get_by!/1, one!/1, reload/1 and reload!/1. The bang variants raise ActiveMemory.NotFoundError.
  • count/1, which asks the table for its size rather than copying records out, so it is O(1). On a ttl table it takes sweep: true to exclude expired but unswept records.
  • exists?/2.
  • :order_by, :limit and :offset on all/1 and select/2. Sorting happens after reading, and uses a value's own compare/2 when it has one, so Decimal and the calendar types order correctly rather than by Erlang term order.
  • ActiveMemory.NotFoundError and ActiveMemory.MultipleResultsError.
  • __attributes__(:primary_key), the table's first field — what ETS and Mnesia key a record on.

changed

Changed

  • one/1 now raises ActiveMemory.MultipleResultsError when a query matches more than one record, instead of returning {:error, :more_than_one_result}. This matches Ecto.Repo.one/2. withdraw/1 raises there too, since deleting an arbitrary one of several matches would be wrong. Callers matching on {:error, :more_than_one_result} need updating.
  • An Ecto schema table that declares a primary key somewhere other than its first field, or a composite primary key, raises when the table is created. An in memory table keys a record on its first field, so neither can be honored, and the previous behavior would have read the wrong field.

fixed

Fixed

  • An Ecto schema table with an autogenerating primary key of a custom type (@primary_key {:uuid, Ecto.UUID, autogenerate: true}) generated no key, so every record was written under a nil key and collapsed onto one entry.
  • Reconciling a recovered Mnesia table's options could crash the store's startup: an option change Mnesia refused raised out of init/1, and a table naming more than one copy type (ram_copies plus disc_copies, for instance) crashed the reconciliation even when the configuration was valid. A refused change is now logged as a warning and skipped, so the store starts and the table keeps its current setting. A copy configuration that is wrong in the code itself — the same node under two copy types — raises ArgumentError, since it would fail on every boot.
  • Compile warnings from the test dependency local_cluster (deprecated :slave usage, charlist syntax) are gone with the upgrade to 2.1.

documentation

Documentation

  • A "Deleting a record" section explaining that delete/1 matches a record in full, that a stale struct therefore removes nothing while still returning :ok, and that withdraw/1 is the query based alternative.
  • A ttl on an Ecto schema table needs an explicit field :expires_at, :integer; the attributes DSL still adds it for you.
  • Store and ActiveRepo documentation now describes the same behavior for the operations they share.
  • A "Testing" section covering which test modules can run async: true — a module owning its own table and store runs concurrently today — and which need async: false, namely modules sharing the application's store, since a table's module name is its physical table name.
  • The majority option, Mnesia's quorum writes, is documented as the mitigation for partition behavior rather than one line in a list of options.

0-7-4

0.7.4

fixed-1

Fixed

  • use ActiveMemory.Store and use ActiveMemory.ActiveRepo read the table's ttl while the caller's module compiled, making every table a compile time dependency of its store. Tooling that compiles a store's file without the table module loaded — a language server, for one — raised UndefinedFunctionError on code that compiles and runs correctly. The lookup happens at runtime now.

0-7-3

0.7.3

fixed-2

Fixed

  • Removed an unreachable ttl clause that newer Elixir type checkers flagged in any project defining a store on a table without a ttl.
  • Removed unreachable clauses in the ETS adapter's select/2.

0-7-2

0.7.2

changed-1

Changed

  • delete_all/0 returns :ok on success. The ETS adapter had returned the raw true from :ets.delete_all_objects/1 and the Mnesia adapter {:atomic, :ok}, neither matching the documented :ok | {:error, any()} spec, so :ok = Store.delete_all() raised a MatchError.

0-7-1-and-earlier

0.7.1 and earlier

See the commit history for releases before this changelog was kept. Notable additions were record expiry (ttl), ActiveMemory.ActiveRepo for managing several tables from one process, ActiveMemory.TableHeir so an ETS table survives its store crashing, and making withdraw/1 a single atomic operation.