Commit e092cfa7 authored by MrMan's avatar MrMan

Add some code & typeclasses to support expressing tasks w/ids

parent f1e287f3
......@@ -32,6 +32,7 @@ library:
- aeson
- bytestring
- system-filepath
- uuid
executables:
haskell-restish-todo-exe:
......
......@@ -3,6 +3,8 @@
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Types where
......@@ -10,6 +12,7 @@ import qualified Data.Text as DT
import Data.Either (isRight)
import Data.Maybe (isJust, fromJust)
import Data.Functor.Identity (Identity(..))
import Data.UUID (UUID)
----------------
-- First Stab --
......@@ -201,8 +204,58 @@ data TaskStoreError = NoSuchTask TaskID
newtype TaskID = TaskID { getTaskID :: Int } deriving (Eq, Show, Read)
class Component c => TaskStore c where
persistTask :: c -> Validated (FullySpecifiedTask state) -> Either TaskStoreError (FullySpecifiedTask state)
completeTask :: c -> TaskID -> Either TaskStoreError CompletedTask
getTask :: c -> TaskID -> Either TaskStoreError (FullySpecifiedTask state)
updateTask :: c -> TaskID -> PartialTask state -> Either TaskStoreError (FullySpecifiedTask state)
deleteTask :: c -> TaskID -> Either TaskStoreError (FullySpecifiedTask state)
persistTask :: c -> Validated (FullySpecifiedTask state) -> Either TaskStoreError (WithID (FullySpecifiedTask state))
completeTask :: c -> TaskID -> Either TaskStoreError (WithID CompletedTask)
getTask :: c -> TaskID -> Either TaskStoreError (WithID (FullySpecifiedTask state))
updateTask :: c -> TaskID -> PartialTask state -> Either TaskStoreError (WithID (FullySpecifiedTask state))
deleteTask :: c -> TaskID -> Either TaskStoreError (WithID (FullySpecifiedTask state))
--------------
-- Metadata --
--------------
-- -- The basic approach to modeling a thing+id
-- WithId a = { id :: Int
-- , obj :: a
-- }
-- -- But what if I chose a to id with UUIDs instead?
-- WithId a = { id :: UUID
-- , obj :: a
-- }
-- -- What if I allowed both to happen? SQLite does have rowids available by default, in the simplest way I can think of:
-- data WithId a = { id :: Maybe Int
-- , uuid :: Maybe UUID
-- , obj :: a
-- }
-- -- Hmnn, what if we get a little fancier, and unify (a disjoint union, anyone?) both possibilities?
-- newtype NumericID = { getNumericId :: Int } deriving (Eq, Show, Read)
-- data TaskID = NumericID
-- | UUID deriving (Eq, Show, Read)
-- data WithId a = { id :: TaskID
-- , obj :: a
-- }
-- -- Is there any benefit from getting *even* fancier? Is there a benefit from being *super explicit* about what kind of ID is present?
-- data WithId idt a = { id :: idt
-- , obj :: a
-- }
-- type WithNumericId = WithID Int a;
-- type WithUUID = WithID UUID a;
-- type WithAllIds = WithID (Int, UUID) a;
data WithID a where
UUIDID :: UUID -> a -> WithID a
IntID :: Int -> a -> WithID a
-- | A typeclass consisting of types that can produce an ID usable by a SQL library to represent itself.
-- for example, if SQL library a can take `Int` for numeric IDs as well as `String`s for UUIDs, and id is an abstraction over both forms of ID,
-- then `getRowIDValue id` will produce the appropriate SQLValue for use in a query using the specified SQL library
class HasRowIDValue id sqlvalue where
getRowIDValue :: id -> sqlvalue
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment