eventium-sql-common 0.1.0 → 0.2.1
raw patch · 7 files changed
+296/−92 lines, 7 filesdep +timedep −persistent-templatedep ~eventium-coredep ~persistent
Dependencies added: time
Dependencies removed: persistent-template
Dependency ranges changed: eventium-core, persistent
Files
- eventium-sql-common.cabal +19/−7
- src/Eventium/ProjectionCache/Sql.hs +150/−0
- src/Eventium/Store/Sql.hs +1/−0
- src/Eventium/Store/Sql/DefaultEntity.hs +17/−13
- src/Eventium/Store/Sql/JSONString.hs +14/−16
- src/Eventium/Store/Sql/Operations.hs +93/−51
- src/Eventium/Store/Sql/Orphans.hs +2/−5
eventium-sql-common.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.37.0.+-- This file has been generated from package.yaml by hpack version 0.38.3. -- -- see: https://github.com/sol/hpack name: eventium-sql-common-version: 0.1.0+version: 0.2.1 synopsis: Common library for SQL event stores description: Eventium-sql-common provides shared utilities and abstractions for SQL-based event stores. It includes Persistent entity definitions, JSON serialization helpers, and common database@@ -25,8 +25,14 @@ type: git location: https://github.com/aleks-sidorenko/eventium +flag ci+ description: Enable -Werror for CI builds+ manual: True+ default: False+ library exposed-modules:+ Eventium.ProjectionCache.Sql Eventium.Store.Sql Eventium.Store.Sql.DefaultEntity Eventium.Store.Sql.JSONString@@ -36,15 +42,21 @@ Paths_eventium_sql_common hs-source-dirs: src- ghc-options: -Wall+ default-extensions:+ NoFieldSelectors+ DuplicateRecordFields+ OverloadedRecordDot+ ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wredundant-constraints -Wno-type-defaults -Wno-incomplete-uni-patterns build-depends: aeson >=1.5 && <2.3 , base >=4.9 && <5 , bytestring >=0.10 && <0.13- , eventium-core+ , eventium-core >=0.2.0 && <0.3.0 , mtl >=2.2 && <2.4- , persistent >=2.13 && <2.15- , persistent-template >=2.12 && <2.13+ , persistent >=2.14 && <2.18 , text >=1.2 && <2.2- , uuid >=1.3 && <1.4+ , time >=1.9 && <1.14+ , uuid ==1.3.* default-language: Haskell2010+ if flag(ci)+ ghc-options: -Werror
+ src/Eventium/ProjectionCache/Sql.hs view
@@ -0,0 +1,150 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedRecordDot #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE NoFieldSelectors #-}++module Eventium.ProjectionCache.Sql+ ( ProjectionName (..),+ CheckpointName (..),+ ProjectionSnapshotEntity (..),+ migrateProjectionSnapshot,+ sqlVersionedProjectionCache,+ sqlGlobalProjectionCache,+ sqlCheckpointStore,+ )+where++import Control.Monad.IO.Class (MonadIO, liftIO)+import Data.Aeson (FromJSON, ToJSON, Value (Object))+import Data.Text (Text)+import Data.Time (UTCTime, getCurrentTime)+import Database.Persist+import Database.Persist.Sql+import Database.Persist.TH+import Eventium.EventSubscription (CheckpointStore (..))+import Eventium.ProjectionCache.Types+import Eventium.Store.Class (EventVersion (..), SequenceNumber (..))+import Eventium.Store.Sql.JSONString (JSONString, encodeJSON)+import Eventium.Store.Sql.Orphans ()+import Eventium.UUID (UUID, nil)++-- | A name identifying a projection in the projection cache.+-- Used as a discriminator so multiple projections can share one storage table.+newtype ProjectionName = ProjectionName Text+ deriving (Show, Read, Eq, Ord, ToJSON, FromJSON, PersistField, PersistFieldSql)++-- | A name identifying a checkpoint in the projection snapshots table.+-- Distinct from 'ProjectionName' to maintain semantic clarity — checkpoint+-- stores track subscription position, while projection caches store+-- aggregate snapshots.+newtype CheckpointName = CheckpointName Text+ deriving (Show, Read, Eq, Ord, ToJSON, FromJSON, PersistField, PersistFieldSql)++share+ [mkPersist sqlSettings {mpsFieldLabelModifier = const id}, mkMigrate "migrateProjectionSnapshot"]+ [persistLowerCase|+ProjectionSnapshotEntity sql=projection_snapshots+ projectionName ProjectionName+ entityId UUID sql=key+ position Int+ state JSONString+ updatedAt UTCTime+ Primary projectionName entityId+ deriving Show+|]++-- | A SQL-backed 'ProjectionCache' for per-entity snapshots.+--+-- Stores one row per entity. The @key@ is a UUID (aggregate/entity ID)+-- and @position@ is an EventVersion.+--+-- Composes with 'codecProjectionCache' for state encoding.+-- Works with both PostgreSQL and SQLite via Persistent.+sqlVersionedProjectionCache ::+ (MonadIO m) =>+ ProjectionName ->+ ProjectionCache UUID EventVersion JSONString (SqlPersistT m)+sqlVersionedProjectionCache name =+ ProjectionCache+ { storeSnapshot = \uuid (EventVersion ver) state -> do+ now <- liftIO getCurrentTime+ repsert (ProjectionSnapshotEntityKey name uuid) $+ ProjectionSnapshotEntity+ { projectionName = name,+ entityId = uuid,+ position = ver,+ state = state,+ updatedAt = now+ },+ loadSnapshot = \uuid -> do+ mEntity <- get (ProjectionSnapshotEntityKey name uuid)+ return $ fmap (\e -> (EventVersion e.position, e.state)) mEntity+ }++-- | A SQL-backed 'ProjectionCache' for global blob snapshots.+--+-- Stores one row per read model using 'nil' UUID as the key.+-- The @position@ is a SequenceNumber.+--+-- Composes with 'codecProjectionCache' for state encoding.+-- Works with both PostgreSQL and SQLite via Persistent.+sqlGlobalProjectionCache ::+ (MonadIO m) =>+ ProjectionName ->+ ProjectionCache () SequenceNumber JSONString (SqlPersistT m)+sqlGlobalProjectionCache name =+ ProjectionCache+ { storeSnapshot = \() (SequenceNumber sn) state -> do+ now <- liftIO getCurrentTime+ repsert (ProjectionSnapshotEntityKey name nil) $+ ProjectionSnapshotEntity+ { projectionName = name,+ entityId = nil,+ position = sn,+ state = state,+ updatedAt = now+ },+ loadSnapshot = \() -> do+ mEntity <- get (ProjectionSnapshotEntityKey name nil)+ return $ fmap (\e -> (SequenceNumber e.position, e.state)) mEntity+ }++-- | A SQL-backed 'CheckpointStore' for tracking 'SequenceNumber' position.+--+-- Reuses the @projection_snapshots@ table. Stores one row with the+-- 'CheckpointName' as the projection name and 'nil' UUID as the entity key.+-- The @position@ column stores the sequence number; the @state@ column+-- stores an empty JSON string.+sqlCheckpointStore ::+ (MonadIO m) =>+ CheckpointName ->+ CheckpointStore (SqlPersistT m) SequenceNumber+sqlCheckpointStore (CheckpointName name) =+ let projName = ProjectionName name+ in CheckpointStore+ { getCheckpoint = do+ mEntity <- get (ProjectionSnapshotEntityKey projName nil)+ return $ maybe 0 (SequenceNumber . (.position)) mEntity,+ saveCheckpoint = \(SequenceNumber sn) -> do+ now <- liftIO getCurrentTime+ repsert (ProjectionSnapshotEntityKey projName nil) $+ ProjectionSnapshotEntity+ { projectionName = projName,+ entityId = nil,+ position = sn,+ state = encodeJSON (Object mempty),+ updatedAt = now+ }+ }
src/Eventium/Store/Sql.hs view
@@ -3,6 +3,7 @@ ) where +import Eventium.ProjectionCache.Sql as X import Eventium.Store.Sql.DefaultEntity as X import Eventium.Store.Sql.JSONString as X import Eventium.Store.Sql.Operations as X
src/Eventium/Store/Sql/DefaultEntity.hs view
@@ -36,14 +36,15 @@ SqlEvent sql=events uuid UUID version EventVersion- event JSONString+ payload JSONString+ metadata JSONString Maybe UniqueUuidVersion uuid version deriving Show |] sqlEventMakeKey :: SequenceNumber -> Key SqlEvent-sqlEventMakeKey sequenceNumber =- toSqlKey (fromIntegral (unSequenceNumber sequenceNumber))+sqlEventMakeKey (SequenceNumber n) =+ toSqlKey (fromIntegral n) sqlEventUnKey :: Key SqlEvent -> SequenceNumber sqlEventUnKey key =@@ -52,13 +53,16 @@ defaultSqlEventStoreConfig :: SqlEventStoreConfig SqlEvent JSONString defaultSqlEventStoreConfig = SqlEventStoreConfig- SqlEvent- sqlEventMakeKey- sqlEventUnKey- sqlEventUuid- sqlEventVersion- sqlEventEvent- SqlEventId- SqlEventUuid- SqlEventVersion- SqlEventEvent+ { sequenceMakeEntity = SqlEvent,+ makeKey = sqlEventMakeKey,+ unKey = sqlEventUnKey,+ uuid = \(SqlEvent u _ _ _) -> u,+ version = \(SqlEvent _ v _ _) -> v,+ payload = \(SqlEvent _ _ p _) -> p,+ metadata = \(SqlEvent _ _ _ m) -> m,+ sequenceNumberField = SqlEventId,+ uuidField = SqlEventUuid,+ versionField = SqlEventVersion,+ payloadField = SqlEventPayload,+ metadataField = SqlEventMetadata+ }
src/Eventium/Store/Sql/JSONString.hs view
@@ -3,39 +3,37 @@ module Eventium.Store.Sql.JSONString ( JSONString,- jsonStringSerializer,+ jsonStringCodec,+ encodeJSON,+ decodeJSON, ) where -import Data.Aeson+import qualified Data.Aeson as Aeson import Data.Text.Lazy (Text) import qualified Data.Text.Lazy.Encoding as TLE import Database.Persist import Database.Persist.Sql-import Eventium.Serializer+import Eventium.Codec (Codec (..)) -- | A more specific type than just ByteString for JSON data.-newtype JSONString = JSONString {unJSONString :: Text}+newtype JSONString = JSONString Text deriving (Eq, PersistField) instance PersistFieldSql JSONString where sqlType _ = SqlOther "jsonb" instance Show JSONString where- show = show . unJSONString+ show (JSONString t) = show t -jsonStringSerializer :: (ToJSON a, FromJSON a) => Serializer a JSONString-jsonStringSerializer =- Serializer+jsonStringCodec :: (Aeson.ToJSON a, Aeson.FromJSON a) => Codec a JSONString+jsonStringCodec =+ Codec encodeJSON decodeJSON- decodeJSONEither -encodeJSON :: (ToJSON a) => a -> JSONString-encodeJSON = JSONString . TLE.decodeUtf8 . encode--decodeJSON :: (FromJSON a) => JSONString -> Maybe a-decodeJSON = decode . TLE.encodeUtf8 . unJSONString+encodeJSON :: (Aeson.ToJSON a) => a -> JSONString+encodeJSON = JSONString . TLE.decodeUtf8 . Aeson.encode -decodeJSONEither :: (FromJSON a) => JSONString -> Either String a-decodeJSONEither = eitherDecode . TLE.encodeUtf8 . unJSONString+decodeJSON :: (Aeson.FromJSON a) => JSONString -> Maybe a+decodeJSON (JSONString t) = Aeson.decode . TLE.encodeUtf8 $ t
src/Eventium/Store/Sql/Operations.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-}@@ -12,37 +11,39 @@ sqlGetStreamEvents, sqlMaxEventVersion, sqlStoreEvents,+ sqlStoreEventsTagged, unsafeSqlStoreGlobalStreamEvents, ) where import Control.Monad.IO.Class import Data.Foldable (for_)-import Data.Maybe (listToMaybe)+import Data.Maybe (fromMaybe, listToMaybe) import Data.Text (Text) import Database.Persist-import Database.Persist.Class (SafeToInsert)-import Database.Persist.Names (EntityNameDB (..), FieldNameDB (..)) import Database.Persist.Sql import Eventium.Store.Class+import Eventium.Store.Sql.JSONString (JSONString, decodeJSON, encodeJSON) import Eventium.Store.Sql.Orphans as X () import Eventium.UUID data SqlEventStoreConfig entity serialized = SqlEventStoreConfig- { sqlEventStoreConfigSequenceMakeEntity :: UUID -> EventVersion -> serialized -> entity,+ { sequenceMakeEntity :: UUID -> EventVersion -> serialized -> Maybe JSONString -> entity, -- Key manipulation- sqlEventStoreConfigMakeKey :: SequenceNumber -> Key entity,- sqlEventStoreConfigUnKey :: Key entity -> SequenceNumber,+ makeKey :: SequenceNumber -> Key entity,+ unKey :: Key entity -> SequenceNumber, -- Record functions- sqlEventStoreConfigUUID :: entity -> UUID,- sqlEventStoreConfigVersion :: entity -> EventVersion,- sqlEventStoreConfigData :: entity -> serialized,+ uuid :: entity -> UUID,+ version :: entity -> EventVersion,+ payload :: entity -> serialized,+ metadata :: entity -> Maybe JSONString, -- EntityFields- sqlEventStoreConfigSequenceNumberField :: EntityField entity (Key entity),- sqlEventStoreConfigUUIDField :: EntityField entity UUID,- sqlEventStoreConfigVersionField :: EntityField entity EventVersion,- sqlEventStoreConfigDataField :: EntityField entity serialized+ sequenceNumberField :: EntityField entity (Key entity),+ uuidField :: EntityField entity UUID,+ versionField :: EntityField entity EventVersion,+ payloadField :: EntityField entity serialized,+ metadataField :: EntityField entity (Maybe JSONString) } sqlEventStoreReader ::@@ -62,82 +63,89 @@ SqlEventStoreConfig entity serialized -> Entity entity -> GlobalStreamEvent serialized-sqlEventToGlobalStream config@SqlEventStoreConfig {..} (Entity key event) =- StreamEvent () (sqlEventStoreConfigUnKey key) (sqlEventToVersioned config event)+sqlEventToGlobalStream config (Entity eKey event) =+ let versioned = sqlEventToVersioned config event+ in StreamEvent () (config.unKey eKey) versioned.metadata versioned +-- | Decode metadata from a stored JSONString. Returns empty metadata on NULL+-- or decode failure, ensuring events are always readable.+decodeMetadata :: Maybe JSONString -> EventMetadata+decodeMetadata = fromMaybe (emptyMetadata "") . (>>= decodeJSON)+ sqlEventToVersioned :: SqlEventStoreConfig entity serialized -> entity -> VersionedStreamEvent serialized-sqlEventToVersioned SqlEventStoreConfig {..} entity =+sqlEventToVersioned config entity = StreamEvent- (sqlEventStoreConfigUUID entity)- (sqlEventStoreConfigVersion entity)- (sqlEventStoreConfigData entity)+ (config.uuid entity)+ (config.version entity)+ (decodeMetadata $ config.metadata entity)+ (config.payload entity) sqlGetProjectionIds ::- (MonadIO m, PersistEntity entity, PersistEntityBackend entity ~ SqlBackend) =>+ (MonadIO m, PersistEntity entity) => SqlEventStoreConfig entity serialized -> SqlPersistT m [UUID]-sqlGetProjectionIds SqlEventStoreConfig {..} =+sqlGetProjectionIds config = fmap unSingle <$> rawSql ("SELECT DISTINCT " <> uuidFieldName <> " FROM " <> tableName) [] where- tableName = unEntityNameDB $ tableDBName (sqlEventStoreConfigSequenceMakeEntity nil 0 undefined)- uuidFieldName = unFieldNameDB $ fieldDBName sqlEventStoreConfigSequenceNumberField+ tableName = unEntityNameDB $ tableDBName (config.sequenceMakeEntity nil 0 undefined Nothing)+ uuidFieldName = unFieldNameDB $ fieldDBName config.uuidField sqlGetStreamEvents :: (MonadIO m, PersistEntity entity, PersistEntityBackend entity ~ SqlBackend) => SqlEventStoreConfig entity serialized -> QueryRange UUID EventVersion -> SqlPersistT m [VersionedStreamEvent serialized]-sqlGetStreamEvents config@SqlEventStoreConfig {..} QueryRange {..} = do+sqlGetStreamEvents config query = do entities <- selectList filters selectOpts return $ sqlEventToVersioned config . entityVal <$> entities where startFilter =- case queryRangeStart of+ case query.start of StartFromBeginning -> []- StartQueryAt start -> [sqlEventStoreConfigVersionField >=. start]+ StartQueryAt s -> [config.versionField >=. s] (endFilter, endSelectOpt) =- case queryRangeLimit of+ case query.limit of NoQueryLimit -> ([], []) MaxNumberOfEvents maxNum -> ([], [LimitTo maxNum])- StopQueryAt stop -> ([sqlEventStoreConfigVersionField <=. stop], [])- filters = (sqlEventStoreConfigUUIDField ==. queryRangeKey) : startFilter ++ endFilter- selectOpts = Asc sqlEventStoreConfigSequenceNumberField : endSelectOpt+ StopQueryAt stop -> ([config.versionField <=. stop], [])+ filters = (config.uuidField ==. query.key) : startFilter ++ endFilter+ selectOpts = Asc config.sequenceNumberField : endSelectOpt sqlGetAllEventsInRange :: (MonadIO m, PersistEntity entity, PersistEntityBackend entity ~ SqlBackend) => SqlEventStoreConfig entity serialized -> QueryRange () SequenceNumber -> SqlPersistT m [GlobalStreamEvent serialized]-sqlGetAllEventsInRange config@SqlEventStoreConfig {..} QueryRange {..} = do+sqlGetAllEventsInRange config query = do entities <- selectList filters selectOpts return $ sqlEventToGlobalStream config <$> entities where startFilter =- case queryRangeStart of+ case query.start of StartFromBeginning -> []- StartQueryAt start -> [sqlEventStoreConfigSequenceNumberField >=. sqlEventStoreConfigMakeKey start]+ StartQueryAt s -> [config.sequenceNumberField >=. config.makeKey s] (endFilter, endSelectOpt) =- case queryRangeLimit of+ case query.limit of NoQueryLimit -> ([], []) MaxNumberOfEvents maxNum -> ([], [LimitTo maxNum])- StopQueryAt stop -> ([sqlEventStoreConfigSequenceNumberField <=. sqlEventStoreConfigMakeKey stop], [])+ StopQueryAt stop -> ([config.sequenceNumberField <=. config.makeKey stop], []) filters = startFilter ++ endFilter- selectOpts = Asc sqlEventStoreConfigSequenceNumberField : endSelectOpt+ selectOpts = Asc config.sequenceNumberField : endSelectOpt sqlMaxEventVersion ::- (MonadIO m, PersistEntity entity, PersistEntityBackend entity ~ SqlBackend) =>+ (MonadIO m, PersistEntity entity) => SqlEventStoreConfig entity serialized -> (FieldNameDB -> FieldNameDB -> FieldNameDB -> Text) -> UUID -> SqlPersistT m EventVersion-sqlMaxEventVersion SqlEventStoreConfig {..} maxVersionSql uuid =- let tableName = FieldNameDB $ unEntityNameDB $ tableDBName (sqlEventStoreConfigSequenceMakeEntity nil 0 undefined)- uuidFieldName = fieldDBName sqlEventStoreConfigUUIDField- versionFieldName = fieldDBName sqlEventStoreConfigVersionField- rawVals = rawSql (maxVersionSql tableName uuidFieldName versionFieldName) [toPersistValue uuid]+sqlMaxEventVersion config maxVersionSql uid =+ let tableName = FieldNameDB $ unEntityNameDB $ tableDBName (config.sequenceMakeEntity nil 0 undefined Nothing)+ uuidFieldName = fieldDBName config.uuidField+ versionFieldName = fieldDBName config.versionField+ rawVals = rawSql (maxVersionSql tableName uuidFieldName versionFieldName) [toPersistValue uid] in maybe 0 unSingle . listToMaybe <$> rawVals sqlStoreEvents ::@@ -148,17 +156,46 @@ UUID -> [serialized] -> SqlPersistT m EventVersion-sqlStoreEvents config@SqlEventStoreConfig {..} mLockCommand maxVersionSql uuid events = do- versionNum <- sqlMaxEventVersion config maxVersionSql uuid- let entities = zipWith (sqlEventStoreConfigSequenceMakeEntity uuid) [versionNum + 1 ..] events+sqlStoreEvents config mLockCommand maxVersionSql uid events = do+ versionNum <- sqlMaxEventVersion config maxVersionSql uid+ let entities = zipWith (\v e -> config.sequenceMakeEntity uid v e Nothing) [versionNum + 1 ..] events -- NB: We need to take a lock on the events table or else the global sequence -- numbers may not increase monotonically over time. for_ mLockCommand $ \lockCommand -> rawExecute (lockCommand tableName) [] _ <- insertMany entities return $ versionNum + EventVersion (length events) where- tableName = unEntityNameDB $ tableDBName (sqlEventStoreConfigSequenceMakeEntity nil 0 undefined)+ tableName = unEntityNameDB $ tableDBName (config.sequenceMakeEntity nil 0 undefined Nothing) +-- | Like 'sqlStoreEvents' but accepts 'TaggedEvent's, using their metadata+-- for event type name, correlation ID, causation ID, and timestamp.+sqlStoreEventsTagged ::+ (MonadIO m, PersistEntity entity, PersistEntityBackend entity ~ SqlBackend, SafeToInsert entity) =>+ SqlEventStoreConfig entity serialized ->+ Maybe (Text -> Text) ->+ (FieldNameDB -> FieldNameDB -> FieldNameDB -> Text) ->+ UUID ->+ [TaggedEvent serialized] ->+ SqlPersistT m EventVersion+sqlStoreEventsTagged config mLockCommand maxVersionSql uid taggedEvents = do+ versionNum <- sqlMaxEventVersion config maxVersionSql uid+ let entities =+ zipWith+ ( \v (TaggedEvent meta e) ->+ config.sequenceMakeEntity+ uid+ v+ e+ (Just $ encodeJSON meta)+ )+ [versionNum + 1 ..]+ taggedEvents+ for_ mLockCommand $ \lockCommand -> rawExecute (lockCommand tableName) []+ _ <- insertMany entities+ return $ versionNum + EventVersion (length taggedEvents)+ where+ tableName = unEntityNameDB $ tableDBName (config.sequenceMakeEntity nil 0 undefined Nothing)+ -- | Useful if you have some 'GlobalStreamEvent's and you want to shove them in -- a SQL event store. This can happen when you are moving events between event -- stores, or you somehow generate the events outside of the current SQL event@@ -168,10 +205,15 @@ SqlEventStoreConfig entity serialized -> [GlobalStreamEvent serialized] -> SqlPersistT m ()-unsafeSqlStoreGlobalStreamEvents SqlEventStoreConfig {..} events =+unsafeSqlStoreGlobalStreamEvents config events = insertEntityMany $ fmap mkEventEntity events where- mkEventEntity (StreamEvent () seqNum (StreamEvent uuid vers event)) =+ mkEventEntity (StreamEvent () seqNum _ (StreamEvent uid vers meta evtPayload)) = Entity- (sqlEventStoreConfigMakeKey seqNum)- (sqlEventStoreConfigSequenceMakeEntity uuid vers event)+ (config.makeKey seqNum)+ ( config.sequenceMakeEntity+ uid+ vers+ evtPayload+ (Just $ encodeJSON meta)+ )
src/Eventium/Store/Sql/Orphans.hs view
@@ -6,7 +6,6 @@ ) where -import qualified Data.ByteString as BS import Data.Proxy import qualified Data.Text as T import qualified Data.Text.Encoding as TE@@ -24,8 +23,6 @@ Nothing -> Left "Invalid UUID" fromPersistValue (PersistByteString bs) = maybe (Left "Invalid UUID") Right (uuidFromText (TE.decodeUtf8 bs))- fromPersistValue (PersistDbSpecific bs) =- maybe (Left "Invalid UUID") Right (uuidFromText (TE.decodeUtf8 bs)) fromPersistValue (PersistLiteral_ _ bs) = maybe (Left "Invalid UUID") Right (uuidFromText (TE.decodeUtf8 bs)) fromPersistValue v = Left $ "Expected UUID-compatible PersistValue, got: " <> T.pack (show v)@@ -34,14 +31,14 @@ sqlType _ = SqlOther "uuid" instance PersistField EventVersion where- toPersistValue = toPersistValue . unEventVersion+ toPersistValue (EventVersion n) = toPersistValue n fromPersistValue = fmap EventVersion . fromPersistValue instance PersistFieldSql EventVersion where sqlType _ = sqlType (Proxy :: Proxy Int) instance PersistField SequenceNumber where- toPersistValue = toPersistValue . unSequenceNumber+ toPersistValue (SequenceNumber n) = toPersistValue n fromPersistValue = fmap SequenceNumber . fromPersistValue instance PersistFieldSql SequenceNumber where