diff --git a/heidi.cabal b/heidi.cabal index ef87e8a..92ace6f 100644 --- a/heidi.cabal +++ b/heidi.cabal @@ -58,7 +58,8 @@ library -- , primitive , scientific >= 0.3.5.1 , text >= 1.2.2.2 - -- , time >= 1.6.0.1 + , time >= 1.6.0.1 + , hashable-time >= 0.2.0 -- , transformers , unordered-containers > 0.2.8 , vector >= 0.12.0.1 diff --git a/src/Data/Generics/Encode/Internal.hs b/src/Data/Generics/Encode/Internal.hs index 3ce4dd5..5627c67 100644 --- a/src/Data/Generics/Encode/Internal.hs +++ b/src/Data/Generics/Encode/Internal.hs @@ -41,9 +41,9 @@ module Data.Generics.Encode.Internal (gflattenHM, gflattenGT, -- * VP (Primitive types) VP(..), -- ** Lenses - vpInt, vpDouble, vpFloat, vpString, vpText, vpBool, vpScientific, vpChar, vpOneHot, + vpInt, vpDouble, vpFloat, vpString, vpText, vpBool, vpScientific, vpChar, vpOneHot, vpDay, vpUTCTime, vpTimeOfDay, vpLocalTime, vpTimeZone, vpNominalDiffTime, vpDiffTime, vpUniversalTime, -- ** 'MonadThrow' getters - getIntM, getInt8M, getInt16M, getInt32M, getInt64M, getWordM, getWord8M, getWord16M, getWord32M, getWord64M, getBoolM, getFloatM, getDoubleM, getScientificM, getCharM, getStringM, getTextM, getOneHotM, TypeError(..), + getIntM, getInt8M, getInt16M, getInt32M, getInt64M, getWordM, getWord8M, getWord16M, getWord32M, getWord64M, getBoolM, getFloatM, getDoubleM, getScientificM, getCharM, getStringM, getTextM, getOneHotM, getDayM, getUTCTimeM, getTimeOfDayM, getLocalTimeM, getTimeZoneM, getNominalDiffTimeM, getDiffTimeM, getUniversalTimeM, TypeError(..), -- * TC (Type and Constructor annotation) TC(..), tcTyN, tcTyCon, mkTyN, mkTyCon, -- * Heidi (generic ADT encoding) @@ -75,6 +75,8 @@ import Lens.Micro.TH (makeLenses) import Data.Scientific (Scientific) -- text import Data.Text (Text, unpack) +-- time +import Data.Time (Day, UTCTime, TimeOfDay, LocalTime, TimeZone, NominalDiffTime, DiffTime, UniversalTime) -- import Data.Time (Day, LocalTime, TimeOfDay) -- import qualified Data.Vector as V @@ -82,7 +84,7 @@ import qualified Data.HashMap.Strict as HM -- import qualified Data.GenericTrie as GT import Data.Generics.Encode.OneHot (OneHot, mkOH) -import Data.Generics.Encode.Internal.Prim (VP(..), vpInt, vpScientific, vpFloat, vpDouble, vpString, vpChar, vpText, vpBool, vpOneHot) +import Data.Generics.Encode.Internal.Prim (VP(..), vpInt, vpBool, vpFloat, vpDouble, vpScientific, vpChar, vpString, vpText, vpOneHot, vpDay, vpUTCTime, vpTimeOfDay, vpLocalTime, vpTimeZone, vpNominalDiffTime, vpDiffTime, vpUniversalTime) -- import Data.List (unfoldr) -- import qualified Data.Foldable as F -- import qualified Data.Sequence as S (Seq(..), empty) @@ -327,6 +329,15 @@ instance Heidi Scientific where {toVal = VPrim . VPScientific ; header _ = HLeaf instance Heidi Char where {toVal = VPrim . VPChar ; header _ = HLeaf "Char"} instance Heidi String where {toVal = VPrim . VPString ; header _ = HLeaf "String"} instance Heidi Text where {toVal = VPrim . VPText ; header _ = HLeaf "Text"} +instance Heidi Day where {toVal = VPrim . VPDay ; header _ = HLeaf "Day"} +instance Heidi UTCTime where {toVal = VPrim . VPUTCTime ; header _ = HLeaf "UTCTime"} +instance Heidi TimeOfDay where {toVal = VPrim . VPTimeOfDay ; header _ = HLeaf "TimeOfDay"} +instance Heidi LocalTime where {toVal = VPrim . VPLocalTime ; header _ = HLeaf "LocalTime"} +instance Heidi TimeZone where {toVal = VPrim . VPTimeZone ; header _ = HLeaf "TimeZone"} +instance Heidi NominalDiffTime where {toVal = VPrim . VPNominalDiffTime ; header _ = HLeaf "NominalDiffTime"} +instance Heidi DiffTime where {toVal = VPrim . VPDiffTime ; header _ = HLeaf "DiffTime"} +instance Heidi UniversalTime where {toVal = VPrim . VPUniversalTime ; header _ = HLeaf "UniversalTime"} + instance Heidi a => Heidi (Maybe a) where toVal = \case @@ -405,7 +416,30 @@ getText = \case {VPText i -> Just i; _ -> Nothing} -- | Extract a OneHot value getOneHot :: VP -> Maybe (OneHot Int) getOneHot = \case {VPOH i -> Just i; _ -> Nothing} - +-- | Extract a Day +getDay :: VP -> Maybe Day +getDay = \case {VPDay i -> Just i; _ -> Nothing} +-- | Extract a UTCTime +getUTCTime :: VP -> Maybe UTCTime +getUTCTime = \case {VPUTCTime i -> Just i; _ -> Nothing} +-- | Extract a TimeOfDay +getTimeOfDay :: VP -> Maybe TimeOfDay +getTimeOfDay = \case {VPTimeOfDay i -> Just i; _ -> Nothing} +-- | Extract a LocalTime +getLocalTime :: VP -> Maybe LocalTime +getLocalTime = \case {VPLocalTime i -> Just i; _ -> Nothing} +-- | Extract a TimeZone +getTimeZone :: VP -> Maybe TimeZone +getTimeZone = \case {VPTimeZone i -> Just i; _ -> Nothing} +-- | Extract a NominalDiffTime +getNominalDiffTime :: VP -> Maybe NominalDiffTime +getNominalDiffTime = \case {VPNominalDiffTime i -> Just i; _ -> Nothing} +-- | Extract a DiffTime +getDiffTime :: VP -> Maybe DiffTime +getDiffTime = \case {VPDiffTime i -> Just i; _ -> Nothing} +-- | Extract a UniversalTime +getUniversalTime :: VP -> Maybe UniversalTime +getUniversalTime = \case {VPUniversalTime i -> Just i; _ -> Nothing} -- | Helper function for decoding into a 'MonadThrow'. decodeM :: (MonadThrow m, Exception e) => e -> (a -> m b) -> Maybe a -> m b @@ -448,6 +482,22 @@ getTextM :: MonadThrow m => VP -> m Text getTextM x = decodeM TextCastE pure (getText x) getOneHotM :: MonadThrow m => VP -> m (OneHot Int) getOneHotM x = decodeM OneHotCastE pure (getOneHot x) +getDayM :: MonadThrow m => VP -> m Day +getDayM x = decodeM DayCastE pure (getDay x) +getUTCTimeM :: MonadThrow m => VP -> m UTCTime +getUTCTimeM x = decodeM UTCTimeCastE pure (getUTCTime x) +getLocalTimeM :: MonadThrow m => VP -> m LocalTime +getLocalTimeM x = decodeM LocalTimeCastE pure (getLocalTime x) +getTimeOfDayM :: MonadThrow m => VP -> m TimeOfDay +getTimeOfDayM x = decodeM TimeOfDayCastE pure (getTimeOfDay x) +getTimeZoneM :: MonadThrow m => VP -> m TimeZone +getTimeZoneM x = decodeM TimeZoneCastE pure (getTimeZone x) +getNominalDiffTimeM :: MonadThrow m => VP -> m NominalDiffTime +getNominalDiffTimeM x = decodeM NominalDiffTimeCastE pure (getNominalDiffTime x) +getDiffTimeM :: MonadThrow m => VP -> m DiffTime +getDiffTimeM x = decodeM DiffTimeCastE pure (getDiffTime x) +getUniversalTimeM :: MonadThrow m => VP -> m UniversalTime +getUniversalTimeM x = decodeM UniversalTimeCastE pure (getUniversalTime x) -- | Type errors data TypeError = @@ -469,6 +519,14 @@ data TypeError = | StringCastE | TextCastE | OneHotCastE + | DayCastE + | UTCTimeCastE + | LocalTimeCastE + | TimeOfDayCastE + | NominalDiffTimeCastE + | TimeZoneCastE + | DiffTimeCastE + | UniversalTimeCastE deriving (Show, Eq, Typeable) instance Exception TypeError diff --git a/src/Data/Generics/Encode/Internal/Prim.hs b/src/Data/Generics/Encode/Internal/Prim.hs index 3833acf..281f235 100644 --- a/src/Data/Generics/Encode/Internal/Prim.hs +++ b/src/Data/Generics/Encode/Internal/Prim.hs @@ -2,7 +2,7 @@ {-# LANGUAGE LambdaCase #-} {-# language TemplateHaskell #-} {-# options_ghc -Wno-unused-imports #-} -module Data.Generics.Encode.Internal.Prim (VP(..), vpInt, vpBool, vpFloat, vpDouble, vpScientific, vpChar, vpString, vpText, vpOneHot) where +module Data.Generics.Encode.Internal.Prim (VP(..), vpInt, vpBool, vpFloat, vpDouble, vpScientific, vpChar, vpString, vpText, vpOneHot, vpDay, vpUTCTime, vpTimeOfDay, vpLocalTime, vpTimeZone, vpNominalDiffTime, vpDiffTime, vpUniversalTime) where import Data.Int (Int8, Int16, Int32, Int64) import Data.Word (Word, Word8, Word16, Word32, Word64) @@ -16,6 +16,11 @@ import Lens.Micro.TH (makeLenses) import Data.Scientific (Scientific) -- text import Data.Text (Text, unpack) +-- time +import Data.Time (Day, UTCTime, TimeOfDay, LocalTime, TimeZone, NominalDiffTime, DiffTime, UniversalTime) + +-- hashable-time +import Data.Hashable.Time (Hashable(..)) import Data.Generics.Encode.OneHot (OneHot, mkOH) @@ -42,6 +47,17 @@ data VP = | VPText { _vpText :: Text } -- ^ 'Text' | VPOH { _vpOneHot :: OneHot Int } -- ^ 1-hot encoding of an enum value | VPUnit + | VPDay { _vpDay :: Day } -- ^ 'Day' + | VPUTCTime { _vpUTCTime :: UTCTime } -- ^ 'UTCTime' + | VPTimeOfDay { _vpTimeOfDay :: TimeOfDay } -- ^ 'TimeOfDay' + | VPLocalTime { _vpLocalTime :: LocalTime } -- ^ 'LocalTime' + | VPTimeZone { _vpTimeZone :: TimeZone } -- ^ 'TimeZone' + | VPNominalDiffTime { _vpNominalDiffTime :: NominalDiffTime } -- ^ 'NominalDiffTime' + | VPDiffTime { _vpDiffTime :: DiffTime } -- ^ 'DiffTime' + | VPUniversalTime { _vpUniversalTime :: UniversalTime } -- ^ 'UniversalTime' + + + deriving (Eq, Ord, G.Generic) instance Hashable VP makeLenses ''VP @@ -67,3 +83,11 @@ instance Show VP where VPText t -> unpack t VPOH oh -> show oh VPUnit -> show () + VPDay d -> show d + VPUTCTime t -> show t + VPTimeOfDay t -> show t + VPLocalTime t -> show t + VPTimeZone t -> show t + VPNominalDiffTime t -> show t + VPDiffTime t -> show t + VPUniversalTime t -> show t diff --git a/src/Heidi.hs b/src/Heidi.hs index 7561b19..0d4f9cf 100644 --- a/src/Heidi.hs +++ b/src/Heidi.hs @@ -74,7 +74,8 @@ module Heidi ( , traverseWithKey -- ** Lens combinators -- *** Traversals - , int, bool, float, double, char, string, text, scientific, oneHot + , int, bool, float, double, char, string, text, scientific, oneHot, day, utcTime, timeOfDay, localTime, timeZone, nominalDiffTime, diffTime, universalTime + -- ** Getters -- *** Getters , real, txt -- , flag @@ -93,7 +94,7 @@ import Control.Monad.Catch (MonadThrow(..)) import Core.Data.Frame.List (Frame, frame, head, take, drop, numRows, filter, groupWith, scanl, scanr, toVector) import Core.Data.Frame.Generic (encode) -import Data.Generics.Encode.Internal (Heidi(..), VP(..), getIntM, getInt8M, getInt16M, getInt32M, getInt64M, getWordM, getWord8M, getWord16M, getWord32M, getWord64M, getBoolM, getFloatM, getDoubleM, getScientificM, getCharM, getStringM, getTextM, getOneHotM, TypeError(..), TC(..), tcTyN, tcTyCon, mkTyN, mkTyCon) +import Data.Generics.Encode.Internal (Heidi(..), VP(..), getIntM, getInt8M, getInt16M, getInt32M, getInt64M, getWordM, getWord8M, getWord16M, getWord32M, getWord64M, getBoolM, getFloatM, getDoubleM, getScientificM, getCharM, getStringM, getTextM, getOneHotM, getDayM, getUTCTimeM, getTimeOfDayM, getLocalTimeM, getTimeZoneM, getNominalDiffTimeM, getDiffTimeM, getUniversalTimeM, TypeError(..), TC(..), tcTyN, tcTyCon, mkTyN, mkTyCon) import Data.Generics.Encode.OneHot (OneHot) import Heidi.Data.Row.GenericTrie import Heidi.Data.Frame.Algorithms.GenericTrie (innerJoin, leftOuterJoin, gatherWith, spreadWith, groupBy) diff --git a/src/Heidi/Data/Frame/Algorithms/HashMap.hs b/src/Heidi/Data/Frame/Algorithms/HashMap.hs index 8db6919..21879d0 100644 --- a/src/Heidi/Data/Frame/Algorithms/HashMap.hs +++ b/src/Heidi/Data/Frame/Algorithms/HashMap.hs @@ -31,6 +31,7 @@ import qualified Data.Foldable as F (foldMap, foldl', foldlM) import qualified Data.Map as M import qualified Data.HashMap.Strict as HM import Data.Hashable (Hashable(..)) +import Data.Hashable.Time (Hashable(..)) import qualified Data.Set as S (Set, fromList) -- import Control.Monad.Primitive (PrimMonad(..), PrimState(..)) -- import Control.Monad.Catch(Exception(..), MonadThrow(..)) diff --git a/src/Heidi/Data/Row/GenericTrie.hs b/src/Heidi/Data/Row/GenericTrie.hs index c0db829..fa6675a 100644 --- a/src/Heidi/Data/Row/GenericTrie.hs +++ b/src/Heidi/Data/Row/GenericTrie.hs @@ -57,7 +57,7 @@ module Heidi.Data.Row.GenericTrie ( , traverseWithKey -- * Lens combinators -- ** Traversals - , int, bool, float, double, char, string, text, scientific, oneHot + , int, bool, float, double, char, string, text, scientific, oneHot, day, utcTime, timeOfDay, localTime, timeZone, nominalDiffTime, diffTime, universalTime -- ** Getters , real, txt -- , flag @@ -91,12 +91,14 @@ import Lens.Micro (Lens', Traversal', Getting, (^.), (^?), (<&>), _Just, Getting import Data.Scientific (Scientific) -- text import Data.Text (Text) +-- time +import Data.Time (Day, UTCTime, TimeOfDay, LocalTime, TimeZone, NominalDiffTime, DiffTime, UniversalTime) import qualified Data.Text as T (pack, unpack) -- import qualified Data.Generics.Decode as D (Decode, mkDecode) -- import Data.Generics.Decode ((>>>)) -import Data.Generics.Encode.Internal (VP, vpInt, vpFloat, vpDouble, vpString, vpChar, vpText, vpBool, vpScientific, vpOneHot) +import Data.Generics.Encode.Internal (VP, vpInt, vpFloat, vpDouble, vpString, vpChar, vpText, vpBool, vpScientific, vpOneHot, vpDay, vpUTCTime, vpTimeOfDay, vpLocalTime, vpTimeZone, vpNominalDiffTime, vpDiffTime, vpUniversalTime) import Data.Generics.Encode.OneHot (OneHot) -- import Data.Generics.Codec -- import Core.Data.Row.Internal (KeyError(..)) @@ -267,7 +269,30 @@ scientific k = at k . _Just . vpScientific -- | Decode a 'OneHot' from the given column index oneHot :: GT.TrieKey k => k -> Traversal' (Row k VP) (OneHot Int) oneHot k = at k . _Just . vpOneHot - +-- | Decode a 'Day' from the given column index +day :: GT.TrieKey k => k -> Traversal' (Row k VP) Day +day k = at k . _Just . vpDay +-- | Decode a 'UTCTime' from the given column index +utcTime :: GT.TrieKey k => k -> Traversal' (Row k VP) UTCTime +utcTime k = at k . _Just . vpUTCTime +-- | Decode a 'TimeOfDay' from the given column index +timeOfDay :: GT.TrieKey k => k -> Traversal' (Row k VP) TimeOfDay +timeOfDay k = at k . _Just . vpTimeOfDay +-- | Decode a 'LocalTime' from the given column index +localTime :: GT.TrieKey k => k -> Traversal' (Row k VP) LocalTime +localTime k = at k . _Just . vpLocalTime +-- | Decode a 'TimeZone' from the given column index +timeZone :: GT.TrieKey k => k -> Traversal' (Row k VP) TimeZone +timeZone k = at k . _Just . vpTimeZone +-- | Decode a 'NominalDiffTime' from the given column index +nominalDiffTime :: GT.TrieKey k => k -> Traversal' (Row k VP) NominalDiffTime +nominalDiffTime k = at k . _Just . vpNominalDiffTime +-- | Decode a 'DiffTime' from the given column index +diffTime :: GT.TrieKey k => k -> Traversal' (Row k VP) DiffTime +diffTime k = at k . _Just . vpDiffTime +-- | Decode a 'UniversalTime' from the given column index +universalTime :: GT.TrieKey k => k -> Traversal' (Row k VP) UniversalTime +universalTime k = at k . _Just . vpUniversalTime