Arcadic.Function (Arcadic v0.7.0)

Copy Markdown View Source

ArcadeDB user-defined functions — tenant-blind DEFINE FUNCTION / DELETE FUNCTION DDL, parallel to Arcadic.FullText/Arcadic.Geo.

A function name is a dotted library.fn reference validated per segment (String.split(name, "."), each segment through Arcadic.Identifier — a bare Identifier.validate is wrong, it rejects .; a degenerate lib..fn yields an empty segment that fails closed). The body is embedded as a "..." DDL literal and admitted only through an internal positive-allowlist guard — the sole breakout byte ", the backslash, and control/line bytes are rejected value-free before any wire call. ArcadeDB's "..." body literal has no escape (\", doubled "", single-quote delimiter, and newlines all parse-error), so the single-line/single-quoted-body limit is a substrate constraint, not a narrowing — ArcadeDB's own e2e tests use only single-line, single-quoted-JS bodies.

Calling a defined function

There is no call wrapper here (a call wrapper is a query template — a charter non-goal). Invoke a defined function inside an ordinary Arcadic.query/4 via the backtick idiom:

Arcadic.query(conn, "SELECT `math.sum`(:a, :b) AS total", %{"a" => 1, "b" => 2},
  language: "sql")

The library/function name is interpolated (behind the per-segment allowlist); the arguments ride the params map, never the statement.

Summary

Functions

Defines a function name (a dotted library.fn) with a body literal and opts

Defines a function, raising on error.

Deletes a function name (a dotted library.fn); idempotent server-side once the library exists (deleting from a never-defined library errors). Value-free on a bad name.

Deletes a function, raising on error.

Functions

define(conn, name, body, opts \\ [])

@spec define(Arcadic.Conn.t(), String.t(), String.t(), keyword()) ::
  :ok | {:error, atom() | Exception.t()}

Defines a function name (a dotted library.fn) with a body literal and opts:

  • :params — a list of parameter-name atoms/strings, each Identifier-validated (default []).
  • :language:js (default) | :sql | :cypher.

A single trailing opts keyword list (like every sibling DDL helper), so there is no positional-argument ambiguity:

define(conn, "math.sum", "return a + b", params: [:a, :b], language: :sql)
define(conn, "lib.fn", "return 1")                      # no params, js
define(conn, "lib.fn", "return 1", language: :sql)      # opts, no params

Emits DEFINE FUNCTION lib.fn "body" [PARAMETERS [a, b]] LANGUAGE <lang>. Value-free on a bad name (:invalid_identifier), a bad param (:invalid_identifier), an unencodable body (:unencodable_body), or an unknown language (:invalid_language) — none echo the offending value. A non-binary body is a caller-contract violation and raises ArgumentError value-free.

define!(conn, name, body, opts \\ [])

@spec define!(Arcadic.Conn.t(), String.t(), String.t(), keyword()) :: :ok

Defines a function, raising on error.

delete(conn, name)

@spec delete(Arcadic.Conn.t(), String.t()) :: :ok | {:error, atom() | Exception.t()}

Deletes a function name (a dotted library.fn); idempotent server-side once the library exists (deleting from a never-defined library errors). Value-free on a bad name.

delete!(conn, name)

@spec delete!(Arcadic.Conn.t(), String.t()) :: :ok

Deletes a function, raising on error.