DoubleEntryLedger.Stores.InstanceStore (double_entry_ledger v0.1.0)

View Source

Provides functions for managing ledger instances in the double-entry ledger system.

This module serves as the primary interface for all ledger instance operations, including creating, retrieving, updating, and deleting instances. It also provides specialized queries to verify ledger integrity through balance verification across currencies.

Key Functionality

  • Instance Management: Create, retrieve, update, and delete ledger instances
  • Instance Queries: Find and list instances by various criteria
  • Balance Verification: Calculate and verify that total debits equal total credits by currency
  • Transaction Safety: Ensures critical operations use appropriate database isolation levels

Usage Examples

Creating a new ledger instance:

{:ok, instance} = DoubleEntryLedger.Stores.InstanceStore.create(%{
  address: "Business Ledger",
  metadata: %{owner: "ACME Corp"}
})

Retrieving and updating an instance:

instance = DoubleEntryLedger.Stores.InstanceStore.get_by_id(instance_id)
{:ok, updated_instance} = DoubleEntryLedger.Stores.InstanceStore.update(
  instance.id,
  %{address: "Updated:Ledger:address"}
)

Verifying ledger balance integrity:

{:ok, currency_balances} = InstanceStore.sum_accounts_debits_and_credits_by_currency(instance.id)
# Check that for each currency, debits = credits

Implementation Notes

All functions perform appropriate validation and return standardized results:

  • Success: {:ok, result}
  • Error: {:error, reason}

Balance verification queries run in transactions with REPEATABLE READ isolation to ensure consistency when concurrent operations are taking place.

Summary

Functions

Creates a new ledger instance with the given attributes.

Deletes a ledger instance by its ID.

Retrieves a ledger instance by its ID.

Calculates the sum of debits and credits for all accounts in a ledger instance, grouped by currency.

Updates a ledger instance with the given attributes.

Functions

create(attrs)

@spec create(map()) ::
  {:ok, DoubleEntryLedger.Instance.t()} | {:error, Ecto.Changeset.t()}

Creates a new ledger instance with the given attributes.

Parameters

  • attrs (map): A map of attributes for the ledger instance.

Returns

  • {:ok, instance}: On success.
  • {:error, changeset}: If there was an error during creation.

Examples

iex> attrs = %{address: "Test:Ledger"}
iex> {:ok, instance} = InstanceStore.create(attrs)
iex> instance.address
"Test:Ledger"

delete(id)

@spec delete(Ecto.UUID.t()) ::
  {:ok, DoubleEntryLedger.Instance.t()} | {:error, Ecto.Changeset.t()}

Deletes a ledger instance by its ID.

Ensures that there are no associated transactions or accounts before deletion, as defined in Instance.delete_changeset/1.

Parameters

  • id (Ecto.UUID.t()): The ID of the ledger instance to delete.

Returns

  • {:ok, instance}: On success.
  • {:error, changeset}: If there was an error during deletion.

Examples

iex> {:ok, instance} = InstanceStore.create(%{address: "Temporary:Ledger"})
iex> {:ok, _} = InstanceStore.delete(instance.id)
iex> InstanceStore.get_by_id(instance.id) == nil
true

get_by_address(address)

@spec get_by_address(String.t()) :: DoubleEntryLedger.Instance.t() | nil

get_by_id(id)

@spec get_by_id(Ecto.UUID.t()) :: DoubleEntryLedger.Instance.t() | nil

Retrieves a ledger instance by its ID.

Parameters

  • id (Ecto.UUID.t()): The ID of the ledger instance.

Returns

  • instance: The ledger instance struct, or nil if not found.

Examples

iex> {:ok, instance} = InstanceStore.create(%{address: "Sample:Ledger"})
iex> retrieved = InstanceStore.get_by_id(instance.id)
iex> retrieved.id == instance.id
true

list_all()

sum_accounts_debits_and_credits_by_currency(instance_id)

@spec sum_accounts_debits_and_credits_by_currency(Ecto.UUID.t()) ::
  {:ok, [map()]} | {:error, Ecto.Changeset.t()}

Calculates the sum of debits and credits for all accounts in a ledger instance, grouped by currency.

This function runs a database query in a transaction with REPEATABLE READ isolation level to ensure consistent results even if accounts are being updated concurrently.

Parameters

  • instance_id (Ecto.UUID.t()): The ID of the ledger instance.

Returns

  • {:ok, list(map)}: On success, returns a list of maps containing currency, posted_debit, posted_credit, pending_debit, and pending_credit sums.
  • {:error, reason}: If there was an error during the transaction.

update(id, attrs)

@spec update(Ecto.UUID.t(), map()) ::
  {:ok, DoubleEntryLedger.Instance.t()} | {:error, Ecto.Changeset.t()}

Updates a ledger instance with the given attributes.

Parameters

  • id (Ecto.UUID.t()): The ID of the ledger instance to update.
  • attrs (map): The attributes to update.

Returns

  • {:ok, instance}: On success.
  • {:error, changeset}: If there was an error during update.

Examples

iex> {:ok, instance} = InstanceStore.create(%{address: "Ledger"})
iex> {:ok, updated_instance} = InstanceStore.update(instance.id, %{address: "Updated:Ledger"})
iex> updated_instance.address
"Updated:Ledger"