Parameterized Cypher query builder for Apache AGE.
AGE requires queries in the form:
SELECT * FROM ag_catalog.cypher('graph_name', $$ CYPHER $$, $1) AS (v agtype)Where $1 is a JSON-encoded map of parameters.
Summary
Functions
Builds a parameterized Cypher query wrapped for AGE execution.
Builds a parameterized Cypher query with custom return type columns.
Builds a static Cypher query (no parameters).
Builds a static Cypher query with custom return type columns.
build/4 wrapped so a non-JSON-encodable param value fails closed as
{:error, :params_not_json_encodable} instead of raising: Jason.EncodeError
embeds the raw bytes in its message, and Protocol.UndefinedError (a struct
with no Jason.Encoder impl nested in a param) inspects the value into its
message. This is the ONE home for that classifier — every executing caller
(AshAge.DataLayer.build_and_query, AshAge.Changes.EdgeCypher.safe_build,
AshAge.cypher/5, the traverse path) routes through it, so the redaction
logic cannot drift between copies. Identifier/$$-breakout ArgumentErrors
propagate unchanged: they are value-free by design and must stay loud.
Functions
Builds a parameterized Cypher query wrapped for AGE execution.
Returns {sql_string, [json_params]} suitable for Ecto.Adapters.SQL.query/3.
Builds a parameterized Cypher query with custom return type columns.
return_types is a keyword list like [{:v, :agtype}, {:e, :agtype}].
Builds a static Cypher query (no parameters).
Omits the params argument entirely — AGE rejects NULL as the third argument.
Builds a static Cypher query with custom return type columns.
@spec safe_build(atom() | String.t(), String.t(), map(), keyword()) :: {:ok, {String.t(), list()}} | {:error, :params_not_json_encodable}
build/4 wrapped so a non-JSON-encodable param value fails closed as
{:error, :params_not_json_encodable} instead of raising: Jason.EncodeError
embeds the raw bytes in its message, and Protocol.UndefinedError (a struct
with no Jason.Encoder impl nested in a param) inspects the value into its
message. This is the ONE home for that classifier — every executing caller
(AshAge.DataLayer.build_and_query, AshAge.Changes.EdgeCypher.safe_build,
AshAge.cypher/5, the traverse path) routes through it, so the redaction
logic cannot drift between copies. Identifier/$$-breakout ArgumentErrors
propagate unchanged: they are value-free by design and must stay loud.