# AshNeo4j v0.10.1 - Table of Contents > Ash DataLayer for Neo4j ## Pages - [Home](readme.md) - [License](mit.md) - How To - [AshNeo4j Livebook](ash_neo4j_datalayer.md) - [Managing Neo4j Schema](managing_schema.md) - DSLs - [AshNeo4j.DataLayer](dsl-ashneo4j-datalayer.md) - About AshNeo4j - [Change Log](changelog.md) ## Modules - AshNeo4j - [AshNeo4j](AshNeo4j.md): Top-level helpers for the AshNeo4j data layer. - [AshNeo4j.DataLayer](AshNeo4j.DataLayer.md): Ash DataLayer for Neo4j. - [AshNeo4j.Sandbox](AshNeo4j.Sandbox.md): Test sandbox for AshNeo4j, analogous to `Ecto.Adapters.SQL.Sandbox`. - Introspection - [AshNeo4j.DataLayer.Info](AshNeo4j.DataLayer.Info.md): Introspection helpers for AshNeo4j.DataLayer - [AshNeo4j.EdgeDescriptor](AshNeo4j.EdgeDescriptor.md): Describes a single graph edge from a resource's perspective. - [AshNeo4j.Resource.Info](AshNeo4j.Resource.Info.md): Resource information for AshNeo4j.DataLayer - [AshNeo4j.ResourceMapping](AshNeo4j.ResourceMapping.md): A compile-time description of how an Ash resource maps to the Neo4j graph. - Cypher - [AshNeo4j.Cypher](AshNeo4j.Cypher.md): AshNeo4j Cypher Functions for converting Elixir data structures to Cypher query components and running Cypher queries against a Neo4j database. Ideally has no specific knowledge of Ash - [AshNeo4j.Cypher.Call](AshNeo4j.Cypher.Call.md): `CALL { … }` block joining pre-rendered branch cyphers with `UNION` or `UNION ALL`. Used for native combination-query pushdown (`:union`, `:union_all`). - [AshNeo4j.Cypher.CallSubquery](AshNeo4j.Cypher.CallSubquery.md): `CALL { … }` subquery block holding a pre-rendered inner query body, e.g. a scoped aggregate `CALL { WITH s MATCH (s)(d) RETURN min(d.p) AS agg_v }`. Distinct from `Call`, which joins branches with `UNION`/`UNION ALL`. - [AshNeo4j.Cypher.Create](AshNeo4j.Cypher.Create.md): CREATE clause. `pattern` is a Cypher pattern string, e.g. `"(n:Actor {name: $n_name})"`. - [AshNeo4j.Cypher.Delete](AshNeo4j.Cypher.Delete.md): DELETE clause. `items` is a list of variables to delete, e.g. `["r"]`. - [AshNeo4j.Cypher.DetachDelete](AshNeo4j.Cypher.DetachDelete.md): DETACH DELETE clause. - [AshNeo4j.Cypher.Limit](AshNeo4j.Cypher.Limit.md): LIMIT clause. - [AshNeo4j.Cypher.Match](AshNeo4j.Cypher.Match.md): MATCH clause. `pattern` is a Cypher pattern string, e.g. `"(s:Actor)"`. - [AshNeo4j.Cypher.Merge](AshNeo4j.Cypher.Merge.md): MERGE clause. `pattern` is a Cypher pattern string. - [AshNeo4j.Cypher.OnCreateSet](AshNeo4j.Cypher.OnCreateSet.md): ON CREATE SET clause (MERGE). `expression` is the full SET expression, e.g. `"n += {born: $nc_born}"`. - [AshNeo4j.Cypher.OnMatchSet](AshNeo4j.Cypher.OnMatchSet.md): ON MATCH SET clause (MERGE). `expression` is the full SET expression, e.g. `"n += {touched: $nm_touched}"`. - [AshNeo4j.Cypher.OptionalMatch](AshNeo4j.Cypher.OptionalMatch.md): OPTIONAL MATCH clause. - [AshNeo4j.Cypher.OrderBy](AshNeo4j.Cypher.OrderBy.md): ORDER BY clause. Each term is a `{property_expression, :asc | :desc}` pair. - [AshNeo4j.Cypher.Query](AshNeo4j.Cypher.Query.md): Typed representation of a Cypher query, and builders for constructing common patterns. - [AshNeo4j.Cypher.Remove](AshNeo4j.Cypher.Remove.md): REMOVE clause. `items` is a list of property references, e.g. `["n.born"]`. - [AshNeo4j.Cypher.Return](AshNeo4j.Cypher.Return.md): RETURN clause. - [AshNeo4j.Cypher.Set](AshNeo4j.Cypher.Set.md): SET clause. `expression` is the full SET expression, e.g. `"n += {born: $n_born}"`. - [AshNeo4j.Cypher.Skip](AshNeo4j.Cypher.Skip.md): SKIP clause. - [AshNeo4j.Cypher.Where](AshNeo4j.Cypher.Where.md): WHERE clause. Each entry in `conditions` is ANDed together. - [AshNeo4j.Cypher.With](AshNeo4j.Cypher.With.md): WITH clause. - Utilities - [AshNeo4j.BoltyHelper](AshNeo4j.BoltyHelper.md): AshNeo4j BoltyHelper - [AshNeo4j.Mermaid](AshNeo4j.Mermaid.md): Render a graph query result as a [Mermaid flowchart](https://mermaid.js.org/syntax/flowchart.html) string. - [AshNeo4j.Neo4jHelper](AshNeo4j.Neo4jHelper.md): AshNeo4j DataLayer Neo4j Helper - [AshNeo4j.QueryHelper](AshNeo4j.QueryHelper.md): AshNeo4j DataLayer QueryHelper - [AshNeo4j.Util](AshNeo4j.Util.md): AshNeo4j Util - Internals - [AshNeo4j.Calculations.ProjectedTraversal](AshNeo4j.Calculations.ProjectedTraversal.md): Read-time projection of a graph traversal (#329): follows a hop `chain` from each record to the reached node and returns it as a value — late-binding the reached node's concrete type at read time via `AshNeo4j.worlds/1`. - [AshNeo4j.Constraint](AshNeo4j.Constraint.md): Convenience helpers for creating the Neo4j uniqueness constraints that enforce a resource's **primary key** (#32) and its `identities` (#20) at the database level. - [AshNeo4j.DataLayer.Cast](AshNeo4j.DataLayer.Cast.md): Casting for AshNeo4j.DataLayer - [AshNeo4j.DataLayer.Domain](AshNeo4j.DataLayer.Domain.md): Domain-level DSL extension for AshNeo4j. - [AshNeo4j.DataLayer.Domain.Info](AshNeo4j.DataLayer.Domain.Info.md): Introspection helpers for AshNeo4j.DataLayer.Domain - [AshNeo4j.DataLayer.Dump](AshNeo4j.DataLayer.Dump.md): Dumping for AshNeo4j.DataLayer - [AshNeo4j.DataLayer.TypeClassifier](AshNeo4j.DataLayer.TypeClassifier.md): Type Classifier for AshNeo4j.DataLayer - [AshNeo4j.Error.GeoDimensionMismatch](AshNeo4j.Error.GeoDimensionMismatch.md): Returned (never raised) when a spatial operation combines geometries of different coordinate dimensions (2D vs 3D) — e.g. a 3D `%Geo.PointZ{}` against a 2D attribute, or vice versa. Neo4j silently returns `null` for mixed-CRS operations (which then drops rows in a `WHERE`), so AshNeo4j refuses up front (#270) by returning `{:error, error}`. - [AshNeo4j.Error.Internal](AshNeo4j.Error.Internal.md): **Returned** (never raised) for an internal invariant the data layer couldn't satisfy — an input shape it didn't expect, or a relationship/aggregate path it couldn't resolve (#372). Distinct from the `Unsupported*` / `Requires*` family (deliberate refusals, `:invalid`) and from `Neo4j` (server errors): this is "we reached a state we shouldn't have", so its class is `:unknown`. - [AshNeo4j.Error.Neo4j](AshNeo4j.Error.Neo4j.md): Wraps a Neo4j server error surfaced from `AshNeo4j.Cypher.run/1` (a `%Bolty.Error{}`), preserving its Neo4j status code and message and classifying it by `:category` (#358) — so a failure surfaces as the actual error, not a generic string. The server-side complement to the returned-error work (#350). - [AshNeo4j.Error.RequiresCypher25](AshNeo4j.Error.RequiresCypher25.md): Returned (never raised) when a Cypher 25 operation is attempted against a Neo4j server older than 2025.06. Upgrade to Neo4j 2025.06 or later to use this feature. - [AshNeo4j.Error.RequiresDynamicLabels](AshNeo4j.Error.RequiresDynamicLabels.md): Returned (never raised) when a dynamic label/type operation (`MATCH (n:$(expr))`, `-[r:$(expr)]->`) is attempted against a Neo4j server older than 5.26. This is the **server-feature axis** — dynamic labels run under plain `CYPHER 5` and are unrelated to the `CYPHER 25` selector (`AshNeo4j.Error.RequiresCypher25`). Upgrade to Neo4j 5.26 or later to use this feature. - [AshNeo4j.Error.UnresolvableTraversal](AshNeo4j.Error.UnresolvableTraversal.md): **Returned** (never raised) when a `traverse(^chain, …)` filter predicate can't be formed because the current graph view can't resolve part of it — a reached node whose label resolves to no loaded resource, or a field that isn't a mapped property of the reached resource. - [AshNeo4j.Error.Unsupported3DGeometry](AshNeo4j.Error.Unsupported3DGeometry.md): Returned (never raised) when a 3D areal or linear geometry (`%Geo.PolygonZ{}`, `%Geo.LineStringZ{}`, …) is written. #270 Phase 1 supports 3D **points** (`%Geo.PointZ{}`) only; 3D areal/linear geometries are deferred to Phase 2, because exact 3D containment/distance needs a model the 2D `topo` refinement cannot provide. Storing 2D bbox companions would silently drop the z. - [AshNeo4j.Error.UnsupportedAtomic](AshNeo4j.Error.UnsupportedAtomic.md): **Returned** (never raised) when a `changeset.atomics` expression can't be rendered into the update Cypher `SET` (#361). The renderer covers arithmetic (`+ - * /`), comparisons, `if/3` (⇒ `CASE`), string concat / `string_trim` (Ash's string cast), attribute refs and scalar literals; an expression using any other Ash function is refused rather than mis-written. - [AshNeo4j.Error.UnsupportedChangesetFilter](AshNeo4j.Error.UnsupportedChangesetFilter.md): **Returned** (never raised) when a `changeset.filter` guard (the "only-update-if" predicate) can't be honoured (#361). We refuse rather than apply the write **unguarded**: silently dropping the guard would write when the predicate says not to (the write-side analogue of the traverse synthesis leaks, #342). - [AshNeo4j.Error.UnsupportedFilterFragment](AshNeo4j.Error.UnsupportedFilterFragment.md): **Returned** (never raised) when a `fragment(...)` filter (the Cypher escape hatch, #33) can't be pushed down — and, because raw Cypher can't be evaluated in Elixir, it can't fall back to in-memory filtering either, so the data layer refuses rather than silently return wrong results. - [AshNeo4j.Error.UnsupportedIdentity](AshNeo4j.Error.UnsupportedIdentity.md): **Returned** (never raised) when an `identity` can't be enforced as a Neo4j uniqueness constraint (#20), so it can't be created by `AshNeo4j.Constraint` — and is refused rather than skipped, since silently leaving it unenforced would permit the duplicate/split records the constraint exists to prevent. - [AshNeo4j.Error.UnsupportedManyToMany](AshNeo4j.Error.UnsupportedManyToMany.md): **Returned** (never raised) when a relationship write resolves to a many-to-many modelled as **back-to-back `has_many`** — two resources each declaring a `has_many` to the other over one edge (#127). Ash anchors a `has_many` by an attribute on the *related* resource; with a `has_many` on both sides there is no to-one side to anchor the connect, so the data layer can't determine which node to relate. The edge itself already represents the many-to-many; the model just needs a to-one side on each hop to anchor the connect. - [AshNeo4j.Functions.StClosestPoint](AshNeo4j.Functions.StClosestPoint.md): `st_closest_point(collection, point)` — returns the closest vertex from a multi-vertex geometry to a target point. Mirrors ash_geo / PostGIS `ST_ClosestPoint`. v1 supports - [AshNeo4j.Functions.StContains](AshNeo4j.Functions.StContains.md): Spatial containment — true if the first geometry contains the second. - [AshNeo4j.Functions.StDistance](AshNeo4j.Functions.StDistance.md): Geodesic distance between two geometries, in meters. Mirrors ash_geo / PostGIS `ST_Distance`. Post #274 every geometry arrives as a `%Geo.*{}` struct. - [AshNeo4j.Functions.StDistanceInMeters](AshNeo4j.Functions.StDistanceInMeters.md): Alias for `st_distance`. PostGIS distinguishes the two because PostGIS `ST_Distance` returns degrees for geographic types unless cast; Neo4j's `point.distance` is always meters for WGS-84, so the distinction is cosmetic for us. This module exists for API parity with ash_geo so consumer code reads identically across data layers. - [AshNeo4j.Functions.StDwithin](AshNeo4j.Functions.StDwithin.md): True if two geometries are within a given distance of each other. Mirrors ash_geo / PostGIS `ST_DWithin`. v1 supports point-point only, with the threshold in meters (geodesic, WGS-84). - [AshNeo4j.Functions.StIntersects](AshNeo4j.Functions.StIntersects.md): `st_intersects(a, b)` — true if two geometries share any space. Mirrors ash_geo / PostGIS `ST_Intersects`. Exact, via [`topo`](https://hex.pm/packages/topo) on the `%Geo.*{}` geometries (#267) — handles any combination of Point / LineString / Polygon / Multi* directly, including segment-edge crossings. - [AshNeo4j.Functions.StWithin](AshNeo4j.Functions.StWithin.md): `st_within(a, b)` — true if `a` is contained by `b`. Argument-flipped `st_contains`. Mirrors ash_geo / PostGIS `ST_Within`. - [AshNeo4j.Functions.Traverse](AshNeo4j.Functions.Traverse.md): A multi-hop graph traversal as an `Ash.Expr` value, pushed down to a Cypher path pattern (#321). - [AshNeo4j.Functions.VectorCosineDistance](AshNeo4j.Functions.VectorCosineDistance.md): Cosine *distance* between a stored vector attribute and a query embedding — the ash_ai-compatible counterpart to `AshNeo4j.Functions.VectorSimilarity`. - [AshNeo4j.Functions.VectorMath](AshNeo4j.Functions.VectorMath.md): Shared in-memory cosine maths for the vector query functions. - [AshNeo4j.Functions.VectorSimilarity](AshNeo4j.Functions.VectorSimilarity.md): Normalised cosine similarity between a stored vector attribute and a query embedding, matching Neo4j's `vector.similarity.cosine/2`. - [AshNeo4j.Geo](AshNeo4j.Geo.md): Geodesic geometry primitives for the in-memory side of AshNeo4j's spatial predicates. - [AshNeo4j.GeoJson](AshNeo4j.GeoJson.md): RFC 7946 GeoJSON encoder/decoder over the `:geo` library. - [AshNeo4j.Spatial](AshNeo4j.Spatial.md): Convenience helpers for creating the Neo4j POINT indexes that back AshNeo4j's spatial pushdown (#275). - [AshNeo4j.Type.NxTensor](AshNeo4j.Type.NxTensor.md): Ash attribute type for a typed tensor of rank 1 to 3 (#309), backed by `Nx.Tensor`. - [AshNeo4j.Type.Vector](AshNeo4j.Type.Vector.md): Ash attribute type for vector embeddings, stored as a Neo4j `LIST`. - [AshNeo4j.Unknown](AshNeo4j.Unknown.md): A sentinel value for *"the data layer tried to determine this and couldn't, in its current view of the graph"* — complementary to `Ash.NotLoaded`. - [AshNeo4j.Vector](AshNeo4j.Vector.md): Convenience helpers for creating the Neo4j VECTOR indexes that back `AshNeo4j.Type.Vector` attributes. - [AshNeo4j.Verifiers.VerifyAttributeType](AshNeo4j.Verifiers.VerifyAttributeType.md): Verifies that attribute types are supported by AshNeo4j.DataLayer - [AshNeo4j.Verifiers.VerifyEnrichable](AshNeo4j.Verifiers.VerifyEnrichable.md): Verifies that relate is unique so relationships are enrichable - [AshNeo4j.Verifiers.VerifyGuard](AshNeo4j.Verifiers.VerifyGuard.md): Verifies that each guard is a node relationship meeting Neo4j conventions - [AshNeo4j.Verifiers.VerifyIdentities](AshNeo4j.Verifiers.VerifyIdentities.md): Refuses, at compile time, any `identity` that can't be enforced as a Neo4j uniqueness constraint (#20) — so an unenforceable identity is caught loudly here rather than silently leaving a gap that permits duplicate/split records. - [AshNeo4j.Verifiers.VerifyLabelsPascalCase](AshNeo4j.Verifiers.VerifyLabelsPascalCase.md): Verifies that Neo4j labels are PascalCase - [AshNeo4j.Verifiers.VerifyPropertiesCamelCase](AshNeo4j.Verifiers.VerifyPropertiesCamelCase.md): Verifies that Neo4j properties are camelCase - [AshNeo4j.Verifiers.VerifyRelate](AshNeo4j.Verifiers.VerifyRelate.md): Verifies that each relate relates to a relationship, and that the edge labels meets Neo4j conventions ## Mix Tasks - Internals - [mix ash_neo4j.install](Mix.Tasks.AshNeo4j.Install.md): Installs AshNeo4j