Packages

Asset-first data orchestration framework for Elixir/BEAM.

Current section

Files

Jump to
flowstone lib flowstone io memory.ex
Raw

lib/flowstone/io/memory.ex

defmodule FlowStone.IO.Memory do
@moduledoc """
In-memory I/O manager for tests and development.
Keys are normalized to ensure consistent lookups regardless of partition format
(atoms, strings, dates all serialize to the same canonical form).
"""
use Agent
@behaviour FlowStone.IO.Manager
alias FlowStone.Partition
def start_link(opts \\ []) do
name = Keyword.get(opts, :name, __MODULE__)
Agent.start_link(fn -> %{} end, name: name)
end
@impl true
def load(asset, partition, config) do
agent = resolve_agent(config)
key = normalize_key(asset, partition)
case Agent.get(agent, &Map.get(&1, key)) do
nil -> {:error, :not_found}
data -> {:ok, data}
end
end
@impl true
def store(asset, data, partition, config) do
agent = resolve_agent(config)
key = normalize_key(asset, partition)
Agent.update(agent, &Map.put(&1, key, data))
:ok
end
@impl true
def delete(asset, partition, config) do
agent = resolve_agent(config)
key = normalize_key(asset, partition)
Agent.update(agent, &Map.delete(&1, key))
:ok
end
@impl true
def metadata(asset, partition, config) do
with {:ok, data} <- load(asset, partition, config) do
{:ok,
%{
size_bytes: :erlang.external_size(data),
updated_at: DateTime.utc_now(),
checksum: :erlang.phash2(data)
}}
end
end
@impl true
def exists?(asset, partition, config) do
agent = resolve_agent(config)
key = normalize_key(asset, partition)
Agent.get(agent, &Map.has_key?(&1, key))
end
# Normalize keys to ensure consistent lookups regardless of partition format
defp normalize_key(asset, partition) do
asset_str = to_string(asset)
partition_str = Partition.serialize(partition)
{asset_str, partition_str}
end
defp resolve_agent(config) do
case config do
%{agent: agent} -> agent
%{"agent" => agent} -> agent
_ -> __MODULE__
end
end
end