TerminusDB.Document (terminusdb_ex v0.3.3)

Copy Markdown View Source

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.

Returns a Stream of documents, decoded incrementally from the response.

Types

delete_opt()

@type delete_opt() ::
  {:author, String.t()}
  | {:message, String.t()}
  | {:graph_type, graph_type()}
  | {:id, String.t()}
  | {:nuke, boolean()}
  | {:organization, String.t()}

get_opt()

@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()}

graph_type()

@type graph_type() :: :instance | :schema

insert_opt()

@type insert_opt() ::
  {:author, String.t()}
  | {:message, String.t()}
  | {:graph_type, graph_type()}
  | {:full_replace, boolean()}
  | {:raw_json, boolean()}
  | {:organization, String.t()}

query_opt()

@type query_opt() ::
  {:graph_type, graph_type()}
  | {:skip, non_neg_integer()}
  | {:count, pos_integer()}
  | {:as_list, boolean()}
  | {:organization, String.t()}

update_opt()

@type update_opt() ::
  {:author, String.t()}
  | {:message, String.t()}
  | {:graph_type, graph_type()}
  | {:create, boolean()}
  | {:raw_json, boolean()}
  | {:organization, String.t()}

Functions

delete(config, opts \\ [])

@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 — overrides config.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"

delete!(config, opts \\ [])

@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"}

get(config, opts \\ [])

@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 (default 0).
  • :count — max number of documents to return.
  • :as_list — request a JSON array instead of concatenated JSON.
  • :unfold — join referenced documents (default true).
  • :minimized — minify output (default true).
  • :compress_ids — compress IDs using prefixes (default true).
  • :organization — overrides config.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

get!(config, opts \\ [])

@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"}

insert(config, document, opts \\ [])

@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 — if true, delete all existing documents before inserting.
  • :raw_json — if true, insert as untyped sys:JSONDocument (no schema check).
  • :organization — overrides config.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

insert!(config, document, opts \\ [])

@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"}]

query(config, template, opts \\ [])

@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 — overrides config.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"

query!(config, template, opts \\ [])

@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"}]

replace(config, document, opts \\ [])

@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 (default false).
  • :raw_json — treat as untyped JSON (default false).
  • :organization — overrides config.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"

replace!(config, document, opts \\ [])

@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"}

stream(config, opts \\ [])

@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()