ExeQute.QError (exe_qute v0.1.2)

Copy Markdown

Parsed kdb+ backtrace returned when a server's .Q.trp error handler emits a ** Backtrace: string as the query response instead of raising a wire-level error.

ExeQute.query/2 and query/3 automatically detect such responses and return {:error, %ExeQute.QError{}} rather than wrapping the backtrace in an :ok tuple.

The struct keeps the raw backtrace text, a list of parsed frames, and — if the server emits one — an :message containing the error text (e.g. "hop. OS reports: Connection refused"). Stock kdb+ gateways that only emit a backtrace leave :message as nil; gateways patched to include the error inline as ** Backtrace: <error>\n [N] ... populate it.

inspect/1 renders the raw backtrace with line breaks preserved (so it shows readably in IEx), and to_string/1 returns the same text for use with IO.puts/1.

Summary

Functions

Returns true if value is a kdb+ backtrace string.

Converts a Connection.query response tuple, replacing any backtrace string (whether returned via :ok or raised as an :error) with a {:error, %ExeQute.QError{}} tuple.

Parses a raw kdb+ backtrace string into an ExeQute.QError struct.

Wraps a q query string in a server-side error trap.

Unwraps a response previously wrapped with trap/1.

Types

frame()

@type frame() :: %{
  level: non_neg_integer(),
  code: String.t(),
  file: String.t() | nil,
  line: pos_integer() | nil,
  function: String.t() | nil
}

t()

@type t() :: %ExeQute.QError{
  frames: [frame()],
  message: String.t() | nil,
  raw: String.t()
}

Functions

backtrace?(arg1)

@spec backtrace?(term()) :: boolean()

Returns true if value is a kdb+ backtrace string.

from_response(other)

@spec from_response({:ok, term()} | {:error, term()}) ::
  {:ok, term()} | {:error, term()}

Converts a Connection.query response tuple, replacing any backtrace string (whether returned via :ok or raised as an :error) with a {:error, %ExeQute.QError{}} tuple.

Responses that don't carry a backtrace are passed through unchanged.

Examples

iex> ExeQute.QError.from_response({:ok, [1, 2, 3]})
{:ok, [1, 2, 3]}

iex> ExeQute.QError.from_response({:error, :timeout})
{:error, :timeout}

iex> {:error, %ExeQute.QError{}} =
...>   ExeQute.QError.from_response({:error, "** Backtrace:  [0]  (.Q.trp)"})

parse(raw)

@spec parse(String.t()) :: {:ok, t()} | :error

Parses a raw kdb+ backtrace string into an ExeQute.QError struct.

Returns :error if raw does not begin with the ** Backtrace: marker.

Example

iex> {:ok, %ExeQute.QError{frames: [%{level: 0} | _]}} =
...>   ExeQute.QError.parse("** Backtrace:  [0]  (.Q.trp)\n")

trap(query)

@spec trap(String.t()) :: String.t()

Wraps a q query string in a server-side error trap.

Use together with untrap/1 to capture kdb+ errors directly, even on gateways that swallow them inside .Q.trp. The wrapper installs an @[...] form that fires inside the gateway's handler, so the error string reaches the client untouched.

Examples

query = ExeQute.QError.trap("select from trade")
{:ok, conn} = ExeQute.connect(host: "kdb", port: 5010)
ExeQute.query(conn, query) |> ExeQute.QError.untrap()
#=> {:ok, [...]}   on success
#=> {:error, "..."} on q-side error, with the original error string

untrap(other)

@spec untrap({:ok, term()} | {:error, term()}) :: {:ok, term()} | {:error, term()}

Unwraps a response previously wrapped with trap/1.

Tagged-success responses become {:ok, value}; tagged-error responses become {:error, error_string}. Anything else is passed through unchanged, so untrap/1 is safe to chain after ExeQute.query/2 even if the trap wrapping ended up bypassed (e.g. by an outer gateway).