# `Beancount.Storage`
[🔗](https://github.com/thanos/beancount_ex/blob/v0.6.0/lib/beancount/storage.ex#L1)

Storage and import/export for Beancount directives via Ecto.

`Beancount.Storage` is the high-level persistence API. It converts
`Beancount.Directives.*` structs to `Beancount.Schemas.*` rows (and back),
backed by `Beancount.Repo`. Use it to load a ledger into the database, read
it back, or round-trip through `.bean` files.

For SQL queries over stored rows, use `Beancount.Queries`. For balance
reports that require inventory booking, use `Beancount.Report` (which runs
BQL through the configured engine).

## Configuration

The default backend is SQLite in-memory (`:memory:`), which requires no setup
and is cleared when the OS process exits. Keep `pool_size: 1` with
`:memory:` — each connection in the pool gets its own empty database.

    config :beancount_ex, Beancount.Repo,
      database: ":memory:",
      pool_size: 1

For a persistent ledger, point `:database` at a file:

    config :beancount_ex, Beancount.Repo, database: "ledger.db"

The migration in `priv/repo/migrations` creates one table per directive type;
the application supervisor runs it on startup.

## Public functions

| Function | Description |
|----------|-------------|
| `import_file/1` | Parse a `.bean` file and store the directives |
| `store/1` | Replace all rows with a directive list |
| `load/0` | Rebuild directive structs from the database |
| `export_file/1` | Render stored directives to a `.bean` file |
| `clear/0` | Delete every row from all directive tables |

`store/1` and `import_file/1` run in a transaction: existing rows are
cleared first, then each directive is inserted in source order (`file_order`).

## Example: store, query, export

    ledger = [
      Beancount.open(~D[2026-01-01], "Assets:Bank", ["USD"]),
      Beancount.transaction(~D[2026-01-31], "*", "Employer", "Salary", [
        Beancount.posting("Assets:Bank", Decimal.new("100"), "USD"),
        Beancount.posting("Income:Salary", Decimal.new("-100"), "USD")
      ])
    ]

    {:ok, 2} = Beancount.Storage.store(ledger)

    [%Beancount.Directives.Open{account: "Assets:Bank"} | _] =
      Beancount.Storage.load()

    Beancount.Queries.list_opens(prefix: "Assets")

    :ok = Beancount.Storage.export_file("out.bean")

## Import / export

    {:ok, count} = Beancount.Storage.import_file("ledger.bean")
    :ok = Beancount.Storage.export_file("out.bean")

Future backends: PostgreSQL (via `postgrex`), Mnesia (via `ecto_mnesia`).

# `clear`

```elixir
@spec clear() :: :ok
```

Clear all directives from the database.

Deletes every row from all directive tables. Always returns `:ok`.

## Examples

    :ok = Beancount.Storage.clear()
    [] = Beancount.Storage.load()

# `export_file`

```elixir
@spec export_file(Path.t()) :: :ok | {:error, term()}
```

Export all directives from the database to a `.bean` file.

Loads every stored directive (see `load/0`) and renders it to Beancount text
at `path`.

## Examples

    :ok = Beancount.Storage.export_file("out.bean")

# `import_file`

```elixir
@spec import_file(Path.t()) :: {:ok, non_neg_integer()} | {:error, term()}
```

Import directives from a `.bean` file into the database.

Parses the file and stores the resulting directives, replacing any existing
rows. Returns the number of directives stored.

## Examples

    {:ok, count} = Beancount.Storage.import_file("ledger.bean")
    # => {:ok, 128}

# `load`

```elixir
@spec load() :: [Beancount.Directive.t()]
```

Load all directives from the database.

Rebuilds `Beancount.Directives.*` structs from the stored rows. Dated
directives are returned in date order; undated directives (`option`,
`include`, `plugin`, `pushtag`, `poptag`) sort ahead of dated ones.

## Examples

    Beancount.Storage.store([Beancount.open(~D[2026-01-01], "Assets:Bank", ["USD"])])

    [%Beancount.Directives.Open{account: "Assets:Bank"}] = Beancount.Storage.load()

# `store`

```elixir
@spec store([Beancount.Directive.t()]) :: {:ok, non_neg_integer()} | {:error, term()}
```

Store a list of directives into the database.

Runs in a transaction that first clears all existing rows, then inserts each
directive into its matching table. Returns `{:ok, count}` where `count` is the
number of directives actually stored; entries that are not recognized
directives are skipped and not counted.

## Examples

    ledger = [
      Beancount.open(~D[2026-01-01], "Assets:Bank", ["USD"]),
      Beancount.transaction(~D[2026-01-31], "*", "Employer", "Salary", [
        Beancount.posting("Assets:Bank", Decimal.new("100"), "USD"),
        Beancount.posting("Income:Salary", Decimal.new("-100"), "USD")
      ])
    ]

    {:ok, 2} = Beancount.Storage.store(ledger)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
