packages feed

bolty-0.2.0.0: src/Database/Bolty/AccessMode.hs

-- | Access mode for Bolt transactions and routing.
--
-- The Bolt protocol carries a @mode@ field on BEGIN and RUN messages whose
-- only valid values are @"r"@ (read) and @"w"@ (write). This module hides
-- that wire shape behind a sum type so consumers can't construct invalid
-- modes, and so the read\/write distinction reads as data at use sites
-- (cluster routing, transaction primitives, session management).
--
-- The 'PackStream' instance is the single point where the wire encoding
-- lives: 'ReadAccess' \<-\> @"r"@, 'WriteAccess' \<-\> @"w"@.
module Database.Bolty.AccessMode
  ( AccessMode(..)
  ) where

import           Data.Kind            (Type)
import           Data.PackStream      (PackStream(..), Ps(..), Result(..), withString)
import           GHC.Generics         (Generic)


-- | Whether a transaction (or session connection) is intended for reading
-- or writing. The value flows to two distinct layers:
--
-- * Cluster routing (Session\/Routing layer): 'ReadAccess' picks a follower,
--   'WriteAccess' picks the leader. No-op on non-clustered connections.
-- * Per-transaction enforcement (BEGIN\/RUN @mode@): 'ReadAccess' instructs
--   the server to reject write attempts upfront (Neo4j 5+); 'WriteAccess'
--   is the default and allows writes.
type AccessMode :: Type
data AccessMode = ReadAccess | WriteAccess
  deriving stock (Show, Eq, Ord, Enum, Bounded, Generic)


-- | Wire format: a single-character PackStream string, @"r"@ or @"w"@.
-- @fromPs@ rejects any other string to preserve the invariant on decode.
instance PackStream AccessMode where
  toPs ReadAccess  = PsString "r"
  toPs WriteAccess = PsString "w"
  fromPs = withString "AccessMode" $ \t -> case t of
    "r" -> Success ReadAccess
    "w" -> Success WriteAccess
    _   -> Error ("expected mode \"r\" or \"w\", got: " <> t)