Convenience helpers for creating the Neo4j uniqueness constraints that enforce a
resource's primary key (#32) and its identities (#20) at the database level.
# Create the constraints for a resource (primary key + every identity)
AshNeo4j.Constraint.create_constraints(AssignmentRelationship)
# Review the Cypher without touching the database
AshNeo4j.Constraint.constraint_statements(AssignmentRelationship)The primary-key constraint enforces uniqueness of the primary key among nodes of the resource's label. It's skipped when an identity already constrains the same attributes (no redundant constraint).
Consistent with AshNeo4j's "no automatic migrations" stance — like
AshNeo4j.Vector, this is an ergonomic tool you call (e.g. from a start-up or
release task), not run on boot. Statements use IF NOT EXISTS, so they are safe
to run repeatedly.
Unsupported identities are refused, not skipped
An identity that can't be enforced — nils_distinct?: false, or a filtered
identity (where:) — returns {:error, %AshNeo4j.Error.UnsupportedIdentity{}}
and creates nothing for the resource (all-or-nothing). Skipping would leave
the identity unenforced and permit the duplicate records the constraint exists to
prevent. The same cases are refused at compile time by
AshNeo4j.Verifiers.VerifyIdentities.
Naming
Identity constraints are named <label_lower>_<identity_name> (e.g.
assignmentrelationship_unique_assignment); the primary-key constraint is
<label_lower>_pk.
Summary
Functions
Returns {:ok, [statement]} — the CREATE CONSTRAINT Cypher create_constraints/2
would run — without touching the database, or {:error, %UnsupportedIdentity{}}.
Runs CREATE CONSTRAINT … IF NOT EXISTS for resource's primary key and every
identity.
Runs DROP CONSTRAINT … IF EXISTS for resource's primary key and every identity.
A no-op for absent constraints. Unsupported identities are refused (nothing was
created for them to drop), consistent with create_constraints/2.
Functions
@spec constraint_statements(Ash.Resource.t()) :: {:ok, [String.t()]} | {:error, term()}
Returns {:ok, [statement]} — the CREATE CONSTRAINT Cypher create_constraints/2
would run — without touching the database, or {:error, %UnsupportedIdentity{}}.
AshNeo4j.Constraint.constraint_statements(Post)
#=> {:ok, ["CREATE CONSTRAINT post_pk IF NOT EXISTS FOR (n:Post) REQUIRE n.uuid IS UNIQUE",
# "CREATE CONSTRAINT post_unique_unique IF NOT EXISTS FOR (n:Post) REQUIRE n.unique IS UNIQUE"]}
@spec create_constraints( Ash.Resource.t(), keyword() ) :: {:ok, [Bolty.Response.t()]} | {:error, term()}
Runs CREATE CONSTRAINT … IF NOT EXISTS for resource's primary key and every
identity.
Returns {:ok, [%Bolty.Response{}]} (one per constraint), or
{:error, %AshNeo4j.Error.UnsupportedIdentity{}} if any identity can't be
enforced — in which case nothing is created.
@spec drop_constraints( Ash.Resource.t(), keyword() ) :: {:ok, [Bolty.Response.t()]} | {:error, term()}
Runs DROP CONSTRAINT … IF EXISTS for resource's primary key and every identity.
A no-op for absent constraints. Unsupported identities are refused (nothing was
created for them to drop), consistent with create_constraints/2.