Public API for querying NebulaGraph.
The recommended pattern — define a graph module
Borrowing from Ecto's Repo pattern, define a graph module in your application:
# lib/my_app/graph.ex
defmodule MyApp.Graph do
use NebulaGraphEx.Graph, otp_app: :my_app
endPut connection options in config:
# config/config.exs
config :my_app, MyApp.Graph,
hostname: "localhost",
port: 9669,
username: "root",
space: "my_graph",
pool_size: 10Override secrets at runtime (recommended for passwords):
# config/runtime.exs
import Config
config :my_app, MyApp.Graph,
hostname: System.fetch_env!("NEBULA_HOST"),
password: fn -> System.fetch_env!("NEBULA_PASS") endAdd to your supervision tree — that's it:
# lib/my_app/application.ex
def start(_type, _args) do
children = [MyApp.Graph]
Supervisor.start_link(children, strategy: :one_for_one)
endNow query without ever referencing a PID or pool name:
MyApp.Graph.query("MATCH (v:Player) RETURN v.name, v.age LIMIT 5")
MyApp.Graph.query!("RETURN 1+1 AS n") |> ResultSet.first!() |> Record.get!("n")Direct pool usage (without use)
When you need multiple pools, or want full control, start NebulaGraphEx.Graph
directly in your supervision tree:
children = [
{NebulaGraphEx.Graph,
name: MyApp.Graph,
hostname: "localhost",
port: 9669,
space: "my_graph",
pool_size: 10}
]Then pass the name (or PID) to every call:
NebulaGraphEx.Graph.query(MyApp.Graph, "MATCH (v:Player) RETURN v LIMIT 5")Parameterised queries
Always use parameters for user-supplied values — never interpolate into the statement string.
MyApp.Graph.query(
"MATCH (v:Player{name: $name}) RETURN v.age AS age",
%{"name" => "Tim Duncan"}
)Per-query options
Any pool option can be overridden for a single call:
MyApp.Graph.query(stmt, %{},
space: "other_space",
timeout: 30_000,
decode_mapper: &NebulaGraphEx.Record.to_map/1
)Bang variants
query!/3 raises NebulaGraphEx.Error on failure instead of returning
{:error, error}.
Connection status
Use status/1 or status/2 when you want a health check for a pool. It
verifies that the pool process is alive and, by default, executes RETURN 1
to confirm the connection can run a query.
{:ok, status} = MyApp.Graph.status()
status.connected?
#=> trueSee NebulaGraphEx.Options for the full option reference.
Summary
Functions
Injects a graph module into the calling module.
Executes a nGQL statement and applies fun to every %Record{} row,
returning a list of results.
Executes a nGQL statement and returns {:ok, %ResultSet{}} or
{:error, %NebulaGraphEx.Error{}}.
Like query/4 but raises NebulaGraphEx.Error on failure.
Starts a supervised connection pool and links it to the calling process.
Checks whether a pool is alive and able to execute a simple query.
Issues USE <space> on the given connection, switching the active graph
space for that connection's current session.
Functions
Injects a graph module into the calling module.
Options
:otp_app— required. The OTP application atom used to look up config viaApplication.get_env(otp_app, __MODULE__, []).
Generated API
When you use NebulaGraphEx.Graph, otp_app: :my_app, the following functions
are injected into your module, all scoped to the pool that the module itself
manages:
start_link/1— starts the pool (used by your supervision tree).child_spec/1— makes the module a valid child spec entry.query/1,2,3—query(statement, params \\ %{}, opts \\ []).query!/1,2,3— raises on failure.map/2,3,4—map(statement, params \\ %{}, opts \\ [], fun).status/0,1— checks whether the pool is alive and can run a simple query.use_space/1,2—use_space(space, opts \\ []).
All functions are overridable so you can add instrumentation or defaults.
@spec map( DBConnection.conn(), String.t(), map(), keyword(), (NebulaGraphEx.ResultSet.t() -> term()) ) :: {:ok, [term()]} | {:error, NebulaGraphEx.Error.t()}
Executes a nGQL statement and applies fun to every %Record{} row,
returning a list of results.
Equivalent to:
{:ok, rs} = query(conn, stmt, params, opts)
Enum.map(ResultSet.rows(rs), fun)Example
NebulaGraphEx.Graph.map(MyApp.Graph, "MATCH (v:Player) RETURN v.name", fn record ->
record |> NebulaGraphEx.Record.get!("v.name")
end)
#=> ["Tim Duncan", "LeBron James", ...]
@spec query(DBConnection.conn(), String.t(), map(), keyword()) :: {:ok, NebulaGraphEx.ResultSet.t()} | {:error, NebulaGraphEx.Error.t()}
Executes a nGQL statement and returns {:ok, %ResultSet{}} or
{:error, %NebulaGraphEx.Error{}}.
Arguments
conn— pool name or PID fromstart_link/1. When using theusemacro, this is the module itself and is passed automatically.statement— nGQL string.params— map of parameter bindings. Default:%{}.opts— per-query option overrides (seeNebulaGraphEx.Options). Default:[].
Examples
{:ok, rs} = NebulaGraphEx.Graph.query(MyApp.Graph, "RETURN 1+1 AS sum")
rs |> NebulaGraphEx.ResultSet.first!() |> NebulaGraphEx.Record.get!("sum")
#=> 2
{:error, %NebulaGraphEx.Error{code: :e_syntax_error}} =
NebulaGraphEx.Graph.query(MyApp.Graph, "THIS IS NOT VALID nGQL")
@spec query!(DBConnection.conn(), String.t(), map(), keyword()) :: NebulaGraphEx.ResultSet.t()
Like query/4 but raises NebulaGraphEx.Error on failure.
Example
NebulaGraphEx.Graph.query!(MyApp.Graph, "MATCH (v:Player) RETURN count(v) AS n")
|> NebulaGraphEx.ResultSet.first!()
|> NebulaGraphEx.Record.get!("n")
#=> 51
Starts a supervised connection pool and links it to the calling process.
Typically called via a module that uses NebulaGraphEx.Graph. When using the
pool directly, pass a :name so callers can reference it by atom:
children = [
{NebulaGraphEx.Graph,
name: MyApp.Graph,
hostname: System.fetch_env!("NEBULA_HOST"),
password: fn -> System.fetch_env!("NEBULA_PASS") end,
space: "my_graph",
pool_size: 20}
]See NebulaGraphEx.Options for the full option reference.
@spec status( DBConnection.conn(), keyword() ) :: {:ok, %{ pid: pid(), connected?: true, queryable?: boolean(), probe_statement: String.t() | nil }} | {:error, %{ pid: pid() | nil, connected?: boolean(), queryable?: false, probe_statement: String.t() | nil, error: term(), error_details: map() }}
Checks whether a pool is alive and able to execute a simple query.
This is an active health check. It first resolves the pool process and then,
unless disabled, executes RETURN 1 AS status to verify the checked-out
connection can talk to NebulaGraph successfully.
Options
:probe_statement— query used for the health check. Default:"RETURN 1 AS status".:probe_query— whether to run the health-check query. Default:true.:query_opts— options passed to the probe query. Default:[].
Return value
On success:
{:ok,
%{
pid: #PID<0.123.0>,
connected?: true,
queryable?: true,
probe_statement: "RETURN 1 AS status"
}}If the pool process is missing:
{:error,
%{
pid: nil,
connected?: false,
queryable?: false,
error: :not_running,
error_details: %{reason: :not_running, message: "pool process is not running"}
}}If the pool exists but the probe query fails:
{:error,
%{
pid: #PID<0.123.0>,
connected?: true,
queryable?: false,
probe_statement: "RETURN 1 AS status",
error: %NebulaGraphEx.Error{},
error_details: %{code: :e_syntax_error, message: "...", category: :query}
}}
@spec use_space(DBConnection.conn(), String.t(), keyword()) :: {:ok, NebulaGraphEx.ResultSet.t()} | {:error, NebulaGraphEx.Error.t()}
Issues USE <space> on the given connection, switching the active graph
space for that connection's current session.
This is only useful when you hold a checked-out connection directly. With
the pool, prefer passing the :space option to query/4 instead.