API Reference AshArcadic v#0.1.0

Copy Markdown View Source

Modules

Ash Framework integration for ArcadeDB.

Pure aggregate Cypher builder + decoder for AshArcadic. Builds ONE parameterized statement per Ash.Query.Aggregate (each carries its own filter/field/uniq?/ include_nil?/default_value); RETURN uses SYNTHETIC aliases (agg<i>), never the caller name (Rule 1). Value-reading aggregates over non-summable/non-orderable/ sensitive (:binary) storage fail closed value-free — a correctness guard mirroring {:sort, :binary} AND a leak guard (a min/list over an encrypted-binary attr would order-by / return ciphertext into the result; §6.4). A list/first requesting include_nil?: true also fails closed value-free (ArcadeDB collect drops nulls; §6.5). Empty sets — and value-reading sets with no non-null field values — decode to the aggregate struct's own .default_value (spec §6.3).

Value serialization and flat-JSON-row decode for the ArcadeDB wire.

Ash change that persists a graph edge from the action's record to a destination named by an argument, after the vertex write, inside the action's transaction.

Ash change that removes a graph edge from the action's record to a destination named by an argument, after the vertex write, inside the action's transaction.

A host module that supplies the Arcadic.Conn a resource's data layer executes through — the repo analog for ash_postgres/ash_age. The host owns base_url, auth, transport, and pool; AshArcadic asks only for the handle.

Ash DataLayer for ArcadeDB — the "ash_postgres of ArcadeDB". Executes through the tenant-blind arcadic transport. Exposes an arcade do … end resource section and implements the Ash.DataLayer behaviour.

Introspection for the arcade do … end DSL section.

Build-blocking compile verifier: an edge's label or any properties key that is not a valid Arcadic.Identifier raises a Spark.Error.DslError (surfaced as a compiler diagnostic under --warnings-as-errors). Edge labels are interpolated into Cypher (MERGE (a)-[e:LABEL]->(b)) and property keys into SET e.<key>, so both are validated at declaration time.

Compile-verifier for :attribute multitenancy. Two fail-open holes turned into compile errors (AshArcadic has no rls_guc; those ash_age clauses are dropped — ArcadeDB has no row-level security)

Compile-verifier (build-blocking under --warnings-as-errors): a relationship's LOCAL join attribute must not be sensitive. A sensitive attribute is app-side-encrypted binary (ValidateSensitive R2); an encrypted-binary FK cannot be IN-joined — Slice-5 relationship loading builds dest.<fk> IN [<plaintext pks>], so a sensitive join key silently breaks loading and leaks via filter presence/absence. Fail closed, value-free (names the attribute atom only).

Compile-verifier for arcade do sensitive [...] end (build-blocking under --warnings-as-errors)

Compile-verifier: a primary-key attribute must not appear in arcade do skip [...] end. A skipped PK is never written as a property, so every update/destroy MATCH on the full primary key matches zero rows (perpetual StaleRecord) and reads decode a nil PK.

Compile-verifier for arcade do sparse_vector_index … end (build-blocking under --warnings-as-errors). A sparse index declares a (tokens, weights) attribute PAIR; BOTH attributes must be

Compile-verifier for arcade do vector_index … end (build-blocking under --warnings-as-errors). Each declared vector_index name must be

Edge configuration for an ArcadeDB relationship declared in an arcade do … end block. The %AshArcadic.Edge{} struct is the target of the edge DSL entity; AshArcadic.Changes.{CreateEdge,DestroyEdge} read it by name.

Error for failed create operations. Carries only resource + structural reason.

Error for failed queries/reads/destroys. Carries only query label + structural reason.

Error for a filter operation AshArcadic cannot push down to Cypher. Carries ONLY the operator/function module and the referenced field name — the filtered value is never captured, so neither the message nor a log line built from it leaks PII/secrets (AGENTS.md Rule 4).

Error for failed update operations. Carries only resource + structural reason.

Identifier validation for values AshArcadic interpolates into Cypher or a database name (labels, database names, sort/PK/attribute field names). The allowlist is single-sourced in Arcadic.Identifier (letter-first, ≤128) — the same guard the transport applies — so labels and DB names satisfy the URL-path and statement rules by construction. Never interpolate a VALUE; values ride params. A failure carries the invalid-SHAPE fact only, never the offending string (AGENTS.md Rules 1 & 4).

Bounded variable-length graph traversal as an Ash manual relationship.

Resolves the ArcadeDB database name for a :context-multitenant resource + tenant. The name reaches a URL path, so it must be a valid Arcadic.Identifier (letter-first, ≤128 bytes), injective (distinct tenants → distinct databases — a hard isolation invariant), and deterministic.

Read-action preparation that turns an Ash read into a vector search — dense kNN, sparse (learned-sparse / BM25-style) kNN, or hybrid fusion (dense/sparse/full-text arms). Attach it to a read action whose arguments carry the query data

Query structure for AshArcadic. Accumulates filters/sort/limit/offset; compiled to Cypher by to_cypher/1 (Plan 2). client/database/label come from the resource's arcade DSL; database is overridden per-tenant by set_tenant/3 for :context resources (Plan 2).

Translates an Ash value-expression (an expression calculation's body, or a compound operand of a filter/sort) into a parameterized Cypher SCALAR. Used by AshArcadic.Query.Filter (WHERE operands) and the sort path (ORDER BY) — NOT the load path (loaded calculations compute in Elixir, AshArcadic.DataLayer.run_query).

Translates an Ash.Filter expression into a parameterized Cypher WHERE fragment. Only operators ArcadeDB can push down are emitted; anything else returns {:error, %UnsupportedFilter{}} carrying operator/field only (never the value — AGENTS.md Rule 4).

Builds the Cypher SET clause for a query-scoped bulk write (update_query) and for the atomic surface of create/upsert, from an Ash changeset's atomic + static changes. Pure — no transport.

Sparse (learned-sparse / BM25-style) vector-index configuration declared in an arcade do … end block. The %AshArcadic.SparseVectorIndex{} struct is the target of the sparse_vector_index DSL entity; it is declaration only — metadata the read path reads at query time (the Type[tokens,weights] reference), plus compile-time validation (ValidateSparseVectorIndex). AshArcadic does NOT create the index — the host app runs Arcadic.Vector.create_sparse_index/5 (there is no migration/DDL machinery here).

Post-authorization Elixir fold for traversal aggregates (Slice 4). Folds a source's ALREADY-authorized, node-deduped, tenant-scoped, filtered, sorted destination records (from Traverse.load's Read B) into one aggregate value — never a DB-side aggregate (which would count policy-denied nodes and double-count multi-path nodes for sum/avg).

Dense vector-index configuration declared in an arcade do … end block. The %AshArcadic.VectorIndex{} struct is the target of the vector_index DSL entity; it is declaration only — metadata the read path reads at query time (the Type[property] reference, and similarity for distance/threshold semantics), plus compile-time validation (ValidateVectorIndex). AshArcadic does NOT create the index — the host app runs Arcadic.Vector.create_dense_index/5 (there is no migration/DDL machinery here, by the same precedent that leaves endpoint-PK indexes to the host).