Behaviour for defining custom manifest types with extensible logic.
This module enables applications to create specialized manifest types by extending
DCATR.Manifest with custom properties, loading logic, and resource extraction.
The behaviour provides a hierarchical callback system with low-level building blocks
and high-level orchestration points.
Callback Hierarchy
Low-level callbacks (per-file/resource operations):
init_dataset/1- Initialize empty dataset with optional seed datagraph_name_for_file/2- Classify files into named graphs during loadingload_file/2- Load and preprocess individual RDF files
High-level callbacks (pipeline orchestration):
load_dataset/1- Complete dataset loading pipeline (calls low-level callbacks)load_manifest/2- Extract service and additional resources from loaded dataset
Usage
Custom manifest types should use DCATR.Manifest.Type and define a Grax schema
extending DCATR.Manifest:
defmodule MyApp.Manifest do
use DCATR.Manifest.Type
use Grax.Schema
schema MyApp.NS.ManifestType < DCATR.Manifest do
property custom_config: MyApp.NS.customConfig(), type: :string
link agent: MyApp.NS.agent(), type: MyApp.Agent
end
@impl true
def load_manifest(manifest, opts) do
with {:ok, manifest} <- super(manifest, opts),
{:ok, agent} <- load_custom_agent(manifest) do
Grax.put(manifest, :agent, agent)
end
end
endThe module automatically provides convenience functions for accessing the manifest
hierarchy: manifest/1, service/1, repository/1, dataset/1 (with ! variants).
Summary
Callbacks
Generates manifest files from templates for a project.
Returns the path to the template directory used for manifest generation.
Low-level callback for determining the graph name for a file during loading.
Low-level callback for initializing the manifest dataset before loading files.
High-level callback for orchestrating the complete dataset loading process.
Low-level callback for loading and preprocessing a single RDF file.
High-level callback for extracting and loading resources from the dataset.
Functions
Returns the service type module for a given manifest type.
Types
@type schema() :: Grax.Schema.t()
@type t() :: module()
Callbacks
Generates manifest files from templates for a project.
See DCATR.Manifest.Generator for details on the generation process which the
default implementation uses.
@callback generator_template() :: String.t()
Returns the path to the template directory used for manifest generation.
The default implementation points to DCATR.Manifest.Generator.default_template_dir/0.
Override this to provide custom manifest templates for your manifest type.
@callback graph_name_for_file(file :: String.t(), opts :: keyword()) :: RDF.Statement.graph_name() | nil
Low-level callback for determining the graph name for a file during loading.
Called by load_file/2 to classify loaded graphs. Override this to add custom
file classification patterns (e.g., based on filename patterns or content inspection).
The default implementation calls DCATR.Manifest.Loader.graph_name_for_file/2.
Example Override
@impl true
def graph_name_for_file(file, opts) do
super(file, opts) ||
cond do
file =~ ~r/store\.(test|dev|prod)\.(ttl|nt)$/ -> DCATR.Manifest.Loader.service_manifest_graph_name()
file =~ ~r/history\./ -> RDF.bnode("history")
true -> nil
end
end
@callback init_dataset(opts :: keyword()) :: {:ok, RDF.Dataset.t()} | {:error, any()}
Low-level callback for initializing the manifest dataset before loading files.
Called by load_dataset/1 at the start of the loading process, before any files
are read. Override this to inject seed data or perform custom initialization.
The default implementation DCATR.Manifest.Loader.init_dataset/1 returns an empty dataset.
Example Override
@impl true
def init_dataset(opts) do
# Add seed triples before file loading
{:ok, RDF.Dataset.new(...)}
end
@callback load_dataset(opts :: keyword()) :: {:ok, RDF.Dataset.t()} | {:error, any()}
High-level callback for orchestrating the complete dataset loading process.
Called by DCATR.Manifest.Loader.load/2 to load all manifest files and merge them
into a dataset. Override this to customize the loading pipeline or add dataset-level
preprocessing after all files are loaded.
The default implementation calls DCATR.Manifest.Loader.load_dataset/1.
Example Override
@impl true
def load_dataset(opts) do
with {:ok, dataset} <- super(opts) do
preprocess(dataset)
end
end
@callback load_file(file :: String.t(), opts :: keyword()) :: {:ok, RDF.Dataset.t() | RDF.Graph.t() | nil} | {:error, any()}
Low-level callback for loading and preprocessing a single RDF file.
Called by load_dataset/1 for each file during the loading process. Override this
to add custom preprocessing (e.g., template expansion, validation) before the file
data is merged into the dataset.
Return {:ok, nil} to skip a file (e.g., based on custom filtering logic).
The default implementation calls DCATR.Manifest.Loader.load_file/2.
Example Override
@impl true
def load_file(file, opts) do
cond do
file =~ ~r/\.ignore.nt\./ -> {:ok, nil} # Skip files matching pattern
true -> super(file, opts)
end
end
High-level callback for extracting and loading resources from the dataset.
Called by DCATR.Manifest.Loader.load/2 after the dataset is loaded. Override this
to load additional resources (e.g., agents, policies) alongside the service.
The default implementation calls DCATR.Manifest.Loader.load_manifest/2.
Options
:service_id- Explicit service ID (skips auto-detection)
Example Override
@impl true
def load_manifest(manifest, opts) do
with {:ok, manifest} <- super(manifest, opts),
{:ok, agent} <- Agent.load(manifest.dataset, agent_id(), ...) do
Grax.put(manifest, :agent, agent)
end
end
Functions
Returns the service type module for a given manifest type.
Extracts the DCATR.Service.Type from the manifest's :service property schema definition.
Examples
iex> DCATR.Manifest.Type.service_type(DCATR.Manifest)
DCATR.Service