{-# LANGUAGE DefaultSignatures, TypeFamilies, TypeOperators, PolyKinds, FlexibleInstances, ScopedTypeVariables, FlexibleContexts #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module ProjectM36.Atomable where
import ProjectM36.Base
import ProjectM36.DataTypes.Primitive
import ProjectM36.DataTypes.List
import ProjectM36.DataTypes.NonEmptyList
import ProjectM36.DataTypes.Maybe
import ProjectM36.DataTypes.Either
import GHC.Generics
import qualified Data.Map as M
import qualified Data.Text as T
import Control.DeepSeq (NFData)
import Data.Binary
import Control.Applicative
import Data.Time.Calendar
import Data.ByteString (ByteString)
import Data.Time.Clock
import Data.Maybe
import Data.Proxy
import qualified Data.List.NonEmpty as NE
class (Eq a, NFData a, Binary a, Show a) => Atomable a where
toAtom :: a -> Atom
default toAtom :: (Generic a, AtomableG (Rep a)) => a -> Atom
toAtom v = toAtomG (from v) (toAtomTypeG (from v))
fromAtom :: Atom -> a
default fromAtom :: (Generic a, AtomableG (Rep a)) => Atom -> a
fromAtom v@(ConstructedAtom _ _ args) = case fromAtomG v args of
Nothing -> error "no fromAtomG traversal found"
Just x -> to x
fromAtom v = case fromAtomG v [] of
Nothing -> error "no fromAtomG for Atom found"
Just x -> to x
toAtomType :: proxy a -> AtomType
default toAtomType :: (Generic a, AtomableG (Rep a)) => proxy a -> AtomType
toAtomType _ = toAtomTypeG (from (undefined :: a))
toAddTypeExpr :: proxy a -> DatabaseContextExpr
default toAddTypeExpr :: (Generic a, AtomableG (Rep a)) => proxy a -> DatabaseContextExpr
toAddTypeExpr _ = toAddTypeExprG (from (undefined :: a)) (toAtomType (Proxy :: Proxy a))
instance Atomable Integer where
toAtom = IntegerAtom
fromAtom (IntegerAtom i) = i
fromAtom e = error ("improper fromAtom" ++ show e)
toAtomType _ = IntegerAtomType
toAddTypeExpr _ = NoOperation
instance Atomable Int where
toAtom = IntAtom
fromAtom (IntAtom i) = i
fromAtom e = error ("improper fromAtom" ++ show e)
toAtomType _ = IntAtomType
toAddTypeExpr _ = NoOperation
instance Atomable Double where
toAtom = DoubleAtom
fromAtom (DoubleAtom d) = d
fromAtom _ = error "improper fromAtom"
toAtomType _ = DoubleAtomType
toAddTypeExpr _ = NoOperation
instance Atomable T.Text where
toAtom = TextAtom
fromAtom (TextAtom t) = t
fromAtom _ = error "improper fromAtom"
toAtomType _ = TextAtomType
toAddTypeExpr _ = NoOperation
instance Atomable Day where
toAtom = DayAtom
fromAtom (DayAtom d) = d
fromAtom _ = error "improper fromAtom"
toAtomType _ = DayAtomType
toAddTypeExpr _ = NoOperation
instance Atomable UTCTime where
toAtom = DateTimeAtom
fromAtom (DateTimeAtom t) = t
fromAtom _ = error "improper fromAtom"
toAtomType _ = DateTimeAtomType
toAddTypeExpr _ = NoOperation
instance Atomable ByteString where
toAtom = ByteStringAtom
fromAtom (ByteStringAtom b) = b
fromAtom _ = error "improper fromAtom"
toAtomType _ = ByteStringAtomType
toAddTypeExpr _ = NoOperation
instance Atomable Bool where
toAtom = BoolAtom
fromAtom (BoolAtom b) = b
fromAtom _ = error "improper fromAtom"
toAtomType _ = BoolAtomType
toAddTypeExpr _ = NoOperation
instance Atomable a => Atomable (Maybe a) where
toAtom (Just v) = ConstructedAtom "Just" (maybeAtomType (toAtomType (Proxy :: Proxy a))) [toAtom v]
toAtom Nothing = ConstructedAtom "Nothing" (maybeAtomType (toAtomType (Proxy :: Proxy a))) []
fromAtom (ConstructedAtom "Just" _ [val]) = Just (fromAtom val)
fromAtom (ConstructedAtom "Nothing" _ []) = Nothing
fromAtom _ = error "improper fromAtom (Maybe a)"
toAtomType _ = ConstructedAtomType "Maybe" (M.singleton "a" (toAtomType (Proxy :: Proxy a)))
toAddTypeExpr _ = NoOperation
instance (Atomable a, Atomable b) => Atomable (Either a b) where
toAtom (Left l) = ConstructedAtom "Left" (eitherAtomType (toAtomType (Proxy :: Proxy a))
(toAtomType (Proxy :: Proxy b))) [toAtom l]
toAtom (Right r) = ConstructedAtom "Right" (eitherAtomType (toAtomType (Proxy :: Proxy a))
(toAtomType (Proxy :: Proxy b))) [toAtom r]
fromAtom (ConstructedAtom "Left" _ [val]) = Left (fromAtom val)
fromAtom (ConstructedAtom "Right" _ [val]) = Right (fromAtom val)
fromAtom _ = error "improper fromAtom (Either a b)"
instance Atomable a => Atomable [a] where
toAtom [] = ConstructedAtom "Empty" (listAtomType (toAtomType (Proxy :: Proxy a))) []
toAtom (x:xs) = ConstructedAtom "Cons" (listAtomType (toAtomType (Proxy :: Proxy a))) (map toAtom (x:xs))
fromAtom (ConstructedAtom "Empty" _ _) = []
fromAtom (ConstructedAtom "Cons" _ (x:xs)) = fromAtom x:map fromAtom xs
fromAtom _ = error "improper fromAtom [a]"
toAtomType _ = ConstructedAtomType "List" (M.singleton "a" (toAtomType (Proxy :: Proxy a)))
toAddTypeExpr _ = NoOperation
instance Atomable a => Atomable (NE.NonEmpty a) where
toAtom (x NE.:| []) = ConstructedAtom "NECons" (nonEmptyListAtomType (toAtomType (Proxy :: Proxy a))) [toAtom x]
toAtom (x NE.:| xs) = ConstructedAtom "NECons" (nonEmptyListAtomType (toAtomType (Proxy :: Proxy a))) (map toAtom (x:xs))
fromAtom _ = error "improper fromAtom (NonEmptyList a)"
toAtomType _ = ConstructedAtomType "NonEmptyList" (M.singleton "a" (toAtomType (Proxy :: Proxy a)))
toAddTypeExpr _ = NoOperation
#if !MIN_VERSION_binary(0,8,4)
instance Binary a => Binary (NE.NonEmpty a)
#endif
class AtomableG g where
toAtomG :: g a -> AtomType -> Atom
fromAtomG :: Atom -> [Atom] -> Maybe (g a)
toAtomTypeG :: g a -> AtomType
toAtomsG :: g a -> [Atom]
toAddTypeExprG :: g a -> AtomType -> DatabaseContextExpr
getConstructorsG :: g a -> [DataConstructorDef]
getConstructorArgsG :: g a -> [DataConstructorDefArg]
instance (Datatype c, AtomableG a) => AtomableG (M1 D c a) where
toAtomG (M1 v) = toAtomG v
fromAtomG atom args = M1 <$> fromAtomG atom args
toAtomsG = undefined
toAtomTypeG _ = ConstructedAtomType (T.pack typeName) M.empty
where
typeName = datatypeName (undefined :: M1 D c a x)
toAddTypeExprG (M1 v) (ConstructedAtomType tcName _) = AddTypeConstructor tcDef dataConstructors
where
tcDef = ADTypeConstructorDef tcName []
dataConstructors = getConstructorsG v
toAddTypeExprG _ _ = NoOperation
getConstructorsG (M1 v) = getConstructorsG v
getConstructorArgsG = undefined
instance (Constructor c, AtomableG a) => AtomableG (M1 C c a) where
toAtomG (M1 v) t = ConstructedAtom (T.pack constructorName) t atoms
where
atoms = toAtomsG v
constructorName = conName (undefined :: M1 C c a x)
fromAtomG atom@(ConstructedAtom dConsName _ _) args = if dName == dConsName then
M1 <$> fromAtomG atom args
else
Nothing
where
dName = T.pack (conName (undefined :: M1 C c a x))
fromAtomG _ _ = error "unsupported generic traversal"
toAtomsG = undefined
toAtomTypeG = undefined
toAddTypeExprG = undefined
getConstructorsG (M1 v) = [DataConstructorDef (T.pack dName) dArgs]
where
dName = conName (undefined :: M1 C c a x)
dArgs = getConstructorArgsG v
getConstructorArgsG = undefined
instance (Selector c, AtomableG a) => AtomableG (M1 S c a) where
toAtomG = undefined
fromAtomG atom args = M1 <$> fromAtomG atom args
toAtomsG (M1 v) = toAtomsG v
toAtomTypeG (M1 v) = toAtomTypeG v
toAddTypeExprG _ _ = undefined
getConstructorsG = undefined
getConstructorArgsG (M1 v) = getConstructorArgsG v
instance (Atomable a) => AtomableG (K1 c a) where
toAtomG (K1 v) _ = toAtom v
fromAtomG _ args = K1 <$> Just (fromAtom (headatom args))
where headatom (x:_) = x
headatom [] = error "no more atoms for constructor!"
toAtomsG (K1 v) = [toAtom v]
toAtomTypeG _ = toAtomType (Proxy :: Proxy a)
toAddTypeExprG _ _ = undefined
getConstructorsG = undefined
getConstructorArgsG (K1 _) = [DataConstructorDefTypeConstructorArg tCons]
where
tCons = PrimitiveTypeConstructor primitiveATypeName primitiveAType
primitiveAType = toAtomType (Proxy :: Proxy a)
primitiveATypeName = fromMaybe (error ("primitive type missing: " ++ show primitiveAType)) (foldr (\(PrimitiveTypeConstructorDef name typ, _) acc -> if typ == primitiveAType then Just name else acc) Nothing primitiveTypeConstructorMapping)
instance AtomableG U1 where
toAtomG = undefined
fromAtomG _ _ = pure U1
toAtomsG _ = []
toAtomTypeG = undefined
toAddTypeExprG = undefined
getConstructorsG = undefined
getConstructorArgsG _ = []
instance (AtomableG a, AtomableG b) => AtomableG (a :*: b) where
toAtomG = undefined
fromAtomG atom args = (:*:) <$> fromAtomG atom [headatom args] <*> fromAtomG atom (tailatoms args)
where headatom (x:_) = x
headatom [] = error "no more atoms in head for product!"
tailatoms (_:xs) = xs
tailatoms [] = error "no more atoms in tail for product!"
toAtomTypeG = undefined
toAtomsG (x :*: y) = toAtomsG x ++ toAtomsG y
toAddTypeExprG _ _ = undefined
getConstructorsG = undefined
getConstructorArgsG (x :*: y) = getConstructorArgsG x ++ getConstructorArgsG y
instance (AtomableG a, AtomableG b) => AtomableG (a :+: b) where
toAtomG (L1 x) = toAtomG x
toAtomG (R1 x) = toAtomG x
fromAtomG atom args = (L1 <$> fromAtomG atom args) <|> (R1 <$> fromAtomG atom args)
toAtomTypeG = undefined
toAtomsG (L1 x) = toAtomsG x
toAtomsG (R1 x) = toAtomsG x
toAddTypeExprG _ _ = undefined
getConstructorsG _ = getConstructorsG (undefined :: a x) ++ getConstructorsG (undefined :: b x)
getConstructorArgsG = undefined