Document CRUD and query API for TerminusDB.
Wraps the /api/document/{path} endpoints. A "document" is a JSON object
conforming to a schema class, stored as linked triples. Documents can be
inserted, retrieved, queried by template, replaced, and deleted.
All functions require a TerminusDB.Config scoped to a database (via
TerminusDB.Config.with_database/2). The organization defaults to
config.organization but can be overridden per call via the :organization
option.
Graph types
Operations target the :instance graph (data) by default. Pass
graph_type: :schema to operate on the schema graph (schema documents are
documents too).
Quick start
config =
TerminusDB.Config.new(endpoint: "http://localhost:6363")
|> TerminusDB.Config.with_database("mydb")
# Insert a schema (Class document)
{:ok, _} =
TerminusDB.Document.insert(config,
%{"@type" => "Class", "@id" => "Person", "name" => "xsd:string"},
author: "admin", message: "add schema", graph_type: :schema
)
# Insert a document
{:ok, _} =
TerminusDB.Document.insert(config,
%{"@type" => "Person", "name" => "Alice"},
author: "admin", message: "add Alice"
)
# Retrieve documents by type
{:ok, docs} = TerminusDB.Document.get(config, type: "Person", as_list: true)
# Query by template
{:ok, matches} =
TerminusDB.Document.query(config, %{"@type" => "Person", "name" => "Alice"})
# Stream large result sets
TerminusDB.Document.stream(config, type: "Person")
|> Stream.each(&IO.inspect/1)
|> Stream.run()
Summary
Functions
Deletes documents from the database.
Deletes documents, or raises TerminusDB.Error.
Retrieves documents from the database.
Retrieves documents, or raises TerminusDB.Error.
Inserts one or more documents into the database.
Inserts documents, returning the response body or raising TerminusDB.Error.
Queries documents by a template.
Queries documents by template, or raises TerminusDB.Error.
Replaces one or more existing documents.
Replaces documents, or raises TerminusDB.Error.
Returns a Stream of documents, decoded incrementally from the response.
Types
@type get_opt() :: {:graph_type, graph_type()} | {:id, String.t()} | {:type, String.t()} | {:skip, non_neg_integer()} | {:count, pos_integer()} | {:as_list, boolean()} | {:unfold, boolean()} | {:minimized, boolean()} | {:compress_ids, boolean()} | {:organization, String.t()}
@type graph_type() :: :instance | :schema
@type query_opt() :: {:graph_type, graph_type()} | {:skip, non_neg_integer()} | {:count, pos_integer()} | {:as_list, boolean()} | {:organization, String.t()}
Functions
@spec delete(TerminusDB.Config.t(), [delete_opt()]) :: {:ok, term()} | {:error, TerminusDB.Error.t()}
Deletes documents from the database.
With :id, deletes a single document. With :nuke, deletes all documents at
the resource location. Without either, a body containing a list of IDs must
be posted (not yet supported by this function; use :id or :nuke).
Options
:author,:message— commit metadata (required by the API).:graph_type—:instance(default) or:schema.:id— delete a specific document by ID.:nuke— delete all documents (dangerous).:organization— overridesconfig.organization.
Examples
iex> config = TerminusDB.Config.new(
...> endpoint: "http://localhost:6363",
...> adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"api:status" => "api:success"})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> {:ok, resp} = TerminusDB.Document.delete(config,
...> id: "Person/Alice", author: "admin", message: "remove Alice"
...> )
iex> resp["api:status"]
"api:success"
@spec delete!(TerminusDB.Config.t(), [delete_opt()]) :: term()
Deletes documents, or raises TerminusDB.Error.
Examples
iex> config = TerminusDB.Config.new(
...> endpoint: "http://localhost:6363",
...> adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"api:status" => "api:success"})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> TerminusDB.Document.delete!(config, id: "Person/Alice", author: "a", message: "m")
%{"api:status" => "api:success"}
@spec get(TerminusDB.Config.t(), [get_opt()]) :: {:ok, term()} | {:error, TerminusDB.Error.t()}
Retrieves documents from the database.
With :id, returns a single document. Without :id, returns all documents
(or those of a :type). By default TerminusDB returns concatenated JSON; pass
as_list: true to get a JSON array decoded into a list of maps.
Options
:id— retrieve a specific document by ID.:type— retrieve documents of a specific type.:graph_type—:instance(default) or:schema.:skip— number of documents to skip (default0).:count— max number of documents to return.:as_list— request a JSON array instead of concatenated JSON.:unfold— join referenced documents (defaulttrue).:minimized— minify output (defaulttrue).:compress_ids— compress IDs using prefixes (defaulttrue).:organization— overridesconfig.organization.
Examples
Get a single document by ID:
iex> config = TerminusDB.Config.new(
...> endpoint: "http://localhost:6363",
...> adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"@id" => "Person/Alice", "name" => "Alice"})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> {:ok, person} = TerminusDB.Document.get(config, id: "Person/Alice", as_list: false)
iex> person["name"]
"Alice"Get all documents of a type:
iex> config = TerminusDB.Config.new(
...> endpoint: "http://localhost:6363",
...> adapter: fn req -> {req, Req.Response.new(status: 200, body: [%{"@id" => "Person/Alice"}, %{"@id" => "Person/Bob"}])} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> {:ok, docs} = TerminusDB.Document.get(config, type: "Person", as_list: true)
iex> length(docs)
2
@spec get!(TerminusDB.Config.t(), [get_opt()]) :: term()
Retrieves documents, or raises TerminusDB.Error.
Examples
iex> config = TerminusDB.Config.new(
...> endpoint: "http://localhost:6363",
...> adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"@id" => "Person/Alice"})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> TerminusDB.Document.get!(config, id: "Person/Alice")
%{"@id" => "Person/Alice"}
@spec insert(TerminusDB.Config.t(), map() | [map()], [insert_opt()]) :: {:ok, term()} | {:error, TerminusDB.Error.t()}
Inserts one or more documents into the database.
document can be a single map or a list of maps. The response body from
TerminusDB (the inserted document IDs) is returned.
Options
:author— commit author (required by the API).:message— commit message (required by the API).:graph_type—:instance(default) or:schema.:full_replace— iftrue, delete all existing documents before inserting.:raw_json— iftrue, insert as untypedsys:JSONDocument(no schema check).:organization— overridesconfig.organization.
Examples
iex> config = TerminusDB.Config.new(
...> endpoint: "http://localhost:6363",
...> adapter: fn req ->
...> {req, Req.Response.new(status: 200, body: [%{"@id" => "Person/Alice"}])}
...> end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> {:ok, ids} = TerminusDB.Document.insert(config,
...> %{"@type" => "Person", "name" => "Alice"},
...> author: "admin", message: "add Alice"
...> )
iex> ids
[%{"@id" => "Person/Alice"}]Inserting a list of documents:
iex> config = TerminusDB.Config.new(
...> endpoint: "http://localhost:6363",
...> adapter: fn req -> {req, Req.Response.new(status: 200, body: [%{"@id" => "Person/Alice"}, %{"@id" => "Person/Bob"}])} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> {:ok, ids} = TerminusDB.Document.insert(config, [
...> %{"@type" => "Person", "name" => "Alice"},
...> %{"@type" => "Person", "name" => "Bob"}
...> ], author: "admin", message: "add people")
iex> length(ids)
2
@spec insert!(TerminusDB.Config.t(), map() | [map()], [insert_opt()]) :: term()
Inserts documents, returning the response body or raising TerminusDB.Error.
Examples
iex> config = TerminusDB.Config.new(
...> endpoint: "http://localhost:6363",
...> adapter: fn req -> {req, Req.Response.new(status: 200, body: [%{"@id" => "Person/Alice"}])} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> TerminusDB.Document.insert!(config, %{"@type" => "Person", "name" => "Alice"},
...> author: "admin", message: "add"
...> )
[%{"@id" => "Person/Alice"}]
@spec query(TerminusDB.Config.t(), map(), [query_opt()]) :: {:ok, term()} | {:error, TerminusDB.Error.t()}
Queries documents by a template.
template is a map describing the shape of documents to match, e.g.
%{"@type" => "Person", "age" => 30}. TerminusDB returns all documents that
match the template.
Options
:graph_type—:instance(default) or:schema.:skip,:count— pagination.:as_list— return a JSON array.:organization— overridesconfig.organization.
Examples
iex> config = TerminusDB.Config.new(
...> endpoint: "http://localhost:6363",
...> adapter: fn req -> {req, Req.Response.new(status: 200, body: [%{"@type" => "Person", "name" => "Alice", "age" => 30}])} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> {:ok, matches} = TerminusDB.Document.query(config, %{"@type" => "Person", "age" => 30})
iex> hd(matches)["name"]
"Alice"
@spec query!(TerminusDB.Config.t(), map(), [query_opt()]) :: term()
Queries documents by template, or raises TerminusDB.Error.
Examples
iex> config = TerminusDB.Config.new(
...> endpoint: "http://localhost:6363",
...> adapter: fn req -> {req, Req.Response.new(status: 200, body: [%{"name" => "Alice"}])} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> TerminusDB.Document.query!(config, %{"name" => "Alice"})
[%{"name" => "Alice"}]
@spec replace(TerminusDB.Config.t(), map() | [map()], [update_opt()]) :: {:ok, term()} | {:error, TerminusDB.Error.t()}
Replaces one or more existing documents.
If a document does not exist, an error is returned unless create: true is
set, in which case it is inserted.
Options
:author,:message— commit metadata (required by the API).:graph_type—:instance(default) or:schema.:create— insert if the document does not exist (defaultfalse).:raw_json— treat as untyped JSON (defaultfalse).:organization— overridesconfig.organization.
Examples
iex> config = TerminusDB.Config.new(
...> endpoint: "http://localhost:6363",
...> adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"@id" => "Person/Alice", "name" => "Alicia"})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> {:ok, updated} = TerminusDB.Document.replace(config,
...> %{"@id" => "Person/Alice", "name" => "Alicia"},
...> author: "admin", message: "rename Alice"
...> )
iex> updated["name"]
"Alicia"
@spec replace!(TerminusDB.Config.t(), map() | [map()], [update_opt()]) :: term()
Replaces documents, or raises TerminusDB.Error.
Examples
iex> config = TerminusDB.Config.new(
...> endpoint: "http://localhost:6363",
...> adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"@id" => "Person/Alice"})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> TerminusDB.Document.replace!(config, %{"@id" => "Person/Alice", "name" => "Alicia"},
...> author: "admin", message: "rename"
...> )
%{"@id" => "Person/Alice"}
@spec stream(TerminusDB.Config.t(), [get_opt()]) :: Enumerable.t()
Returns a Stream of documents, decoded incrementally from the response.
Uses Req's response streaming (into: :self) and the concatenated-JSON
splitter in TerminusDB.Streaming to yield documents one at a time with
constant memory. Useful for large result sets.
Options
Accepts the same options as get/2 (:type, :graph_type, :skip,
:count, etc.).
Examples
# Stream all Person documents and process one at a time:
TerminusDB.Document.stream(config, type: "Person")
|> Stream.each(&IO.inspect/1)
|> Stream.run()