TerminusDB.WOQL (terminusdb_ex v0.3.0)

Copy Markdown View Source

A functional builder DSL for WOQL (Web Object Query Language).

WOQL is TerminusDB's Datalog-based query language. This module provides a small but solid set of composable functions that build a TerminusDB.WOQL.Query struct, which can be serialized to the JSON-LD wire format via to_jsonld/1 and executed via TerminusDB.WOQL.execute/3.

This is WOQL DSL v0.1 - a focused subset covering the most common patterns. Future releases will extend the vocabulary.

Design

The DSL is purely functional (no macros). Each function returns a %WOQL.Query{} struct and composes by nesting, mirroring the recommended functional WOQL style. Variables are plain strings using the v:Name convention.

Supported vocabulary (v0.1)

FunctionWOQL JSON-LD type
triple/3Triple
and_/1And
or_/1Or
eq/2Equals
select/2Select
read_document/2ReadDocument
type_of/2TypeOf

Quick start

import TerminusDB.WOQL

query =
  and_([
    triple("v:Person", "rdf:type", "@schema:Person"),
    triple("v:Person", "name", "v:Name")
  ])

jsonld = TerminusDB.WOQL.to_jsonld(query)

# Execute against a database
config = TerminusDB.Config.new(endpoint: "http://localhost:6363")
config = TerminusDB.Config.with_database(config, "mydb")
{:ok, result} = TerminusDB.WOQL.execute(config, query)

Summary

Functions

Builds an And conjunction of sub-queries.

Builds an Equals unification: left equals right.

Executes a WOQL query against the database scoped in config.

Executes a WOQL query, or raises TerminusDB.Error.

Deserializes a JSON-LD WOQL query back into a WOQL.Query struct.

Builds an Or disjunction of sub-queries.

Builds a ReadDocument that reads a document by ID into a variable.

Builds a Select that projects the given variables from a sub-query.

Serializes a WOQL.Query to the JSON-LD wire format expected by the /api/woql endpoint.

Builds a Triple pattern: subject, predicate, object.

Builds a TypeOf that unifies the type of a node with a variable.

Types

t()

@type t() :: %TerminusDB.WOQL{args: [term()], op: atom()}

value()

@type value() :: String.t() | woql_var() | number() | boolean() | map()

woql_node()

@type woql_node() :: String.t() | woql_var()

woql_var()

@type woql_var() :: String.t()

Functions

and_(queries)

@spec and_([t()]) :: t()

Builds an And conjunction of sub-queries.

Examples

iex> q = TerminusDB.WOQL.and_([
...>   TerminusDB.WOQL.triple("v:S", "rdf:type", "v:T"),
...>   TerminusDB.WOQL.eq("v:T", "Person")
...> ])
iex> q.op
:and

eq(left, right)

@spec eq(value(), value()) :: t()

Builds an Equals unification: left equals right.

Examples

iex> q = TerminusDB.WOQL.eq("v:Name", "Alice")
iex> q.op
:eq

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

@spec execute(TerminusDB.Config.t(), t(), keyword()) ::
  {:ok, map()} | {:error, TerminusDB.Error.t()}

Executes a WOQL query against the database scoped in config.

Returns {:ok, result} where result is a map containing bindings (a list of maps, one per solution), or {:error, TerminusDB.Error.t()}.

Options

  • :author - commit author (for write queries).
  • :message - commit message (for write queries).
  • :all_witnesses - check for all errors (default false).
  • :organization - overrides config.organization.
  • :repo - overrides config.repo.
  • :branch - overrides config.branch.

Examples

iex> config = TerminusDB.Config.new(
...>   endpoint: "http://localhost:6363",
...>   adapter: fn req ->
...>     {req, Req.Response.new(status: 200, body: %{"bindings" => [%{"Name" => "Alice"}]})}
...>   end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> q = TerminusDB.WOQL.select(["v:Name"],
...>   TerminusDB.WOQL.and_([TerminusDB.WOQL.triple("v:P", "name", "v:Name")])
...> )
iex> {:ok, result} = TerminusDB.WOQL.execute(config, q)
iex> result["bindings"]
[%{"Name" => "Alice"}]

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

@spec execute!(TerminusDB.Config.t(), t(), keyword()) :: map()

Executes a WOQL query, or raises TerminusDB.Error.

Examples

iex> config = TerminusDB.Config.new(
...>   endpoint: "http://localhost:6363",
...>   adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"bindings" => []})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> q = TerminusDB.WOQL.triple("v:S", "p", "v:O")
iex> TerminusDB.WOQL.execute!(config, q)
%{"bindings" => []}

from_jsonld(jsonld)

@spec from_jsonld(map()) :: t()

Deserializes a JSON-LD WOQL query back into a WOQL.Query struct.

Examples

iex> jsonld = %{"@type" => "Triple", "subject" => %{"@type" => "NodeValue", "variable" => "S"}, "predicate" => %{"@type" => "NodeValue", "node" => "name"}, "object" => %{"@type" => "DataValue", "variable" => "N"}}
iex> q = TerminusDB.WOQL.from_jsonld(jsonld)
iex> q.op
:triple

or_(queries)

@spec or_([t()]) :: t()

Builds an Or disjunction of sub-queries.

Examples

iex> q = TerminusDB.WOQL.or_([
...>   TerminusDB.WOQL.eq("v:Name", "Alice"),
...>   TerminusDB.WOQL.eq("v:Name", "Bob")
...> ])
iex> q.op
:or

read_document(id, var)

@spec read_document(String.t(), woql_var()) :: t()

Builds a ReadDocument that reads a document by ID into a variable.

Examples

iex> q = TerminusDB.WOQL.read_document("Person/Alice", "v:Doc")
iex> q.op
:read_document

select(vars, query)

@spec select([woql_var()], t()) :: t()

Builds a Select that projects the given variables from a sub-query.

vars is a list of variable names (e.g. ["v:Name", "v:Person"]).

Examples

iex> q = TerminusDB.WOQL.select(["v:Name"],
...>   TerminusDB.WOQL.and_([
...>     TerminusDB.WOQL.triple("v:Person", "name", "v:Name")
...>   ])
...> )
iex> q.op
:select

to_jsonld(query)

@spec to_jsonld(t()) :: map()

Serializes a WOQL.Query to the JSON-LD wire format expected by the /api/woql endpoint.

Examples

iex> q = TerminusDB.WOQL.triple("v:S", "name", "v:N")
iex> jsonld = TerminusDB.WOQL.to_jsonld(q)
iex> jsonld["@type"]
"Triple"

triple(subject, predicate, object)

@spec triple(woql_node(), woql_node(), value()) :: t()

Builds a Triple pattern: subject, predicate, object.

Any argument can be a variable ("v:Name") or a constant.

Examples

iex> q = TerminusDB.WOQL.triple("v:Person", "name", "v:Name")
iex> q.op
:triple

type_of(node, var)

@spec type_of(woql_node(), woql_var()) :: t()

Builds a TypeOf that unifies the type of a node with a variable.

Examples

iex> q = TerminusDB.WOQL.type_of("v:Person", "v:Type")
iex> q.op
:type_of