module Drasil.Database.TypedUIDRef (
  TypedUIDRef, mkRef,
  typedFind, typedFindOrErr,
) where

import Control.Lens ((^.))
import Data.Maybe (fromMaybe)

import Drasil.Database.Chunk (IsChunk)
import Drasil.Database.ChunkDB (ChunkDB, find)
import Drasil.Database.UID (HasUID(..), UID)

-- | 'UID' references that contain information about the type of data the 'UID'
-- refers to, useful for type-safe dereferencing.
newtype TypedUIDRef typ = TypedUIDRef UID

-- | Create a 'TypedUIDRef' to a chunk.
mkRef :: IsChunk t => t -> TypedUIDRef t
mkRef :: forall t. IsChunk t => t -> TypedUIDRef t
mkRef t
t = UID -> TypedUIDRef t
forall typ. UID -> TypedUIDRef typ
TypedUIDRef (UID -> TypedUIDRef t) -> UID -> TypedUIDRef t
forall a b. (a -> b) -> a -> b
$ t
t t -> Getting UID t UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID t UID
forall c. HasUID c => Getter c UID
Getter t UID
uid

-- | Find a chunk by its typed UID reference.
typedFind :: IsChunk t => TypedUIDRef t -> ChunkDB -> Maybe t
typedFind :: forall t. IsChunk t => TypedUIDRef t -> ChunkDB -> Maybe t
typedFind (TypedUIDRef UID
u) = UID -> ChunkDB -> Maybe t
forall a. Typeable a => UID -> ChunkDB -> Maybe a
find UID
u

-- | Find a chunk by its typed UID reference, erroring if not found.
typedFindOrErr :: IsChunk t => TypedUIDRef t -> ChunkDB -> t
typedFindOrErr :: forall t. IsChunk t => TypedUIDRef t -> ChunkDB -> t
typedFindOrErr TypedUIDRef t
tu ChunkDB
cdb = t -> Maybe t -> t
forall a. a -> Maybe a -> a
fromMaybe ([Char] -> t
forall a. HasCallStack => [Char] -> a
error [Char]
"Typed UID dereference failed.") (TypedUIDRef t -> ChunkDB -> Maybe t
forall t. IsChunk t => TypedUIDRef t -> ChunkDB -> Maybe t
typedFind TypedUIDRef t
tu ChunkDB
cdb)