| Copyright | (c) 2024 |
|---|---|
| License | BSD3 |
| Maintainer | maintainer@example.com |
| Stability | experimental |
| Safe Haskell | None |
| Language | GHC2021 |
Hindsight.Events
Description
This module provides the core API for Hindsight's event system. It enables compile-time event versioning, automatic serialization, and safe event evolution over time.
Overview
Hindsight uses type-level programming to provide compile-time guarantees about
event versioning and upgrades. Events are identified by type-level strings
(Symbols) and can have multiple payload versions that evolve over time.
Quick Start
To define a single-version event:
type instance MaxVersion "user_created" = 0 type instance Versions "user_created" = '[UserCreated] instance Event "user_created" instance MigrateVersion 0 "user_created" -- No method needed for single version!
Then use mkEvent to create event values:
event = mkEvent "user_created" (UserCreated userId name)
Advanced Usage: Multi-Version Events
For events with multiple versions, define consecutive upgrades using Upcast
and the system automatically composes them:
-- V0 → V1 transition
instance Upcast 0 "user_created" where
upcast v0 = V1 { newField = defaultValue, ... }
-- V1 → V2 transition
instance Upcast 1 "user_created" where
upcast v1 = V2 { anotherField = defaultValue, ... }
-- Migration instances use automatic composition
instance MigrateVersion 0 "user_created" -- Automatic: V0 → V1 → V2
instance MigrateVersion 1 "user_created" -- Automatic: V1 → V2
instance MigrateVersion 2 "user_created" -- Automatic: V2 → V2 (identity)
For detailed examples, see the tutorial documentation in the hindsight-tutorials package.
Type Aliases for Clarity
This module provides several type aliases to make complex type signatures more readable:
EventVersionCount- The number of versions for an eventEventVersionVector- The full version vector typeFullVersionRange- Evidence that all versions satisfy constraints
These are particularly useful when reading type errors or writing advanced code.
Synopsis
- class EventConstraints event => Event (event :: Symbol)
- type EventConstraints (event :: Symbol) = (AssertVersionCountMatches event, KnownSymbol event, Typeable event, ToJSON (CurrentPayloadType event), FullVersionRange event, ReifiablePeanoNat (ToPeanoNat (MaxVersion event)))
- data SomeLatestEvent = Event event => SomeLatestEvent {
- getEventProxy :: Proxy event
- getPayload :: CurrentPayloadType event
- mkEvent :: forall (event :: Symbol) -> Event event => CurrentPayloadType event -> SomeLatestEvent
- getEventName :: forall (event :: Symbol). KnownSymbol event => Proxy event -> Text
- type family MaxVersion (event :: Symbol) :: Nat
- type family Versions (event :: Symbol) :: [Type]
- type CurrentPayloadType (event :: Symbol) = FinalVersionType (EventVersionVector event)
- type EventVersionCount (event :: Symbol) = 'PeanoSucc (ToPeanoNat (MaxVersion event))
- type family EventVersionVector (event :: Symbol) :: EventVersions 'PeanoZero (EventVersionCount event) where ...
- type FullVersionRange (event :: Symbol) = HasEvidenceList 'PeanoZero (EventVersionCount event) event ValidPayloadForVersion (EventVersionVector event)
- data EventVersions (startsAt :: PeanoNat) (finalCount :: PeanoNat) where
- Final :: forall (startsAt :: PeanoNat). Type -> EventVersions startsAt ('PeanoSucc startsAt)
- Then :: forall (startsAt :: PeanoNat) (finalCount :: PeanoNat). Type -> EventVersions ('PeanoSucc startsAt) finalCount -> EventVersions startsAt finalCount
- type family FromList (payloadList :: [Type]) :: k where ...
- type family FinalVersionType (vec :: EventVersions startsAt finalCount) where ...
- type PayloadVersion (event :: Symbol) (n :: PeanoNat) = PayloadAtVersion n (EventVersionVector event)
- type family PayloadAtVersion (idx :: PeanoNat) (vec :: EventVersions startsAt finalCount) where ...
- class Upcast (ver :: Nat) (event :: Symbol) where
- upcast :: PayloadAtVersion (ToPeanoNat ver) (EventVersionVector event) -> PayloadAtVersion (ToPeanoNat (ver + 1)) (EventVersionVector event)
- class MigrateVersion (ver :: Nat) (event :: Symbol) where
- migrateVersion :: PayloadAtVersion (ToPeanoNat ver) (EventVersionVector event) -> CurrentPayloadType event
- type family MaxVersionPeano (event :: Symbol) :: PeanoNat where ...
- type Serializable a = (Show a, Eq a, FromJSON a, ToJSON a)
- parseMap :: forall (event :: Symbol). Event event => Map Int (Value -> Parser (CurrentPayloadType event))
- parseMapFromProxy :: forall (event :: Symbol). Event event => Proxy event -> Map Int (Value -> Parser (CurrentPayloadType event))
- getMaxVersion :: forall (event :: Symbol). Event event => Proxy event -> Integer
- data PeanoNat
- class ReifiablePeanoNat (n :: PeanoNat) where
- type family ToPeanoNat (n :: Nat) :: PeanoNat where ...
- type family FromPeanoNat (n :: PeanoNat) :: Nat where ...
- data Dict c where
- data VersionConstraints (ts :: EventVersions startsAt finalCount) (c :: PeanoNat -> Type -> Constraint) where
- VersionConstraintsLast :: forall (c :: PeanoNat -> Type -> Constraint) (startsAt :: PeanoNat) t. c startsAt t => (Proxy startsAt, Proxy t) -> VersionConstraints ('Final t :: EventVersions startsAt ('PeanoSucc startsAt)) c
- VersionConstraintsCons :: forall (c :: PeanoNat -> Type -> Constraint) (startsAt :: PeanoNat) t (finalCount :: PeanoNat) (ts' :: EventVersions ('PeanoSucc startsAt) finalCount). c startsAt t => (Proxy startsAt, Proxy t) -> VersionConstraints ts' c -> VersionConstraints ('Then t ts') c
- class VersionPayloadRequirements event idx payload => ValidPayloadForVersion (event :: Symbol) (idx :: PeanoNat) payload where
- constraintEvidence :: Dict (VersionPayloadRequirements event idx payload)
- class HasEvidenceList (startsAt :: PeanoNat) (finalCount :: PeanoNat) (event :: k) (c :: k -> PeanoNat -> Type -> Constraint) (vec :: EventVersions startsAt finalCount)
- type HasFullEvidenceList (event :: Symbol) (c :: Symbol -> PeanoNat -> Type -> Constraint) = HasEvidenceList 'PeanoZero (EventVersionCount event) event c (EventVersionVector event)
- getPayloadEvidence :: forall (event :: Symbol) (c :: Symbol -> PeanoNat -> Type -> Constraint). HasFullEvidenceList event c => VersionConstraints (EventVersionVector event) (c event)
- type VersionPayloadRequirements (event :: Symbol) (idx :: PeanoNat) payload = (Serializable payload, MigrateVersion (FromPeanoNat idx) event, PayloadVersion event (ToPeanoNat (FromPeanoNat idx)) ~ PayloadVersion event idx, KnownSymbol event, ReifiablePeanoNat idx, Typeable payload, Typeable event, Typeable idx, payload ~ PayloadVersion event idx)
- type family PeanoEqual (a :: PeanoNat) (b :: PeanoNat) (thenResult :: result) (elseResult :: result) :: result where ...
Event Definition
Core types for defining and working with events.
class EventConstraints event => Event (event :: Symbol) Source #
Core type class for versioned events.
This is the main constraint you'll use when working with events. It automatically
includes all necessary constraints via EventConstraints.
To define an event, create instances of MaxVersion, Versions, Event,
and MigrateVersion:
type instance MaxVersion "user_created" = 0 type instance Versions "user_created" = '[UserCreated] instance Event "user_created" instance MigrateVersion 0 "user_created" -- Automatic migration (identity for v0)
type EventConstraints (event :: Symbol) = (AssertVersionCountMatches event, KnownSymbol event, Typeable event, ToJSON (CurrentPayloadType event), FullVersionRange event, ReifiablePeanoNat (ToPeanoNat (MaxVersion event))) Source #
Complete set of constraints required for an event type.
This type alias bundles all the low-level constraints needed for event processing:
AssertVersionCountMatches- Validate MaxVersion matches Versions list lengthKnownSymbol- Access event name as runtime valueTypeable- Runtime type informationToJSON- Serialize current version payloadsFullVersionRange- Compile-time evidence for all version constraintsReifiablePeanoNat- Convert type-level version numbers to runtime values
You don't typically need to use this directly; just use the Event constraint.
This is exported for documentation purposes so you can see what constraints
are actually required.
data SomeLatestEvent Source #
Existential wrapper for an event at its latest version.
This packages up an event name (as a Proxy) with its current payload,
hiding the specific event type. Useful for heterogeneous collections of events.
Create values using mkEvent.
Constructors
| Event event => SomeLatestEvent | |
Fields
| |
Arguments
| :: forall (event :: Symbol) -> Event event | |
| => CurrentPayloadType event | Event payload at current version |
| -> SomeLatestEvent | Wrapped event with type information |
Smart constructor for creating events using RequiredTypeArguments.
This provides a convenient syntax for creating events:
event = mkEvent "user_created" (UserCreated userId name)
This is equivalent to:
event = SomeLatestEvent (Proxy @"user_created") (UserCreated userId name)
Event Names
Arguments
| :: forall (event :: Symbol). KnownSymbol event | |
| => Proxy event | Proxy for the event type |
| -> Text | Event name as Text |
Get the event name as Text from a Symbol.
This converts a type-level event name to a runtime value, useful for logging, debugging, and serialization.
getEventName (Proxy @"user_created") = "user_created"
Event Versioning
Type families and aliases for declaring event versions.
Use MaxVersion to declare the latest version number, and Versions
to specify the payload types for each version.
type family MaxVersion (event :: Symbol) :: Nat Source #
Declare the maximum version number for an event.
Version numbers start at 0. For a single-version event, use MaxVersion = 0.
For multi-version events, increment this as you add versions.
type instance MaxVersion "user_created" = 0 -- Single version type instance MaxVersion "order_placed" = 2 -- Three versions (0, 1, 2)
type family Versions (event :: Symbol) :: [Type] Source #
Declare the payload types for each version of an event.
Use a type-level list to specify all payload versions in order:
-- Single version: type instance Versions "user_created" = '[UserCreated] -- Multiple versions: type instance Versions "order_placed" = '[OrderPlacedV0, OrderPlacedV1, OrderPlacedV2]
The list length must match MaxVersion + 1. This constraint is enforced
at compile time through the version evidence system.
type CurrentPayloadType (event :: Symbol) = FinalVersionType (EventVersionVector event) Source #
Get the current (latest) payload type for an event.
This extracts the final type from the version vector:
CurrentPayloadType "user_created" = UserCreated CurrentPayloadType "order_placed" = OrderPlacedV2 -- if MaxVersion = 2
Clarity Aliases
These aliases make type signatures more readable.
type EventVersionCount (event :: Symbol) = 'PeanoSucc (ToPeanoNat (MaxVersion event)) Source #
The number of versions for an event (as a Peano number).
This is MaxVersion + 1 in Peano encoding. For an event with MaxVersion = 2,
this expands to PeanoSucc (PeanoSucc (PeanoSucc PeanoZero)).
This alias makes type signatures more readable when working with version indices and constraints.
type family EventVersionVector (event :: Symbol) :: EventVersions 'PeanoZero (EventVersionCount event) where ... Source #
The full version vector type for an event.
This type family represents the complete EventVersions structure from version 0 to
MaxVersion. This is computed from the Versions list using FromList.
Example expansion:
EventVersionVector "user_created"
= FromList (Versions "user_created")
= FromList '[UserCreated]
= EventVersions 'PeanoZero ('PeanoSucc 'PeanoZero)
Note: This is an internal type family. Users should work with Versions
which uses the simpler list syntax.
Equations
| EventVersionVector event = FromList (Versions event) :: EventVersions 'PeanoZero ('PeanoSucc (ToPeanoNat (MaxVersion event))) |
type FullVersionRange (event :: Symbol) = HasEvidenceList 'PeanoZero (EventVersionCount event) event ValidPayloadForVersion (EventVersionVector event) Source #
Evidence that all version payloads satisfy the required constraints.
This is the main "proof obligation" checked by EventConstraints. It ensures
that every payload version can be serialized, deserialized, and upgraded to
the latest version.
Using this alias makes EventConstraints much more readable:
type EventConstraints event = ( ... , FullVersionRange event -- instead of massive HasEvidenceList expression , ... )
Internal Version Machinery
Low-level types for the version system.
Most users won't need these directly. The EventVersions GADT and
FromList type family are used internally to convert the simple list
syntax from Versions into the indexed type structure.
data EventVersions (startsAt :: PeanoNat) (finalCount :: PeanoNat) where Source #
Type-level vector of versioned payload types.
This GADT represents a non-empty list of types, indexed by Peano numbers. The indices track the "start" and "end" positions in the version sequence.
startsAt- The version number where this vector beginsfinalCount- One past the last version (i.e., length when startsAt = 0)
Constructors:
Final- A single-element vector (the last/only version)Then- Prepend a type to an existing vector (earlier versions)
Example: A vector of 3 versions (0, 1, 2):
Then PayloadV0 (Then PayloadV1 (Final PayloadV2)) :: EventVersions PeanoZero (PeanoSucc (PeanoSucc (PeanoSucc PeanoZero)))
Constructors
| Final :: forall (startsAt :: PeanoNat). Type -> EventVersions startsAt ('PeanoSucc startsAt) | Final version in the vector |
| Then :: forall (startsAt :: PeanoNat) (finalCount :: PeanoNat). Type -> EventVersions ('PeanoSucc startsAt) finalCount -> EventVersions startsAt finalCount | Prepend an earlier version |
type family FromList (payloadList :: [Type]) :: k where ... Source #
Convert a type-level list to an EventVersions GADT
This has a polymorphic kind to allow recursive usage at different indices.
The result kind is constrained at usage sites via EventVersionVector.
Equations
| FromList '[a] = 'Final a :: EventVersions startsAt ('PeanoSucc startsAt) | |
| FromList (a ': rest) = 'Then a (FromList rest :: EventVersions ('PeanoSucc startsAt) finalCount) |
Upgrade System
Types and classes for upgrading old event versions to the latest.
type family FinalVersionType (vec :: EventVersions startsAt finalCount) where ... Source #
Extract the final (most recent) type from a version vector.
This traverses the vector structure to find the Final constructor.
Equations
| FinalVersionType ('Final t :: EventVersions startsAt ('PeanoSucc startsAt)) = t | |
| FinalVersionType ('Then t rest :: EventVersions startsAt finalCount) = FinalVersionType rest |
type PayloadVersion (event :: Symbol) (n :: PeanoNat) = PayloadAtVersion n (EventVersionVector event) Source #
Get the payload type at a specific version number.
This allows you to reference older payload versions in upgrade logic:
instance Upcast 0 "order_placed" where upcast :: PayloadVersion "order_placed" 0 -> PayloadVersion "order_placed" 1 upcast v0 = ... -- upgrade OrderPlacedV0 to OrderPlacedV1
type family PayloadAtVersion (idx :: PeanoNat) (vec :: EventVersions startsAt finalCount) where ... Source #
Extract the type at a specific version index.
Returns a compile error if the index is out of bounds.
Equations
| PayloadAtVersion idx ('Final t :: EventVersions startsAt ('PeanoSucc startsAt)) = PeanoEqual idx startsAt t (TypeError ('Text "Version index out of bounds") :: Type) | |
| PayloadAtVersion idx ('Then t rest :: EventVersions startsAt finalCount) = PeanoEqual idx startsAt t (PayloadAtVersion idx rest) |
Consecutive Upcast API
API for version migrations using consecutive upgrades.
Define one Upcast instance per version transition, and MigrateVersion
instances are automatically composed.
class Upcast (ver :: Nat) (event :: Symbol) where Source #
Upgrade a payload from version ver to version ver + 1.
This class represents a single consecutive upgrade step. You define one instance for each version transition:
-- Upgrade from V0 to V1
instance Upcast 0 MyEvent where
upcast v0 = V1 { newField = defaultValue, ... }
-- Upgrade from V1 to V2
instance Upcast 1 MyEvent where
upcast v1 = V2 { anotherField = defaultValue, ... }
These consecutive upgrades are automatically composed to provide
migrations from any old version to the latest via MigrateVersion.
Methods
upcast :: PayloadAtVersion (ToPeanoNat ver) (EventVersionVector event) -> PayloadAtVersion (ToPeanoNat (ver + 1)) (EventVersionVector event) Source #
Upgrade from version ver to version ver + 1
Instances
| (TypeError (((((((((('Text "Missing Upcast instance for version " ':<>: 'ShowType ver) ':<>: 'Text " of event \"") ':<>: 'Text event) ':<>: 'Text "\"") ':$$: 'Text "") ':$$: 'Text "You need to define:") ':$$: (((('Text " instance Upcast " ':<>: 'ShowType ver) ':<>: 'Text " \"") ':<>: 'Text event) ':<>: 'Text "\" where")) ':$$: (('Text " upcast v" ':<>: 'ShowType ver) ':<>: 'Text " = ...")) ':$$: 'Text "") ':$$: ((('Text "This upgrades from version " ':<>: 'ShowType ver) ':<>: 'Text " to version ") ':<>: 'ShowType (ver + 1))) :: Constraint) => Upcast ver event Source # | Provide a helpful error message when an Upcast instance is missing. This overlappable instance ensures that if you forget to define an Upcast instance for a version, you get a clear error message instead of cryptic constraint errors. |
Defined in Hindsight.Events Methods upcast :: PayloadAtVersion (ToPeanoNat ver) (EventVersionVector event) -> PayloadAtVersion (ToPeanoNat (ver + 1)) (EventVersionVector event) Source # | |
class MigrateVersion (ver :: Nat) (event :: Symbol) where Source #
Migrate a payload from any version to the latest version.
You must declare an instance for each version, but the method body is optional (uses automatic consecutive composition by default):
-- Automatic consecutive composition (V0 → V1 → V2)
instance MigrateVersion 0 MyEvent
-- Also automatic (V1 → V2)
instance MigrateVersion 1 MyEvent
-- Latest version (identity)
instance MigrateVersion 2 MyEvent
-- Override for direct upgrade (if needed)
instance MigrateVersion 0 MyEvent where
migrateVersion v0 = V2 { ... } -- Skip V1 if it loses information
Minimal complete definition
Nothing
Methods
migrateVersion :: PayloadAtVersion (ToPeanoNat ver) (EventVersionVector event) -> CurrentPayloadType event Source #
Migrate from version ver to the latest version
default migrateVersion :: ConsecutiveUpcast (IsLatest (ToPeanoNat ver) event) (ToPeanoNat ver) event => PayloadAtVersion (ToPeanoNat ver) (EventVersionVector event) -> CurrentPayloadType event Source #
Default implementation: automatically compose consecutive upgrades
This delegates to ConsecutiveUpcast which handles both the
latest version (identity) and non-latest versions (composition) cases.
type family MaxVersionPeano (event :: Symbol) :: PeanoNat where ... Source #
Convert MaxVersion to Peano representation for type-level computation.
This is used internally by the consecutive upcast machinery to determine when a version is the latest.
Equations
| MaxVersionPeano event = ToPeanoNat (MaxVersion event) |
Serialization
Type constraints for JSON serialization.
type Serializable a = (Show a, Eq a, FromJSON a, ToJSON a) Source #
Basic type constraints required for event payloads.
All payload types must be serializable to JSON for storage and transmission.
Parsing Utilities
Functions typically used by store implementations for deserializing events from storage.
Arguments
| :: forall (event :: Symbol). Event event | |
| => Map Int (Value -> Parser (CurrentPayloadType event)) | Map from version to parser |
Build a version-aware parser map for an event.
Creates a map from version numbers to parsers that can deserialize event payloads at any version and automatically upgrade them to the latest.
This is used internally by store implementations when reading events from storage.
parseMap @"order_placed"
= Map.fromList
[ (0, parser that reads OrderPlacedV0 and upgrades to V2)
, (1, parser that reads OrderPlacedV1 and upgrades to V2)
, (2, parser that reads OrderPlacedV2 directly)
]
Arguments
| :: forall (event :: Symbol). Event event | |
| => Proxy event | Proxy for the event type |
| -> Map Int (Value -> Parser (CurrentPayloadType event)) | Map from version to parser |
Convenience wrapper around parseMap that accepts a proxy argument.
Some contexts require explicit type application or proxy arguments. This function provides compatibility with such APIs.
Arguments
| :: forall (event :: Symbol). Event event | |
| => Proxy event | Proxy for the event type |
| -> Integer | Maximum version number |
Get the maximum version number for an event as a runtime integer.
Useful for debugging, logging, or runtime version checks:
getMaxVersion (Proxy @"order_placed") = 2 -- if MaxVersion "order_placed" = 2
Advanced Type-Level Utilities
These are primarily for internal use or advanced scenarios.
Most users won't need to reference these directly. They're exported for documentation purposes and for library implementors.
Peano Numbers
Type-level Peano natural numbers.
These provide an alternative representation to GHC's Nat that's more
suitable for structural recursion and pattern matching at the type level.
0 = PeanoZero 1 = PeanoSucc PeanoZero 2 = PeanoSucc (PeanoSucc PeanoZero) ...
class ReifiablePeanoNat (n :: PeanoNat) where Source #
Convert type-level Peano numbers to runtime integers.
This class allows us to "reify" type-level numbers into runtime values, which is necessary for parsing version numbers from JSON and other runtime operations.
Instances
| ReifiablePeanoNat 'PeanoZero Source # | |
Defined in Hindsight.Events.Internal.TypeLevel Methods | |
| ReifiablePeanoNat n => ReifiablePeanoNat ('PeanoSucc n) Source # | |
Defined in Hindsight.Events.Internal.TypeLevel Methods | |
type family ToPeanoNat (n :: Nat) :: PeanoNat where ... Source #
Convert GHC's Nat to Peano representation.
This is needed because type families and data families use Nat,
but we need PeanoNat for structural pattern matching.
Equations
| ToPeanoNat 0 = 'PeanoZero | |
| ToPeanoNat n = 'PeanoSucc (ToPeanoNat (n - 1)) |
type family FromPeanoNat (n :: PeanoNat) :: Nat where ... Source #
Convert Peano representation back to GHC's Nat.
This is the inverse of ToPeanoNat and is needed for some constraint
manipulations where GHC requires Nat.
Equations
| FromPeanoNat 'PeanoZero = 0 | |
| FromPeanoNat ('PeanoSucc n) = 1 + FromPeanoNat n |
Constraint Evidence
Dictionary carrying constraint evidence.
This allows us to package up constraints and manipulate them at runtime. It's particularly useful for passing around evidence that certain type-level properties hold.
Example use: storing evidence that a payload satisfies serialization constraints so we can retrieve it later when needed.
data VersionConstraints (ts :: EventVersions startsAt finalCount) (c :: PeanoNat -> Type -> Constraint) where Source #
Evidence that each version in a vector satisfies some constraint.
This GADT packages up constraint evidence for all elements in an
EventVersions vector. It's structurally similar to the vector itself:
VersionConstraintsLast- Evidence for a single-element vectorVersionConstraintsCons- Evidence for the head, plus recursive evidence
The constraint c is indexed by version number and payload type:
c :: PeanoNat -> Type -> Constraint
Example: Prove all versions are serializable:
class (ToJSON payload, FromJSON payload) => Serializable (idx :: PeanoNat) payload ... evidence :: VersionConstraints myVersions Serializable
Constructors
| VersionConstraintsLast :: forall (c :: PeanoNat -> Type -> Constraint) (startsAt :: PeanoNat) t. c startsAt t => (Proxy startsAt, Proxy t) -> VersionConstraints ('Final t :: EventVersions startsAt ('PeanoSucc startsAt)) c | Evidence for a single-element vector |
| VersionConstraintsCons :: forall (c :: PeanoNat -> Type -> Constraint) (startsAt :: PeanoNat) t (finalCount :: PeanoNat) (ts' :: EventVersions ('PeanoSucc startsAt) finalCount). c startsAt t => (Proxy startsAt, Proxy t) -> VersionConstraints ts' c -> VersionConstraints ('Then t ts') c | Evidence for head + inductive evidence for tail |
class VersionPayloadRequirements event idx payload => ValidPayloadForVersion (event :: Symbol) (idx :: PeanoNat) payload where Source #
Evidence that a type is a valid payload for a version.
This class packages up VersionPayloadRequirements into a Dict that can
be passed around at runtime. Used internally by the parsing machinery.
Methods
constraintEvidence :: Dict (VersionPayloadRequirements event idx payload) Source #
Instances
| VersionPayloadRequirements event idx payload => ValidPayloadForVersion event idx payload Source # | |
Defined in Hindsight.Events Methods constraintEvidence :: Dict (VersionPayloadRequirements event idx payload) Source # | |
class HasEvidenceList (startsAt :: PeanoNat) (finalCount :: PeanoNat) (event :: k) (c :: k -> PeanoNat -> Type -> Constraint) (vec :: EventVersions startsAt finalCount) Source #
Build constraint evidence for all elements in a version vector.
This class provides a way to automatically derive VersionConstraints
evidence given:
- Evidence that each individual version satisfies the constraint
c - The structure of the version vector
The instances mirror the structure of EventVersions:
Usage:
getEvidenceList :: VersionConstraints myVersions MyConstraint
Minimal complete definition
Instances
| (c event startsAt payload, HasEvidenceList ('PeanoSucc startsAt) finalCount event c ts) => HasEvidenceList startsAt finalCount (event :: k) (c :: k -> PeanoNat -> Type -> Constraint) ('Then payload ts :: EventVersions startsAt finalCount) Source # | Inductive case: Evidence for multi-version vector |
Defined in Hindsight.Events.Internal.Versioning Methods getEvidenceList :: VersionConstraints ('Then payload ts) (c event) Source # | |
| c event startsAt payload => HasEvidenceList startsAt ('PeanoSucc startsAt) (event :: k) (c :: k -> PeanoNat -> Type -> Constraint) ('Final payload :: EventVersions startsAt ('PeanoSucc startsAt)) Source # | Base case: Evidence for a single-version vector |
Defined in Hindsight.Events.Internal.Versioning Methods getEvidenceList :: VersionConstraints ('Final payload :: EventVersions startsAt ('PeanoSucc startsAt)) (c event) Source # | |
type HasFullEvidenceList (event :: Symbol) (c :: Symbol -> PeanoNat -> Type -> Constraint) = HasEvidenceList 'PeanoZero (EventVersionCount event) event c (EventVersionVector event) Source #
Convenience alias for full version range evidence.
This is used in EventConstraints via the FullVersionRange alias.
getPayloadEvidence :: forall (event :: Symbol) (c :: Symbol -> PeanoNat -> Type -> Constraint). HasFullEvidenceList event c => VersionConstraints (EventVersionVector event) (c event) Source #
Extract constraint evidence for all versions of an event.
Used internally by parsing and serialization machinery.
Type-Level Utilities
type VersionPayloadRequirements (event :: Symbol) (idx :: PeanoNat) payload = (Serializable payload, MigrateVersion (FromPeanoNat idx) event, PayloadVersion event (ToPeanoNat (FromPeanoNat idx)) ~ PayloadVersion event idx, KnownSymbol event, ReifiablePeanoNat idx, Typeable payload, Typeable event, Typeable idx, payload ~ PayloadVersion event idx) Source #
Core constraints required for event payloads at a specific version.
This bundles together all the requirements for a payload type at a given version index. You typically won't use this directly.
type family PeanoEqual (a :: PeanoNat) (b :: PeanoNat) (thenResult :: result) (elseResult :: result) :: result where ... Source #
Type-level equality check with conditional results.
Returns thenResult if a and b are equal, elseResult otherwise.
This is used for version number matching.
PeanoEqual PeanoZero PeanoZero "yes" "no" = "yes" PeanoEqual (PeanoSucc PeanoZero) PeanoZero "yes" "no" = "no"
Equations
| PeanoEqual n n (thenResult :: result) (_1 :: result) = thenResult | |
| PeanoEqual n m (_1 :: result) (elseResult :: result) = elseResult |