TypeDB.GRPC (TypeDB.GRPC v0.1.0)

Copy Markdown View Source

TypeDB over gRPC — the entry point.

Shaped after TypeDB, the sibling package's facade, so that the difference between the two transports shows up where it is real rather than in the spelling of every call:

{:ok, _pid} = TypeDB.GRPC.start_link(
  name: :graph,
  address: "127.0.0.1:1729",
  username: "admin",
  password: "password"
)

{:ok, answer} = TypeDB.GRPC.query(:graph, "social", "match $p isa person;",
  transaction_type: :read)

Answers decode into TypeDB.Concept structs and failures arrive as %TypeDB.Error{} — the sibling's, not copies — so code above the data-access layer does not know which transport it is on.

Where the two genuinely differ

  • query/4 is not a one-shot. The protocol has no query outside a transaction, so this opens one, runs the query and finishes it. That is what the HTTP API does server-side for its one-shot too, but here the round trips are yours and a request-serving workload pays for them — measured, 200 independent point reads cost 249 ms here against 213 ms over HTTP.
  • Answers have no ceiling. There is no answer_count_limit, nothing truncates, and TypeDB.Answer.truncated?/1 is always false.
  • Reads can stream. stream/4 hands back an Enumerable that pulls from the server as it is consumed, so an answer larger than memory is a read rather than a problem.
  • Writes go one at a time inside a transaction, or through TypeDB.GRPC.Transaction.execute_many/3 when their answers are not wanted. See that function for why.

Summary

Functions

Creates a database. A no-op for one that already exists.

Creates a database, raising on failure.

Creates a database unless it is already there.

Creates a database unless it is there, raising on failure.

Every database on the server.

Every database, raising on failure.

Deletes a database and everything in it.

Deletes a database, raising on failure.

Writes a database's schema and data to two files.

Exports a database to two files, raising on failure.

Whether the server is reachable and answering.

Server reachability, raising on failure.

Imports a database from two files, raising on failure.

Runs one query in a transaction of its own.

Runs one query, raising TypeDB.Error on failure.

Whether conn can serve a call.

Starts a connection. See TypeDB.GRPC.Config.new/1 for the options.

Reads a query as a Stream, pulling from the server as it is consumed.

Runs fun inside one transaction, committing on success.

The server's distribution and version.

The server's version, raising on failure.

Types

conn()

@type conn() :: TypeDB.GRPC.Connection.t()

Functions

create_database(conn, name, opts \\ [])

@spec create_database(conn(), String.t(), keyword()) ::
  :ok | {:error, TypeDB.Error.t()}

Creates a database. A no-op for one that already exists.

create_database!(conn, name, opts \\ [])

@spec create_database!(term(), term(), term()) :: :ok

Creates a database, raising on failure.

create_database_if_not_exists(conn, name, opts \\ [])

@spec create_database_if_not_exists(conn(), String.t(), keyword()) ::
  :ok | {:error, TypeDB.Error.t()}

Creates a database unless it is already there.

create_database_if_not_exists!(conn, name, opts \\ [])

@spec create_database_if_not_exists!(term(), term(), term()) :: :ok

Creates a database unless it is there, raising on failure.

databases(conn, opts \\ [])

@spec databases(
  conn(),
  keyword()
) :: {:ok, [String.t()]} | {:error, TypeDB.Error.t()}

Every database on the server.

databases!(conn, opts \\ [])

@spec databases!(term(), term()) :: [String.t()]

Every database, raising on failure.

delete_database(conn, name, opts \\ [])

@spec delete_database(conn(), String.t(), keyword()) ::
  :ok | {:error, TypeDB.Error.t()}

Deletes a database and everything in it.

delete_database!(conn, name, opts \\ [])

@spec delete_database!(term(), term(), term()) :: :ok

Deletes a database, raising on failure.

export_database(conn, name, schema_path, data_path, opts \\ [])

@spec export_database(conn(), String.t(), Path.t(), Path.t(), keyword()) ::
  :ok | {:error, TypeDB.Error.t()}

Writes a database's schema and data to two files.

The capability the HTTP API does not have at all — see TypeDB.GRPC.Database.export_to_files/5.

export_database!(conn, name, schema_path, data_path, opts \\ [])

@spec export_database!(term(), term(), term(), term(), term()) :: :ok

Exports a database to two files, raising on failure.

health(conn, opts \\ [])

@spec health(
  conn(),
  keyword()
) :: :ok | {:error, TypeDB.Error.t()}

Whether the server is reachable and answering.

health!(conn, opts \\ [])

@spec health!(term(), term()) :: :ok

Server reachability, raising on failure.

import_database(conn, name, schema_path, data_path, opts \\ [])

@spec import_database(conn(), String.t(), Path.t(), Path.t(), keyword()) ::
  :ok | {:error, TypeDB.Error.t()}

Creates a database from the two files export_database/5 wrote.

import_database!(conn, name, schema_path, data_path, opts \\ [])

@spec import_database!(term(), term(), term(), term(), term()) :: :ok

Imports a database from two files, raising on failure.

query(conn, database, query, opts \\ [])

@spec query(conn(), String.t(), String.t(), keyword()) ::
  {:ok, TypeDB.Answer.t()} | {:error, TypeDB.Error.t()}

Runs one query in a transaction of its own.

Options

  • :transaction_type:read, :write or :schema. Defaults to :schema, matching TypeDB.query/4: it is the only type that accepts every kind of query, and it is also the one that takes the exclusive schema lock, so pass the type you mean.
  • :given_rows — rows for TypeQL's given stage
  • :timeout — how long to wait
  • :transaction_timeout_millis, :schema_lock_acquire_timeout_millis

A :write or :schema query commits; a :read closes.

query!(conn, database, query, opts \\ [])

@spec query!(conn(), String.t(), String.t(), keyword()) :: TypeDB.Answer.t()

Runs one query, raising TypeDB.Error on failure.

running?(conn)

@spec running?(conn()) :: boolean()

Whether conn can serve a call.

Answers about this node's connection process, not about TypeDB — the same caveat as TypeDB.running?/1. health/2 is the question about the server.

start_link(opts)

@spec start_link(keyword()) :: GenServer.on_start()

Starts a connection. See TypeDB.GRPC.Config.new/1 for the options.

stop(conn, reason \\ :normal, timeout \\ :infinity)

@spec stop(conn() | pid(), term(), timeout()) :: :ok

Stops a connection.

stream(conn, database, query, opts \\ [])

@spec stream(conn(), String.t(), String.t(), keyword()) :: Enumerable.t()

Reads a query as a Stream, pulling from the server as it is consumed.

The thing this transport can do that the other cannot. The stream holds one batch at a time and asks TypeDB for the next only when the consumer wants it, so memory follows the batch rather than the answer:

TypeDB.GRPC.stream(conn, "social", "match $p isa person, has name $n; select $n;")
|> Stream.map(&TypeDB.ConceptRow.typed_value(&1, "n"))
|> Enum.each(&IO.puts/1)

The transaction lives for as long as the stream does and is closed when it ends, including when the consumer stops early — Enum.take/2 over a stream of ten million rows reads a batch, not ten million.

Reads only. :transaction_type defaults to :read here rather than to :schema, because a stream of a define is not a thing anybody wants.

transaction(conn, database, type, fun, opts \\ [])

@spec transaction(
  conn(),
  String.t(),
  TypeDB.GRPC.Transaction.type(),
  (TypeDB.GRPC.Transaction.t() -> result),
  keyword()
) :: result | {:error, TypeDB.Error.t()}
when result: term()

Runs fun inside one transaction, committing on success.

Commits when fun returns anything but {:error, _}; closes without committing on an error, a raise, a throw or an exit.

version(conn, opts \\ [])

@spec version(
  conn(),
  keyword()
) :: {:ok, map()} | {:error, TypeDB.Error.t()}

The server's distribution and version.

version!(conn, opts \\ [])

@spec version!(term(), term()) :: map()

The server's version, raising on failure.