Unique event type constraint
Use builder.Unique<TEventType>() inside an IConstraint implementation to enforce that only one event of a specific type can be appended per event source identifier. Use this when the event itself is a unique fact — for example, initializing a project can only happen once per project.
Chronicle discovers all IConstraint implementations automatically — no registration is needed.
Defining a unique event type constraint
Section titled “Defining a unique event type constraint”using Cratis.Chronicle.Events;using Cratis.Chronicle.Events.Constraints;
[EventType]public record ConstraintsUniqueEventTypeProjectInitialized;
public class ConstraintsUniqueEventTypeProjectInitialization : IConstraint{ public void Define(IConstraintBuilder builder) => builder.Unique<ConstraintsUniqueEventTypeProjectInitialized>();}import io.cratis.chronicle.constraints.IConstraintimport io.cratis.chronicle.constraints.IConstraintBuilderimport io.cratis.chronicle.events.EventType
@EventType(id = "constraints-unique-event-type-project-initialized")class ConstraintsUniqueEventTypeProjectInitialized
class ConstraintsUniqueEventTypeProjectInitialization : IConstraint { override fun define(builder: IConstraintBuilder) { builder.uniqueFor(ConstraintsUniqueEventTypeProjectInitialized::class) }}import io.cratis.chronicle.constraints.IConstraint;import io.cratis.chronicle.constraints.IConstraintBuilder;import io.cratis.chronicle.events.EventType;import kotlin.jvm.JvmClassMappingKt;
@EventType(id = "constraints-unique-event-type-project-initialized")class ConstraintsUniqueEventTypeProjectInitialized {}
class ConstraintsUniqueEventTypeProjectInitialization implements IConstraint { @Override public void define(IConstraintBuilder builder) { builder.uniqueFor( JvmClassMappingKt.getKotlinClass(ConstraintsUniqueEventTypeProjectInitialized.class), ""); }}import { constraint, eventType, IConstraint, IConstraintBuilder } from '@cratis/chronicle';
@eventType()class ConstraintsUniqueEventTypeProjectInitialized {}
@constraint()class ConstraintsUniqueEventTypeProjectInitialization implements IConstraint { define(builder: IConstraintBuilder): void { builder.uniqueFor(ConstraintsUniqueEventTypeProjectInitialized); }}Violation message
Section titled “Violation message”Provide a static message string:
using Cratis.Chronicle.Events;using Cratis.Chronicle.Events.Constraints;
[EventType]public record ConstraintsUniqueEventTypeMessageProjectInitialized;
public class ConstraintsUniqueEventTypeMessageProjectInitialization : IConstraint{ public void Define(IConstraintBuilder builder) => builder.Unique<ConstraintsUniqueEventTypeMessageProjectInitialized>( message: "A project can only be initialized once.");}import io.cratis.chronicle.constraints.IConstraintimport io.cratis.chronicle.constraints.IConstraintBuilderimport io.cratis.chronicle.events.EventType
@EventType(id = "constraints-unique-event-type-message-project-initialized")class ConstraintsUniqueEventTypeMessageProjectInitialized
class ConstraintsUniqueEventTypeMessageProjectInitialization : IConstraint { override fun define(builder: IConstraintBuilder) { builder.uniqueFor( ConstraintsUniqueEventTypeMessageProjectInitialized::class, message = "A project can only be initialized once." ) }}import io.cratis.chronicle.constraints.IConstraint;import io.cratis.chronicle.constraints.IConstraintBuilder;import io.cratis.chronicle.events.EventType;import kotlin.jvm.JvmClassMappingKt;
@EventType(id = "constraints-unique-event-type-message-project-initialized")class ConstraintsUniqueEventTypeMessageProjectInitialized {}
class ConstraintsUniqueEventTypeMessageProjectInitialization implements IConstraint { @Override public void define(IConstraintBuilder builder) { builder.uniqueFor( JvmClassMappingKt.getKotlinClass(ConstraintsUniqueEventTypeMessageProjectInitialized.class), "A project can only be initialized once."); }}import { constraint, eventType, IConstraint, IConstraintBuilder } from '@cratis/chronicle';
@eventType()class ConstraintsUniqueEventTypeMessageProjectInitialized {}
@constraint()class ConstraintsUniqueEventTypeMessageProjectInitialization implements IConstraint { define(builder: IConstraintBuilder): void { builder.uniqueFor(ConstraintsUniqueEventTypeMessageProjectInitialized, 'A project can only be initialized once.'); }}Or use a callback to compose the message dynamically from violation context:
using Cratis.Chronicle.Events;using Cratis.Chronicle.Events.Constraints;
[EventType]public record ConstraintsUniqueEventTypeCallbackProjectInitialized;
public class ConstraintsUniqueEventTypeCallbackProjectInitialization : IConstraint{ public void Define(IConstraintBuilder builder) => builder.Unique<ConstraintsUniqueEventTypeCallbackProjectInitialized>( messageCallback: violation => $"Constraint '{violation.ConstraintName}' was violated - the project has already been initialized.");}Constraint name
Section titled “Constraint name”An optional name can be provided to identify the constraint. When not provided, Chronicle uses the event type name as the default constraint name:
using Cratis.Chronicle.Events;using Cratis.Chronicle.Events.Constraints;
[EventType]public record ConstraintsUniqueEventTypeNamedProjectInitialized;
public class ConstraintsUniqueEventTypeNamedProjectInitialization : IConstraint{ public void Define(IConstraintBuilder builder) => builder.Unique<ConstraintsUniqueEventTypeNamedProjectInitialized>( name: "UniqueProjectInitialization", message: "A project can only be initialized once.");}Kotlin does not support this workflow yet.Java does not support this workflow yet.import { constraint, eventType, IConstraint, IConstraintBuilder } from '@cratis/chronicle';
@eventType()class ConstraintsUniqueEventTypeNamedProjectInitialized {}
@constraint()class ConstraintsUniqueEventTypeNamedProjectInitialization implements IConstraint { define(builder: IConstraintBuilder): void { builder.uniqueFor( ConstraintsUniqueEventTypeNamedProjectInitialized, 'A project can only be initialized once.', 'UniqueProjectInitialization'); }}How constraints are enforced
Section titled “How constraints are enforced”When a constraint is registered, the Chronicle Kernel creates the indexes required to enforce it. Constraints are evaluated server-side during append, ensuring data integrity regardless of the client.