Skip to main content

src/barrel_rep_transport_local.erl

%%%-------------------------------------------------------------------
%%% @doc barrel_rep_transport_local - Local transport for replication
%%%
%%% Transport implementation for replicating between databases in
%%% the same Erlang VM. The endpoint is simply the database name.
%%% @end
%%%-------------------------------------------------------------------
-module(barrel_rep_transport_local).

-behaviour(barrel_rep_transport).

-include("barrel_docdb.hrl").

%% barrel_rep_transport callbacks
-export([
    get_doc/3,
    put_rev/4,
    revsdiff/3,
    get_changes/3,
    get_local_doc/2,
    put_local_doc/3,
    delete_local_doc/2,
    db_info/1,
    sync_hlc/2
]).

%%====================================================================
%% barrel_rep_transport callbacks
%%====================================================================

%% @doc Get a document with options
-spec get_doc(db_name(), docid(), map()) ->
    {ok, map(), map()} | {error, not_found} | {error, term()}.
get_doc(DbName, DocId, Opts) ->
    IncludeHistory = maps:get(history, Opts, false),
    GetOpts = case maps:get(rev, Opts, undefined) of
        undefined -> #{};
        RequestedRev -> #{rev => RequestedRev}
    end,
    case barrel_docdb:get_doc(DbName, DocId, GetOpts) of
        {ok, Doc} ->
            Rev = maps:get(<<"_rev">>, Doc),
            Meta = #{
                <<"rev">> => Rev,
                <<"deleted">> => maps:get(<<"_deleted">>, Doc, false)
            },
            Meta2 = case IncludeHistory of
                true ->
                    %% Build revisions from rev
                    Revisions = build_revisions(Rev),
                    Meta#{<<"revisions">> => Revisions};
                false ->
                    Meta
            end,
            {ok, Doc, Meta2};
        {error, _} = Error ->
            Error
    end.

%% @doc Put a document with explicit revision history
-spec put_rev(db_name(), map(), [revid()], boolean()) ->
    {ok, docid(), revid()} | {error, term()}.
put_rev(DbName, Doc, History, Deleted) ->
    barrel_docdb:put_rev(DbName, Doc, History, Deleted).

%% @doc Get revision differences
-spec revsdiff(db_name(), docid(), [revid()]) ->
    {ok, [revid()], [revid()]} | {error, term()}.
revsdiff(DbName, DocId, RevIds) ->
    barrel_docdb:revsdiff(DbName, DocId, RevIds).

%% @doc Get changes since a sequence
-spec get_changes(db_name(), seq() | first, map()) ->
    {ok, [map()], seq()} | {error, term()}.
get_changes(DbName, Since, Opts) ->
    barrel_docdb:get_changes(DbName, Since, Opts).

%% @doc Get a local document
-spec get_local_doc(db_name(), docid()) ->
    {ok, map()} | {error, not_found} | {error, term()}.
get_local_doc(DbName, DocId) ->
    barrel_docdb:get_local_doc(DbName, DocId).

%% @doc Put a local document
-spec put_local_doc(db_name(), docid(), map()) -> ok | {error, term()}.
put_local_doc(DbName, DocId, Doc) ->
    barrel_docdb:put_local_doc(DbName, DocId, Doc).

%% @doc Delete a local document
-spec delete_local_doc(db_name(), docid()) -> ok | {error, not_found} | {error, term()}.
delete_local_doc(DbName, DocId) ->
    barrel_docdb:delete_local_doc(DbName, DocId).

%% @doc Get database info
-spec db_info(db_name()) -> {ok, map()} | {error, term()}.
db_info(DbName) ->
    barrel_docdb:db_info(DbName).

%% @doc Synchronize local HLC with remote timestamp
%% This ensures the local clock reflects causality with remote events.
%% Note: HLC is global to the node, not per-database.
-spec sync_hlc(db_name(), barrel_hlc:timestamp()) ->
    {ok, barrel_hlc:timestamp()} | {error, term()}.
sync_hlc(_DbName, RemoteHlc) ->
    barrel_docdb:sync_hlc(RemoteHlc).

%%====================================================================
%% Internal functions
%%====================================================================

%% @doc Build revisions structure from a single revision
%% In a full implementation, this would query the revision tree
build_revisions(Rev) ->
    {Gen, Hash} = barrel_doc:parse_revision(Rev),
    #{
        <<"start">> => Gen,
        <<"ids">> => [Hash]
    }.