-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | empty -- -- empty @package avers @version 0.0.16 module Avers.TH -- | Generates both ToJSON and FromJSON instance declarations -- for the given data type or data family instance constructor. -- -- This is a convienience function which is equivalent to calling both -- deriveToJSON and deriveFromJSON. deriveJSON :: Options -> Name -> Q [Dec] deriveJSONOptions :: String -> Options variantOptions :: String -> String -> String -> Options defaultVariantOptions :: String -> Options deriveEncoding :: Options -> Name -> Q [Dec] deriveRecordEncoding :: Name -> String -> [(String, Q Exp)] -> Q [Dec] -- | A type that can be converted from JSON, with the possibility of -- failure. -- -- In many cases, you can get the compiler to generate parsing code for -- you (see below). To begin, let's cover writing an instance by hand. -- -- There are various reasons a conversion could fail. For example, an -- Object could be missing a required key, an Array could -- be of the wrong size, or a value could be of an incompatible type. -- -- The basic ways to signal a failed conversion are as follows: -- --
-- -- Allow ourselves to write Text literals.
-- {-# LANGUAGE OverloadedStrings #-}
--
-- data Coord = Coord { x :: Double, y :: Double }
--
-- instance FromJSON Coord where
-- parseJSON (Object v) = Coord <$>
-- v .: "x" <*>
-- v .: "y"
--
-- -- We do not expect a non-Object value here.
-- -- We could use mzero to fail, but typeMismatch
-- -- gives a much more informative error message.
-- parseJSON invalid = typeMismatch "Coord" invalid
--
--
-- Instead of manually writing your FromJSON instance, there are
-- two options to do it automatically:
--
--
-- {-# LANGUAGE DeriveGeneric #-}
--
-- import GHC.Generics
--
-- data Coord = Coord { x :: Double, y :: Double } deriving Generic
--
-- instance FromJSON Coord
--
--
-- If DefaultSignatures doesn't give exactly the results you
-- want, you can customize the generic decoding with only a tiny amount
-- of effort, using genericParseJSON with your preferred
-- Options:
--
-- -- instance FromJSON Coord where -- parseJSON = genericParseJSON defaultOptions --class FromJSON a parseJSON :: Value -> Parser a parseJSONList :: Value -> Parser [a] -- | A type that can be converted to JSON. -- -- An example type and instance: -- --
-- -- Allow ourselves to write Text literals.
-- {-# LANGUAGE OverloadedStrings #-}
--
-- data Coord = Coord { x :: Double, y :: Double }
--
-- instance ToJSON Coord where
-- toJSON (Coord x y) = object ["x" .= x, "y" .= y]
--
-- toEncoding (Coord x y) = pairs ("x" .= x <> "y" .= y)
--
--
-- Instead of manually writing your ToJSON instance, there are two
-- options to do it automatically:
--
--
-- {-# LANGUAGE DeriveGeneric #-}
--
-- import GHC.Generics
--
-- data Coord = Coord { x :: Double, y :: Double } deriving Generic
--
-- instance ToJSON Coord where
-- toEncoding = genericToEncoding defaultOptions
--
--
-- Why do we provide an implementation for toEncoding here? The
-- toEncoding function is a relatively new addition to this class.
-- To allow users of older versions of this library to upgrade without
-- having to edit all of their instances or encounter surprising
-- incompatibilities, the default implementation of toEncoding
-- uses toJSON. This produces correct results, but since it
-- performs an intermediate conversion to a Value, it will be less
-- efficient than directly emitting an Encoding. Our one-liner
-- definition of toEncoding above bypasses the intermediate
-- Value.
--
-- If DefaultSignatures doesn't give exactly the results you
-- want, you can customize the generic encoding with only a tiny amount
-- of effort, using genericToJSON and genericToEncoding
-- with your preferred Options:
--
-- -- instance ToJSON Coord where -- toJSON = genericToJSON defaultOptions -- toEncoding = genericToEncoding defaultOptions --class ToJSON a -- | Convert a Haskell value to a JSON-friendly intermediate type. toJSON :: a -> Value -- | Encode a Haskell value as JSON. -- -- The default implementation of this method creates an intermediate -- Value using toJSON. This provides source-level -- compatibility for people upgrading from older versions of this -- library, but obviously offers no performance advantage. -- -- To benefit from direct encoding, you must provide an -- implementation for this method. The easiest way to do so is by having -- your types implement Generic using the DeriveGeneric -- extension, and then have GHC generate a method body as follows. -- --
-- instance ToJSON Coord where -- toEncoding = genericToEncoding defaultOptions --toEncoding :: a -> Encoding toJSONList :: [a] -> Value toEncodingList :: [a] -> Encoding module Avers.Metrics.TH toLabels :: [String] -> [[String]] toMetrics :: [[String]] -> [[String]] mkMeasurements :: Q [Dec] module Avers.Metrics.Measurements data Measurement M_avers_storage_lookupObject_duration :: Measurement M_avers_storage_lookupSnapshot_duration :: Measurement M_avers_storage_lookupLatestSnapshot_duration :: Measurement M_avers_storage_newestSnapshot_duration :: Measurement M_avers_storage_patchesAfterRevision_duration :: Measurement M_avers_storage_lookupPatch_duration :: Measurement M_avers_storage_applyObjectUpdates_duration :: Measurement M_avers_storage_applyObjectUpdates_numOperations :: Measurement M_avers_storage_applyObjectUpdates_numPreviousPatches :: Measurement M_avers_storage_exists_duration :: Measurement measurementLabels :: Measurement -> [[Char]] module Avers.Index data Index a Index :: Text -> (Exp Object -> Exp a) -> Index a [indexName] :: Index a -> Text [indexExpression] :: Index a -> Exp Object -> Exp a data SomeIndex [SomeIndex] :: (IsDatum a) => Index a -> SomeIndex module Avers.Types -- | Pk - Types which can be converted to a database primary key. class Pk a toPk :: Pk a => a -> Text -- | Path newtype Path Path :: Text -> Path [unPath] :: Path -> Text -- | This path refers to the root of an object. It is only used in -- Set operations. rootPath :: Path -- | ObjId newtype ObjId ObjId :: Text -> ObjId [unObjId] :: ObjId -> Text -- | The root object id is used for object created internally or when there -- is no applicable creator. rootObjId :: ObjId -- | RevId newtype RevId RevId :: Int -> RevId [unRevId] :: RevId -> Int -- | The RevId which is used for the initial snapshot. zeroRevId :: RevId -- | ObjectId data ObjectId -- | The base object whose snapshots contain the actual content. BaseObjectId :: !ObjId -> ObjectId -- | An object describing a particualar release of the base object. ReleaseObjectId :: !ObjId -> !RevId -> ObjectId -- | Object which contains authorization rules. AuthorizationObjectId :: !ObjId -> ObjectId objectIdParser :: Parser ObjectId parseObjectId :: Text -> Maybe ObjectId objectIdBase :: ObjectId -> ObjId -- | The operations that can be applied to JSON values. data Operation -- | Set is applied to Objects. It is used for adding, updating and -- deleting properties from the object. Set :: !Path -> !(Maybe Value) -> Operation [opPath] :: Operation -> !Path [opValue] :: Operation -> !(Maybe Value) -- | Splice is used to manipulate Arrays. It can remove and insert -- multiple elements in a single operation. Splice :: !Path -> !Int -> !Int -> ![Value] -> Operation [opPath] :: Operation -> !Path [opIndex] :: Operation -> !Int [opRemove] :: Operation -> !Int [opInsert] :: Operation -> ![Value] data PatchError UnknownPatchError :: !Text -> PatchError type PatchM a = Either PatchError a data Object Object :: !ObjId -> !Text -> !UTCTime -> !ObjId -> !(Maybe Bool) -> Object [objectId] :: Object -> !ObjId [objectType] :: Object -> !Text [objectCreatedAt] :: Object -> !UTCTime [objectCreatedBy] :: Object -> !ObjId [objectDeleted] :: Object -> !(Maybe Bool) -- | Patch data Patch Patch :: !ObjectId -> !RevId -> !ObjId -> !UTCTime -> !Operation -> Patch [patchObjectId] :: Patch -> !ObjectId [patchRevisionId] :: Patch -> !RevId [patchAuthorId] :: Patch -> !ObjId [patchCreatedAt] :: Patch -> !UTCTime [patchOperation] :: Patch -> !Operation -- | Snapshot data Snapshot Snapshot :: !ObjectId -> !RevId -> !Value -> Snapshot [snapshotObjectId] :: Snapshot -> !ObjectId [snapshotRevisionId] :: Snapshot -> !RevId [snapshotContent] :: Snapshot -> !Value -- | The initial snapshot on top of which all future patches are applied. initialSnapshot :: ObjectId -> Snapshot -- | Release data Release Release :: Release -- | SecretId newtype SecretId SecretId :: Text -> SecretId [unSecretId] :: SecretId -> Text -- | Secret -- -- A Secret is a password (encrypted with scrypt) that is attached -- to a SecretId (for example the ObjId of an account). -- -- It is up to you to ensure that SecretIds are unique. If you use -- ObjIds then they by definition are. data Secret Secret :: !SecretId -> !Text -> Secret [secretId] :: Secret -> !SecretId [secretValue] :: Secret -> !Text -- | BlobId newtype BlobId BlobId :: Text -> BlobId [unBlobId] :: BlobId -> Text -- | Blob data Blob Blob :: !BlobId -> !Int -> !Text -> Blob [blobId] :: Blob -> !BlobId [blobSize] :: Blob -> !Int [blobContentType] :: Blob -> !Text -- | SessionId newtype SessionId SessionId :: Text -> SessionId [unSessionId] :: SessionId -> Text -- | The session record that is stored in the database. -- -- A session is a unique identifier attached to a particular object. It -- contains the creation date and when it was last accessed. If you need -- to store additional data for a session, we recommend to use cookies. data Session Session :: !SessionId -> !ObjId -> !UTCTime -> !UTCTime -> Session [sessionId] :: Session -> !SessionId [sessionObjId] :: Session -> !ObjId [sessionCreatedAt] :: Session -> !UTCTime [sessionLastAccessedAt] :: Session -> !UTCTime data AversError InternalError :: !AversError -> AversError DatabaseError :: !Text -> AversError PatchError :: !PatchError -> AversError ParseError :: !Value -> !Text -> AversError UnknownObjectType :: !Text -> AversError ObjectNotFound :: !ObjId -> AversError DocumentNotFound :: !Text -> AversError AversError :: !Text -> AversError NotAuthorized :: AversError internalError :: AversError -> Avers a internal :: Avers a -> Avers a databaseError :: Text -> Avers a patchError :: PatchError -> Avers a parseError :: (MonadError AversError m) => Value -> Text -> m a documentNotFound :: Text -> Avers a strErr :: String -> Avers a -- | An ObjectType describes a particular type of object that is -- managed by Avers. data ObjectType a ObjectType :: !Text -> Avers ObjId -> [SomeView a] -> ObjectType a -- | The value of the type field of the Object. [otType] :: ObjectType a -> !Text -- | Action which generates a new id. This is so that object types can have -- different strategies how to generate ids. [otId] :: ObjectType a -> Avers ObjId [otViews] :: ObjectType a -> [SomeView a] data SomeObjectType [SomeObjectType] :: (ToDatum a, FromDatum a, FromJSON a, ToJSON a) => ObjectType a -> SomeObjectType parseValueAs :: (FromJSON a) => ObjectType a -> Value -> Either AversError a -- | Configuration of the Avers monad. data Config Config :: !URI -> (BlobId -> Text -> ByteString -> IO (Either AversError ())) -> ![SomeObjectType] -> (Measurement -> Double -> IO ()) -> Config -- | URI which describes the connection details to the RethinkDB -- database. The URI *MUST* include at least the hostname -- (uriRegName) and database name (uriPath without the -- leading slash). The port (uriPort) and credentials -- (uriUserInfo) *MAY* be left empty. in that case the default -- port will be used. [databaseURI] :: Config -> !URI -- | Function which saves the given blob in the blob store. This can be the -- local filesystem or an external service such as Amazon S3. [putBlob] :: Config -> BlobId -> Text -> ByteString -> IO (Either AversError ()) -- | All the object types which Avers knows about. [objectTypes] :: Config -> ![SomeObjectType] -- | This is called when the internal instrumentation code creates a -- measurement. [emitMeasurement] :: Config -> Measurement -> Double -> IO () -- | A change in the system, for example a new object, patch, release, blob -- etc. data Change -- | A new patch was created. CPatch :: !Patch -> Change data Handle Handle :: !Config -> !(Pool Handle) -> !(TVar (Map ObjectId RevId)) -> !(TChan Change) -> Handle -- | A reference to the config, just in case we need it. [hConfig] :: Handle -> !Config -- | A pool of handles which are used to access the database. [hDatabaseHandlePool] :: Handle -> !(Pool Handle) -- | Map from ObjectId to a recent RevId. It may be the -- latest or a few revisions behind. [hRecentRevisionCache] :: Handle -> !(TVar (Map ObjectId RevId)) -- | Changes in the system (new patches, objects, releases etc), even those -- created through other handles, are streamed into this channel. If you -- want to be informed of those changes, duplicate the channel and read -- from the copy. [hChanges] :: Handle -> !(TChan Change) newtype Avers a Avers :: StateT Handle (ExceptT AversError IO) a -> Avers a [runAvers] :: Avers a -> StateT Handle (ExceptT AversError IO) a class (Monad m) => MonadAvers m liftAvers :: MonadAvers m => Avers a -> m a evalAvers :: Handle -> Avers a -> IO (Either AversError a) data View obj a View :: Text -> (Datum -> Either AversError a) -> (obj -> Avers (Maybe a)) -> [SomeIndex] -> View obj a -- | The table name is derived from the view name. Therefore it should be -- unique amongst all views. [viewName] :: View obj a -> Text -- | Function which parses objects stored in this view. [viewParser] :: View obj a -> Datum -> Either AversError a -- | Function which transforms an Avers Object into a type stored in the -- view. [viewObjectTransformer] :: View obj a -> obj -> Avers (Maybe a) -- | Secondary indices defined on the view. [viewIndices] :: View obj a -> [SomeIndex] data SomeView obj [SomeView] :: (ToDatum a, FromDatum a, FromJSON obj, ToJSON a) => View obj a -> SomeView obj instance Control.Monad.State.Class.MonadState Avers.Types.Handle Avers.Types.Avers instance Control.Monad.Error.Class.MonadError Avers.Types.AversError Avers.Types.Avers instance Control.Monad.IO.Class.MonadIO Avers.Types.Avers instance GHC.Base.Monad Avers.Types.Avers instance GHC.Base.Applicative Avers.Types.Avers instance GHC.Base.Functor Avers.Types.Avers instance GHC.Generics.Generic Avers.Types.Change instance GHC.Show.Show Avers.Types.Change instance GHC.Generics.Generic Avers.Types.AversError instance GHC.Show.Show Avers.Types.AversError instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.Session instance Data.Aeson.Types.FromJSON.FromJSON Avers.Types.Session instance Database.RethinkDB.Types.Datum.ToDatum Avers.Types.Session instance Database.RethinkDB.Types.Datum.FromDatum Avers.Types.Session instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.Change instance Avers.Types.MonadAvers Avers.Types.Avers instance Avers.Types.MonadAvers m => Avers.Types.MonadAvers (Control.Monad.Trans.State.Lazy.StateT s m) instance GHC.Generics.Generic Avers.Types.Session instance GHC.Generics.Generic Avers.Types.SessionId instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.Blob instance Data.Aeson.Types.FromJSON.FromJSON Avers.Types.Blob instance Database.RethinkDB.Types.Datum.ToDatum Avers.Types.Blob instance Database.RethinkDB.Types.Datum.FromDatum Avers.Types.Blob instance Avers.Types.Pk Avers.Types.SessionId instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.SessionId instance Data.Aeson.Types.FromJSON.FromJSON Avers.Types.SessionId instance Database.RethinkDB.Types.Datum.FromDatum Avers.Types.SessionId instance Database.RethinkDB.Types.Datum.ToDatum Avers.Types.SessionId instance Avers.Types.Pk Avers.Types.Session instance GHC.Generics.Generic Avers.Types.Blob instance GHC.Show.Show Avers.Types.Blob instance GHC.Generics.Generic Avers.Types.BlobId instance GHC.Show.Show Avers.Types.BlobId instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.Secret instance Data.Aeson.Types.FromJSON.FromJSON Avers.Types.Secret instance Database.RethinkDB.Types.Datum.ToDatum Avers.Types.Secret instance Database.RethinkDB.Types.Datum.FromDatum Avers.Types.Secret instance Avers.Types.Pk Avers.Types.BlobId instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.BlobId instance Data.Aeson.Types.FromJSON.FromJSON Avers.Types.BlobId instance Database.RethinkDB.Types.Datum.FromDatum Avers.Types.BlobId instance Database.RethinkDB.Types.Datum.ToDatum Avers.Types.BlobId instance Avers.Types.Pk Avers.Types.Blob instance GHC.Generics.Generic Avers.Types.Secret instance GHC.Generics.Generic Avers.Types.SecretId instance GHC.Show.Show Avers.Types.SecretId instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.Snapshot instance Data.Aeson.Types.FromJSON.FromJSON Avers.Types.Snapshot instance Database.RethinkDB.Types.Datum.ToDatum Avers.Types.Snapshot instance Database.RethinkDB.Types.Datum.FromDatum Avers.Types.Snapshot instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.Release instance Data.Aeson.Types.FromJSON.FromJSON Avers.Types.Release instance Avers.Types.Pk Avers.Types.SecretId instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.SecretId instance Data.Aeson.Types.FromJSON.FromJSON Avers.Types.SecretId instance Database.RethinkDB.Types.Datum.FromDatum Avers.Types.SecretId instance Database.RethinkDB.Types.Datum.ToDatum Avers.Types.SecretId instance Avers.Types.Pk Avers.Types.Secret instance GHC.Generics.Generic Avers.Types.Snapshot instance GHC.Show.Show Avers.Types.Snapshot instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.Patch instance Data.Aeson.Types.FromJSON.FromJSON Avers.Types.Patch instance Database.RethinkDB.Types.Datum.ToDatum Avers.Types.Patch instance Database.RethinkDB.Types.Datum.FromDatum Avers.Types.Patch instance Avers.Types.Pk Avers.Types.Snapshot instance GHC.Generics.Generic Avers.Types.Patch instance GHC.Show.Show Avers.Types.Patch instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.Object instance Data.Aeson.Types.FromJSON.FromJSON Avers.Types.Object instance Database.RethinkDB.Types.Datum.ToDatum Avers.Types.Object instance Database.RethinkDB.Types.Datum.FromDatum Avers.Types.Object instance Avers.Types.Pk Avers.Types.Patch instance GHC.Generics.Generic Avers.Types.Object instance GHC.Show.Show Avers.Types.Object instance GHC.Generics.Generic Avers.Types.PatchError instance GHC.Show.Show Avers.Types.PatchError instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.Operation instance Data.Aeson.Types.FromJSON.FromJSON Avers.Types.Operation instance Database.RethinkDB.Types.Datum.ToDatum Avers.Types.Operation instance Database.RethinkDB.Types.Datum.FromDatum Avers.Types.Operation instance Avers.Types.Pk Avers.Types.Object instance GHC.Generics.Generic Avers.Types.Operation instance GHC.Show.Show Avers.Types.Operation instance GHC.Classes.Eq Avers.Types.Operation instance GHC.Generics.Generic Avers.Types.ObjectId instance GHC.Show.Show Avers.Types.ObjectId instance GHC.Classes.Ord Avers.Types.ObjectId instance GHC.Classes.Eq Avers.Types.ObjectId instance GHC.Generics.Generic Avers.Types.RevId instance GHC.Show.Show Avers.Types.RevId instance GHC.Classes.Ord Avers.Types.RevId instance GHC.Classes.Eq Avers.Types.RevId instance GHC.Generics.Generic Avers.Types.ObjId instance GHC.Show.Show Avers.Types.ObjId instance GHC.Classes.Ord Avers.Types.ObjId instance GHC.Classes.Eq Avers.Types.ObjId instance GHC.Generics.Generic Avers.Types.Path instance GHC.Show.Show Avers.Types.Path instance GHC.Classes.Ord Avers.Types.Path instance GHC.Classes.Eq Avers.Types.Path instance Avers.Types.Pk Data.Text.Internal.Text instance Data.String.IsString Avers.Types.Path instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.Path instance Data.Aeson.Types.FromJSON.FromJSON Avers.Types.Path instance Database.RethinkDB.Types.Datum.FromDatum Avers.Types.Path instance Database.RethinkDB.Types.Datum.ToDatum Avers.Types.Path instance Avers.Types.Pk Avers.Types.ObjId instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.ObjId instance Data.Aeson.Types.FromJSON.FromJSON Avers.Types.ObjId instance Database.RethinkDB.Types.Datum.FromDatum Avers.Types.ObjId instance Database.RethinkDB.Types.Datum.ToDatum Avers.Types.ObjId instance GHC.Enum.Enum Avers.Types.RevId instance Avers.Types.Pk Avers.Types.RevId instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.RevId instance Data.Aeson.Types.FromJSON.FromJSON Avers.Types.RevId instance Database.RethinkDB.Types.Datum.FromDatum Avers.Types.RevId instance Database.RethinkDB.Types.Datum.ToDatum Avers.Types.RevId instance Avers.Types.Pk Avers.Types.ObjectId instance Data.Aeson.Types.ToJSON.ToJSON Avers.Types.ObjectId instance Data.Aeson.Types.FromJSON.FromJSON Avers.Types.ObjectId instance Database.RethinkDB.Types.Datum.FromDatum Avers.Types.ObjectId instance Database.RethinkDB.Types.Datum.ToDatum Avers.Types.ObjectId module Avers.Metrics measureDuration :: Measurement -> Avers a -> Avers a reportMeasurement :: Measurement -> Double -> Avers () module Avers.Patching -- | Apply the given op on the value. Can throw an exception if the -- operation is invalid. applyOperation :: Value -> Operation -> PatchM Value opOT :: Value -> Operation -> Operation -> Maybe Operation -- | Given an Operation which was created against a particular -- Value (content), rebase it on top of patches which were created -- against the very same content in parallel. -- -- This function assumes that the patches apply cleanly to the content. -- Failure to do so results in a fatal error. rebaseOperation :: Value -> Operation -> [Patch] -> Maybe Operation -- | Resolve the path in the object. resolvePathIn :: Path -> Value -> Maybe Value -- | This module contains RethinkDB Expressions which are used to build -- queries. module Avers.Storage.Expressions objectsTable :: Exp Table sessionsTable :: Exp Table snapshotsTable :: Exp Table patchesTable :: Exp Table secretsTable :: Exp Table blobsTable :: Exp Table -- | The primary key in all our documents is the default "id". primaryKeyField :: Text -- | Expression which represents the primary key field. primaryKeyFieldE :: Exp Text -- | Expression which represents the value of a field inside of an Object. objectFieldE :: (IsDatum a) => Text -> Exp Object -> Exp a -- | True if the object field matches the given value. objectFieldEqE :: (ToDatum a) => Text -> a -> Exp Object -> Exp Bool -- | True if the object's primary key matches the given string. primaryKeyEqE :: Text -> Exp Object -> Exp Bool -- | Take the first item out of a sequence. Beware that this throws an -- error when the sequence is empty. headE :: (IsSequence a, IsDatum r) => Exp a -> Exp r -- | Limit a sequence to the first n items. limitE :: (IsSequence s) => Int -> Exp s -> Exp s mkBounds :: ObjectId -> Int -> Int -> (Bound, Bound) mkBound :: ObjectId -> Int -> Bound objectSnapshotSequenceE :: ObjectId -> Int -> Int -> Exp Table objectPatchSequenceE :: ObjectId -> Int -> Int -> Exp Table -- | Low-level implementation of the storage backend. module Avers.Storage.Backend parseValue :: (FromJSON a, MonadError AversError m) => Value -> m a parseDatum :: (FromDatum a, MonadError AversError m) => Datum -> m a runQuery :: (FromResponse (Result a)) => Exp a -> Avers (Result a) runQueryDatum :: (FromDatum a) => Exp Datum -> Avers a runQuerySingleSelection :: (FromDatum a) => Exp SingleSelection -> Avers a runQueryCollect :: (FromDatum a, IsSequence e, Result e ~ Sequence a) => Exp e -> Avers (Vector a) existsDocument :: (Pk k) => Exp Table -> k -> Avers Bool lookupDocument :: (Pk k, FromDatum a) => Exp Table -> k -> Avers (Maybe a) insertDocument :: (ToDatum a, Pk a) => Exp Table -> a -> Avers () upsertDocument :: (ToDatum a, Pk a) => Exp Table -> a -> Avers () deleteDocument :: (Pk k) => Exp Table -> k -> Avers () instance Database.RethinkDB.Types.Datum.ToDatum Avers.Storage.Backend.WriteResponse instance Database.RethinkDB.Types.Datum.FromDatum Avers.Storage.Backend.WriteResponse instance GHC.Show.Show Avers.Storage.Backend.WriteResponse module Avers.Views viewTableName :: View obj a -> Text -- | Construct the table name for the given view. The table names look -- something like this: "view_openGames" viewTable :: View obj a -> Exp Table data Record a Record :: ObjId -> a -> Record a [recId] :: Record a -> ObjId [recContent] :: Record a -> a updateObjectViews :: ObjectType a -> ObjId -> Maybe a -> Avers () updateView :: (ToDatum a) => View obj a -> ObjId -> Maybe obj -> Avers () instance Avers.Types.Pk (Avers.Views.Record a) instance Data.Aeson.Types.ToJSON.ToJSON a => Data.Aeson.Types.ToJSON.ToJSON (Avers.Views.Record a) instance Database.RethinkDB.Types.Datum.ToDatum a => Database.RethinkDB.Types.Datum.ToDatum (Avers.Views.Record a) -- | This module abstracts the storage engine and provides functions to -- manipulate objects stored in it. module Avers.Storage requireResult :: AversError -> Maybe a -> Avers a -- | True if the object exists. exists :: ObjId -> Avers Bool -- | Lookup an Object by its ObjId. Throws -- ObjectNotFound if the object doesn't exist. lookupObject :: ObjId -> Avers Object -- | Create a new object of the given type. An initial snapshot -- (RevId 0) is created from the supplied content. createObject :: (ToJSON a) => ObjectType a -> ObjId -> a -> Avers ObjId -- | A more low-level version of createObject, for use when you want -- to generate your own ObjId or create objects at a specific time. createObject' :: (ToJSON a) => ObjId -> UTCTime -> ObjectType a -> ObjId -> a -> Avers () -- | Mark the object as deleted. deleteObject :: ObjId -> Avers () -- | Prune the object from the database. This is only allowed if the object -- is marked as deleted. Note that this is a very dangerous operation, it -- can not be undone. -- -- TODO: Prune related Release and Authoriation objects. pruneObject :: ObjId -> Avers () -- | Create a checkpoint for for the given object. All patches (and of -- course snapshots) before the checkpoint can be dropped. Use -- vacuumObject to do that. createCheckpoint :: ObjectId -> ObjId -> Avers RevId isCheckpointPatch :: Patch -> Bool latestCheckpointPatch :: ObjectId -> Avers (Maybe Patch) -- | Drop all patches and snapshots before the most recent checkpoint. This -- effectively drops the object's history, and frees space in the -- database. vacuumObject :: ObjectId -> Avers () -- | Fetch the content of the object and try to parse it. -- -- This function will fail with a ParseError if the content can -- not be decoded into the desired type. objectContent :: (FromJSON a) => ObjectId -> Avers a -- | Get the snapshot of the newest revision of the given object. lookupLatestSnapshot :: ObjectId -> Avers Snapshot applyPatchToSnapshot :: Snapshot -> Patch -> Avers Snapshot applyPatches :: Snapshot -> [Patch] -> Avers Snapshot lookupRecentRevision :: ObjectId -> Avers (Maybe RevId) updateRecentRevision :: ObjectId -> RevId -> Avers () -- | Lookup the latest snapshot within the given range. The bounds are -- inclusive. latestSnapshotBetween :: ObjectId -> Int -> Int -> Avers Snapshot -- | Get the newest snapshot which is stored in the database. The object -- may be at a higher revision if the later snapshots are missing from -- the database. -- -- This is an internal function. If you want the latest snapshot, you -- should use lookupLatestSnapshot. newestSnapshot :: ObjectId -> Avers Snapshot -- | Lookup the snapshot at a particular revision. lookupSnapshot :: ObjectId -> RevId -> Avers Snapshot savePatch :: Patch -> Avers () saveSnapshot :: Snapshot -> Avers () updateSecret :: SecretId -> Text -> Avers () -- | Verify the value against the secret. If that fails, then this function -- throws an error. -- -- This function automatically updates the secret in the database if the -- scrypt params have changed. verifySecret :: SecretId -> Text -> Avers () -- | Internal function which actually saves a secret in the database. saveSecretValue :: SecretId -> EncryptedPass -> Avers () objectPatches :: ObjectId -> Avers [Patch] patchesAfterRevision :: ObjectId -> RevId -> Avers [Patch] lookupPatch :: ObjectId -> RevId -> Avers Patch -- | Lookup an object type which is registered in the Avers monad. lookupObjectType :: Text -> Avers SomeObjectType applyObjectUpdates :: ObjectId -> RevId -> ObjId -> [Operation] -> Bool -> Avers ([Patch], Int, [Patch]) data PatchState a PatchState :: ObjectType a -> ObjectId -> RevId -> ObjId -> [Operation] -> Int -> Snapshot -> Snapshot -> [Patch] -> [Patch] -> PatchState a [psObjectType] :: PatchState a -> ObjectType a [psObjectId] :: PatchState a -> ObjectId [psRevisionId] :: PatchState a -> RevId [psCommitterId] :: PatchState a -> ObjId [psOperations] :: PatchState a -> [Operation] [psNumConsumedOperations] :: PatchState a -> Int [psBaseSnapshot] :: PatchState a -> Snapshot [psLatestSnapshot] :: PatchState a -> Snapshot [psPreviousPatches] :: PatchState a -> [Patch] [psPatches] :: PatchState a -> [Patch] type AversPatch a b = StateT (PatchState a) Avers b patchHandler :: (FromJSON a) => Bool -> AversPatch a Snapshot existsBlob :: BlobId -> Avers Bool lookupBlob :: BlobId -> Avers Blob insertBlob :: Blob -> Avers () saveBlobContent :: Blob -> ByteString -> Avers () saveSession :: Session -> Avers () lookupSession :: SessionId -> Avers Session dropSession :: SessionId -> Avers () newId :: Int -> IO Text validateObject :: Text -> Value -> Avers () validateWithType :: (FromJSON a) => ObjectType a -> Value -> Avers () lookupRelease :: ObjId -> RevId -> Avers Release -- | Create a new release of the given revision. If the object doesn't -- exist, it will fail with ObjectNotFound. createRelease :: ObjId -> RevId -> Avers () lookupLatestRelease :: ObjId -> Avers (Maybe RevId) createBlob :: ByteString -> Text -> Avers Blob objectsOfType :: ObjectType a -> Avers (Vector ObjId) allObjectsOfType :: ObjectType a -> Avers (Vector ObjId) isNotDeleted :: Exp Object -> Exp Bool mapId :: Exp Object -> Exp Text -- | Bootstrap the Avers handle: Create necessary tables, indexes, views -- etc. This operation is idempotent. indexF :: Exp Object -> Exp (Array Datum) bootstrap :: Avers () createTable :: Text -> [SomeIndex] -> Avers () -- | Stream new patches from the database into the channel. streamPatches :: Pool Handle -> TChan Change -> IO () -- | Return a TChan to which all changes in the system are streamed. -- Make sure to continuously drain items from the TChan, otherwise -- they will accumulate in memory and you will run OOM eventually. -- -- Do not write into the channel! changeChannel :: Handle -> IO (TChan Change) module Avers.Handle newHandle :: Config -> IO (Either AversError Handle) -- | Deprecated: Use newHandle instead newState :: Config -> IO (Either AversError Handle) module Avers data Avers a evalAvers :: Handle -> Avers a -> IO (Either AversError a) -- | Path newtype Path Path :: Text -> Path [unPath] :: Path -> Text -- | Pk - Types which can be converted to a database primary key. class Pk a toPk :: Pk a => a -> Text -- | ObjId newtype ObjId ObjId :: Text -> ObjId [unObjId] :: ObjId -> Text -- | The root object id is used for object created internally or when there -- is no applicable creator. rootObjId :: ObjId -- | RevId newtype RevId RevId :: Int -> RevId [unRevId] :: RevId -> Int -- | The RevId which is used for the initial snapshot. zeroRevId :: RevId -- | ObjectId data ObjectId -- | The base object whose snapshots contain the actual content. BaseObjectId :: !ObjId -> ObjectId -- | An object describing a particualar release of the base object. ReleaseObjectId :: !ObjId -> !RevId -> ObjectId -- | Object which contains authorization rules. AuthorizationObjectId :: !ObjId -> ObjectId -- | The operations that can be applied to JSON values. data Operation -- | Set is applied to Objects. It is used for adding, updating and -- deleting properties from the object. Set :: !Path -> !(Maybe Value) -> Operation [opPath] :: Operation -> !Path [opValue] :: Operation -> !(Maybe Value) -- | Splice is used to manipulate Arrays. It can remove and insert -- multiple elements in a single operation. Splice :: !Path -> !Int -> !Int -> ![Value] -> Operation [opPath] :: Operation -> !Path [opIndex] :: Operation -> !Int [opRemove] :: Operation -> !Int [opInsert] :: Operation -> ![Value] data Object Object :: !ObjId -> !Text -> !UTCTime -> !ObjId -> !(Maybe Bool) -> Object [objectId] :: Object -> !ObjId [objectType] :: Object -> !Text [objectCreatedAt] :: Object -> !UTCTime [objectCreatedBy] :: Object -> !ObjId [objectDeleted] :: Object -> !(Maybe Bool) -- | True if the object exists. exists :: ObjId -> Avers Bool -- | Create a new object of the given type. An initial snapshot -- (RevId 0) is created from the supplied content. createObject :: (ToJSON a) => ObjectType a -> ObjId -> a -> Avers ObjId -- | A more low-level version of createObject, for use when you want -- to generate your own ObjId or create objects at a specific time. createObject' :: (ToJSON a) => ObjId -> UTCTime -> ObjectType a -> ObjId -> a -> Avers () -- | Lookup an Object by its ObjId. Throws -- ObjectNotFound if the object doesn't exist. lookupObject :: ObjId -> Avers Object -- | Mark the object as deleted. deleteObject :: ObjId -> Avers () -- | Prune the object from the database. This is only allowed if the object -- is marked as deleted. Note that this is a very dangerous operation, it -- can not be undone. -- -- TODO: Prune related Release and Authoriation objects. pruneObject :: ObjId -> Avers () objectsOfType :: ObjectType a -> Avers (Vector ObjId) allObjectsOfType :: ObjectType a -> Avers (Vector ObjId) -- | Create a checkpoint for for the given object. All patches (and of -- course snapshots) before the checkpoint can be dropped. Use -- vacuumObject to do that. createCheckpoint :: ObjectId -> ObjId -> Avers RevId -- | Drop all patches and snapshots before the most recent checkpoint. This -- effectively drops the object's history, and frees space in the -- database. vacuumObject :: ObjectId -> Avers () -- | Patch data Patch Patch :: !ObjectId -> !RevId -> !ObjId -> !UTCTime -> !Operation -> Patch [patchObjectId] :: Patch -> !ObjectId [patchRevisionId] :: Patch -> !RevId [patchAuthorId] :: Patch -> !ObjId [patchCreatedAt] :: Patch -> !UTCTime [patchOperation] :: Patch -> !Operation data PatchError UnknownPatchError :: !Text -> PatchError lookupPatch :: ObjectId -> RevId -> Avers Patch -- | Snapshot data Snapshot Snapshot :: !ObjectId -> !RevId -> !Value -> Snapshot [snapshotObjectId] :: Snapshot -> !ObjectId [snapshotRevisionId] :: Snapshot -> !RevId [snapshotContent] :: Snapshot -> !Value -- | Get the snapshot of the newest revision of the given object. lookupLatestSnapshot :: ObjectId -> Avers Snapshot -- | Fetch the content of the object and try to parse it. -- -- This function will fail with a ParseError if the content can -- not be decoded into the desired type. objectContent :: (FromJSON a) => ObjectId -> Avers a -- | Release data Release Release :: Release lookupRelease :: ObjId -> RevId -> Avers Release -- | Create a new release of the given revision. If the object doesn't -- exist, it will fail with ObjectNotFound. createRelease :: ObjId -> RevId -> Avers () lookupLatestRelease :: ObjId -> Avers (Maybe RevId) -- | Resolve the path in the object. resolvePathIn :: Path -> Value -> Maybe Value -- | SessionId newtype SessionId SessionId :: Text -> SessionId [unSessionId] :: SessionId -> Text -- | The session record that is stored in the database. -- -- A session is a unique identifier attached to a particular object. It -- contains the creation date and when it was last accessed. If you need -- to store additional data for a session, we recommend to use cookies. data Session Session :: !SessionId -> !ObjId -> !UTCTime -> !UTCTime -> Session [sessionId] :: Session -> !SessionId [sessionObjId] :: Session -> !ObjId [sessionCreatedAt] :: Session -> !UTCTime [sessionLastAccessedAt] :: Session -> !UTCTime saveSession :: Session -> Avers () lookupSession :: SessionId -> Avers Session dropSession :: SessionId -> Avers () -- | An ObjectType describes a particular type of object that is -- managed by Avers. data ObjectType a ObjectType :: !Text -> Avers ObjId -> [SomeView a] -> ObjectType a -- | The value of the type field of the Object. [otType] :: ObjectType a -> !Text -- | Action which generates a new id. This is so that object types can have -- different strategies how to generate ids. [otId] :: ObjectType a -> Avers ObjId [otViews] :: ObjectType a -> [SomeView a] data SomeObjectType [SomeObjectType] :: (ToDatum a, FromDatum a, FromJSON a, ToJSON a) => ObjectType a -> SomeObjectType -- | Lookup an object type which is registered in the Avers monad. lookupObjectType :: Text -> Avers SomeObjectType data AversError InternalError :: !AversError -> AversError DatabaseError :: !Text -> AversError PatchError :: !PatchError -> AversError ParseError :: !Value -> !Text -> AversError UnknownObjectType :: !Text -> AversError ObjectNotFound :: !ObjId -> AversError DocumentNotFound :: !Text -> AversError AversError :: !Text -> AversError NotAuthorized :: AversError -- | Configuration of the Avers monad. data Config Config :: !URI -> (BlobId -> Text -> ByteString -> IO (Either AversError ())) -> ![SomeObjectType] -> (Measurement -> Double -> IO ()) -> Config -- | URI which describes the connection details to the RethinkDB -- database. The URI *MUST* include at least the hostname -- (uriRegName) and database name (uriPath without the -- leading slash). The port (uriPort) and credentials -- (uriUserInfo) *MAY* be left empty. in that case the default -- port will be used. [databaseURI] :: Config -> !URI -- | Function which saves the given blob in the blob store. This can be the -- local filesystem or an external service such as Amazon S3. [putBlob] :: Config -> BlobId -> Text -> ByteString -> IO (Either AversError ()) -- | All the object types which Avers knows about. [objectTypes] :: Config -> ![SomeObjectType] -- | This is called when the internal instrumentation code creates a -- measurement. [emitMeasurement] :: Config -> Measurement -> Double -> IO () data Handle newHandle :: Config -> IO (Either AversError Handle) -- | Deprecated: Use newHandle instead newState :: Config -> IO (Either AversError Handle) strErr :: String -> Avers a parseValueAs :: (FromJSON a) => ObjectType a -> Value -> Either AversError a bootstrap :: Avers () -- | BlobId newtype BlobId BlobId :: Text -> BlobId [unBlobId] :: BlobId -> Text -- | Blob data Blob Blob :: !BlobId -> !Int -> !Text -> Blob [blobId] :: Blob -> !BlobId [blobSize] :: Blob -> !Int [blobContentType] :: Blob -> !Text createBlob :: ByteString -> Text -> Avers Blob lookupBlob :: BlobId -> Avers Blob -- | SecretId newtype SecretId SecretId :: Text -> SecretId [unSecretId] :: SecretId -> Text -- | Secret -- -- A Secret is a password (encrypted with scrypt) that is attached -- to a SecretId (for example the ObjId of an account). -- -- It is up to you to ensure that SecretIds are unique. If you use -- ObjIds then they by definition are. data Secret Secret :: !SecretId -> !Text -> Secret [secretId] :: Secret -> !SecretId [secretValue] :: Secret -> !Text updateSecret :: SecretId -> Text -> Avers () -- | Verify the value against the secret. If that fails, then this function -- throws an error. -- -- This function automatically updates the secret in the database if the -- scrypt params have changed. verifySecret :: SecretId -> Text -> Avers () applyObjectUpdates :: ObjectId -> RevId -> ObjId -> [Operation] -> Bool -> Avers ([Patch], Int, [Patch]) runQuery :: (FromResponse (Result a)) => Exp a -> Avers (Result a) runQueryCollect :: (FromDatum a, IsSequence e, Result e ~ Sequence a) => Exp e -> Avers (Vector a) parseValue :: (FromJSON a, MonadError AversError m) => Value -> m a parseDatum :: (FromDatum a, MonadError AversError m) => Datum -> m a newId :: Int -> IO Text objectsTable :: Exp Table blobsTable :: Exp Table validateObject :: Text -> Value -> Avers () data View obj a View :: Text -> (Datum -> Either AversError a) -> (obj -> Avers (Maybe a)) -> [SomeIndex] -> View obj a -- | The table name is derived from the view name. Therefore it should be -- unique amongst all views. [viewName] :: View obj a -> Text -- | Function which parses objects stored in this view. [viewParser] :: View obj a -> Datum -> Either AversError a -- | Function which transforms an Avers Object into a type stored in the -- view. [viewObjectTransformer] :: View obj a -> obj -> Avers (Maybe a) -- | Secondary indices defined on the view. [viewIndices] :: View obj a -> [SomeIndex] data SomeView obj [SomeView] :: (ToDatum a, FromDatum a, FromJSON obj, ToJSON a) => View obj a -> SomeView obj -- | Construct the table name for the given view. The table names look -- something like this: "view_openGames" viewTable :: View obj a -> Exp Table updateView :: (ToDatum a) => View obj a -> ObjId -> Maybe obj -> Avers () data Index a Index :: Text -> (Exp Object -> Exp a) -> Index a [indexName] :: Index a -> Text [indexExpression] :: Index a -> Exp Object -> Exp a data SomeIndex [SomeIndex] :: (IsDatum a) => Index a -> SomeIndex data Measurement M_avers_storage_lookupObject_duration :: Measurement M_avers_storage_lookupSnapshot_duration :: Measurement M_avers_storage_lookupLatestSnapshot_duration :: Measurement M_avers_storage_newestSnapshot_duration :: Measurement M_avers_storage_patchesAfterRevision_duration :: Measurement M_avers_storage_lookupPatch_duration :: Measurement M_avers_storage_applyObjectUpdates_duration :: Measurement M_avers_storage_applyObjectUpdates_numOperations :: Measurement M_avers_storage_applyObjectUpdates_numPreviousPatches :: Measurement M_avers_storage_exists_duration :: Measurement measurementLabels :: Measurement -> [[Char]] -- | A change in the system, for example a new object, patch, release, blob -- etc. data Change -- | A new patch was created. CPatch :: !Patch -> Change -- | Return a TChan to which all changes in the system are streamed. -- Make sure to continuously drain items from the TChan, otherwise -- they will accumulate in memory and you will run OOM eventually. -- -- Do not write into the channel! changeChannel :: Handle -> IO (TChan Change)