AshR2RML.OBDA.Adapter behaviour (AshR2RML v26.8.29)

Copy Markdown View Source

Behaviour for OBDA query engines, so a caller can dispatch to whichever engine a given mapping/resource actually needs without hand-checking which concrete module to call.

AshR2RML today has two independently-evolved OBDA execution paths -- AshR2RML.OBDA.Ontop (real Ontop CLI process, SPARQL-to-SQL rewriting over a JDBC-connected Postgres) and AshR2RML.OBDA.InMemory (real Ash.read!/2 + in-process SPARQL algebra, for any data layer Ontop cannot reach) -- with no shared interface between them. This behaviour is modeled after Gno's Gno.Store.Adapter (~/gno/lib/gno/store/adapter.ex): a minimal callback contract that lets a caller dispatch/2 by config-struct type, the same way Gno.Store pattern-matches %adapter_type{} to call adapter_type.<fn>.

What is deliberately not ported from Gno.Store.Adapter: SPARQL Graph Store Protocol endpoint resolution (determine_query_endpoint/1, determine_update_endpoint/1, determine_graph_store_endpoint/1), HTTP dispatch (Gno.Store.GenSPARQL), and default/union graph-semantics configuration. AshR2RML never talks to a live SPARQL protocol server -- Ontop is invoked as a one-shot CLI process per query, and InMemory never leaves the BEAM -- so there is no persistent store connection to abstract over.

Summary

Callbacks

The engine's canonical identifier, e.g. :ontop or :in_memory.

Executes sparql against whatever config names (a mapping file pair for Ontop, an Ash resource + mapping IR for InMemory), returning an engine-specific observation struct wrapped in {:ok, _} on success or {:error, %Refusal{}} / {:error, observation} on failure -- unified only at the ok/error-tuple level, since the two engines' observation structs (AshR2RML.OBDA.Observation vs AshR2RML.SPARQL.Observation) carry genuinely different evidence (an external process's exit status and stdout vs. an in-process materialization's row set) and forcing them into one shape would erase real information rather than unify a real abstraction.

Functions

Dispatches query/3 to the adapter module matching config's struct type (mirroring Gno.Store's %adapter_type{} -> adapter_type.<fn> dispatch).

Callbacks

engine_name()

@callback engine_name() :: atom()

The engine's canonical identifier, e.g. :ontop or :in_memory.

query(config, sparql, opts)

@callback query(
  config :: struct() | keyword() | map(),
  sparql :: String.t(),
  opts :: keyword()
) ::
  {:ok, struct()} | {:error, struct() | AshR2RML.Refusal.t()}

Executes sparql against whatever config names (a mapping file pair for Ontop, an Ash resource + mapping IR for InMemory), returning an engine-specific observation struct wrapped in {:ok, _} on success or {:error, %Refusal{}} / {:error, observation} on failure -- unified only at the ok/error-tuple level, since the two engines' observation structs (AshR2RML.OBDA.Observation vs AshR2RML.SPARQL.Observation) carry genuinely different evidence (an external process's exit status and stdout vs. an in-process materialization's row set) and forcing them into one shape would erase real information rather than unify a real abstraction.

Functions

dispatch(config, sparql, opts \\ [])

@spec dispatch(struct(), String.t(), keyword()) ::
  {:ok, struct()} | {:error, struct() | AshR2RML.Refusal.t()}

Dispatches query/3 to the adapter module matching config's struct type (mirroring Gno.Store's %adapter_type{} -> adapter_type.<fn> dispatch).