Gitility.RefDB.Backend behaviour (Gitility v0.4.0)

Copy Markdown View Source

The behaviour for Elixir-backed reference resolution.

References are mutable names for immutable objects, so they live behind a separate contract from object storage: a caller that already knows a commit ID needs no RefDB at all, and a RefDB can be served by GitHub's API, a database, or a snapshot taken at publish time.

The provider model is the same as Gitility.ODB.Backend: init/1 builds a read-only state term, callbacks are stateless and dispatched concurrently, and mutable state is the backend's own explicit responsibility. One module may implement both behaviours, but Gitility treats the two roles as independent capabilities and never shares state between them implicitly.

Reference names are full raw binaries (refs/heads/main); convenience branch/tag selectors are expanded by Gitility before the backend is called. Symbolic refs are followed by Gitility with a hard hop limit. Each hop is an independent, per-hop-atomic resolve/2 call, so a moving backend may expose different generations across one symbolic chain. A backend that needs chain-coherent answers must resolve symbolic refs internally and return direct targets; this is the recommended shape and is what typical API-backed providers naturally return. An optional resolve_following/2 callback is a possible post-1.0 extension, not part of the 0.x behaviour.

Summary

Types

Opaque backend state, produced by init/1, passed read-only.

Callbacks

Builds the backend state from the configuration term given to Gitility.RefDB.start_link/1.

Lists references matching a query as a page of Gitility.Ref structs. Optional: a resolve-only backend (e.g. "ask GitHub for one branch head") simply cannot enumerate, and Gitility.RefDB.list/2 returns {:error, %Gitility.Error{code: :unsupported_operation}} for it.

Invalidates cached ref state. Optional.

Resolves one full reference name to its target, or :not_found.

Cleanup on provider shutdown. Optional.

Types

state()

@type state() :: term()

Opaque backend state, produced by init/1, passed read-only.

Callbacks

init(term)

@callback init(term()) :: {:ok, state()} | {:error, term()}

Builds the backend state from the configuration term given to Gitility.RefDB.start_link/1.

list(t, state)

(optional)
@callback list(Gitility.RefQuery.t(), state()) ::
  {:ok, Gitility.Page.t(Gitility.Ref.t())} | {:error, term()}

Lists references matching a query as a page of Gitility.Ref structs. Optional: a resolve-only backend (e.g. "ask GitHub for one branch head") simply cannot enumerate, and Gitility.RefDB.list/2 returns {:error, %Gitility.Error{code: :unsupported_operation}} for it.

refresh(state)

(optional)
@callback refresh(state()) :: :ok | {:error, term()}

Invalidates cached ref state. Optional.

resolve(binary, state)

@callback resolve(binary(), state()) ::
  {:ok, Gitility.RefTarget.t() | :not_found} | {:error, term()}

Resolves one full reference name to its target, or :not_found.

A symbolic target causes Gitility to make another independent resolve/2 callback for the next hop. Return a direct target if the backend requires a chain-coherent result.

terminate(term, state)

(optional)
@callback terminate(term(), state()) :: term()

Cleanup on provider shutdown. Optional.