on develop help sign in
Reordering cabal dependencies and adding lower bounds
07df0a2Brendan Hay
core/gogol-core.cabal+18−17
@@ -43,23 +43,24 @@ library
43 , Network.Google.Types
43 , Network.Google.Types
44
44
45 build-depends:
45 build-depends:
46− aeson >= 0.8
46+ aeson >= 0.8
47+ , attoparsec >= 0.11.3
47− , base >= 4.7 && < 5
48+ , base >= 4.7 && < 5
48− , bytestring >= 0.9
49+ , bytestring >= 0.9
49− , conduit >= 1.1
50− , dlist >= 0.7
51− , case-insensitive >= 1.2
50+ , case-insensitive >= 1.2
51+ , conduit >= 1.1
52+ , dlist >= 0.7
52− , exceptions >= 0.6
53+ , exceptions >= 0.6
53− , hashable >= 1.2
54+ , hashable >= 1.2
54− , http-client >= 0.4.4
55+ , http-client >= 0.4.4
55− , http-media >= 0.6
56+ , http-media >= 0.6
56− , http-types >= 0.8.6
57+ , http-types >= 0.8.6
57− , lens >= 4.4
58+ , lens >= 4.4
58− , resourcet >= 1.1
59+ , resourcet >= 1.1
59− , scientific >= 0.3
60+ , scientific >= 0.3
60− , servant >= 0.4.4
61+ , servant >= 0.4.4
61− , text >= 1.1
62+ , text >= 1.1
62− , unordered-containers
63+ , unordered-containers >= 0.2.5
63
64
64 if !impl(ghc>=7.9)
65 if !impl(ghc>=7.9)
65 build-depends:
66 build-depends:
core/src/Network/Google/Data/Time.hs+105−13
@@ -10,24 +10,116 @@
10-- Stability : provisional
10-- Stability : provisional
11-- Portability : non-portable (GHC extensions)
11-- Portability : non-portable (GHC extensions)
12--
12--
13−module Network.Google.Data.Time where
13+module Network.Google.Data.Time
14+ ( Time' (..)
15+ , Date' (..)
16+ , DateTime' (..)
14
17
18+ , _Time
19+ , _Date
20+ , _DateTime
21+ ) where
22+
23+import Control.Lens
15import Data.Aeson
24import Data.Aeson
25+import Data.Aeson.Encode
26+import qualified Data.Aeson.Types as Aeson
27+import Data.Attoparsec.Text
28+import Data.Bits ((.&.))
29+import Data.Char (ord)
16−import Data.Data (Data, Typeable)
30+import Data.Data (Data, Typeable)
17−import Data.Text (Text)
31+import Data.Text (Text)
32+import qualified Data.Text as Text
33+import qualified Data.Text.Lazy as LText
34+import qualified Data.Text.Lazy.Builder as Build
18import Data.Time
35import Data.Time
19import GHC.Generics
36import GHC.Generics
20−import Servant.API (FromText, ToText)
37+import Servant.Common.Text
38+
39+-- | This SHOULD be a time in the format of hh:mm:ss. It is
40+-- recommended that you use the "date-time" format instead of "time"
41+-- unless you need to transfer only the time part.
42+newtype Time' = Time' TimeOfDay
43+ deriving (Eq, Ord, Show, Read, Generic, Data, Typeable)
44+
45+_Time :: Iso' Time' TimeOfDay
46+_Time = iso (\(Time' t) -> t) Time'
47+
48+-- | This SHOULD be a date in the format of YYYY-MM-DD. It is
49+-- recommended that you use the "date-time" format instead of "date"
50+-- unless you need to transfer only the date part.
51+newtype Date' = Date' Day
52+ deriving (Eq, Ord, Show, Read, Generic, Data, Typeable)
53+
54+_Date :: Iso' Date' Day
55+_Date = iso (\(Date' t) -> t) Date'
56+
57+-- | This SHOULD be a date in ISO 8601 format of YYYY-MM-
58+-- DDThh:mm:ssZ in UTC time. This is the recommended form of date/timestamp.
59+newtype DateTime' = DateTime' UTCTime
60+ deriving (Eq, Ord, Show, Read, Generic, Data, Typeable)
61+
62+_DateTime :: Iso' DateTime' UTCTime
63+_DateTime = iso (\(DateTime' t) -> t) DateTime'
64+
65+instance FromText Time' where fromText = fmap Time' . parseText timeParser
66+instance FromText Date' where fromText = fmap Date' . parseText dayParser
67+instance FromText DateTime' where fromText = Aeson.parseMaybe parseJSON . String
68+
69+instance FromJSON Time' where
70+ parseJSON = fmap Time' . withText "time" (run timeParser)
71+
72+instance FromJSON Date' where
73+ parseJSON = fmap Date' . withText "date" (run dayParser)
74+
75+instance FromJSON DateTime' where
76+ parseJSON = fmap DateTime' . parseJSON
77+
78+-- FIXME: Revisit once aeson-0.10 is more widely available.
79+instance ToText Time' where toText = Text.pack . show . view _Time
80+instance ToText Date' where toText = Text.pack . show . view _Date
81+instance ToText DateTime' where toText = encodeText
82+
83+-- FIXME: Revisit once aeson-0.10 is more widely available.
84+instance ToJSON Time' where toJSON = String . toText
85+instance ToJSON Date' where toJSON = String . toText
86+instance ToJSON DateTime' where toJSON = toJSON . view _DateTime
87+
88+parseText :: Parser a -> Text -> Maybe a
89+parseText p = either (const Nothing) Just . parseOnly p
90+
91+encodeText :: ToJSON a => a -> Text
92+encodeText = LText.toStrict . Build.toLazyText . encodeToTextBuilder . toJSON
21
93
22−_Time = undefined
94+-- | Parse a time of the form @HH:MM:SS@.
23−_Date = undefined
95+timeParser :: Parser TimeOfDay
24−_DateTime = undefined
96+timeParser = do
97+ h <- twoDigits <* char ':'
98+ m <- twoDigits <* char ':'
99+ s <- twoDigits <&> fromIntegral
100+ if h < 24 && m < 60 && s < 61
101+ then pure (TimeOfDay h m s)
102+ else fail "invalid time"
25
103
26−newtype Time' = Time' Text -- TimeOfDay
104+-- | Parse a date of the form @YYYY-MM-DD@.
27− deriving (Eq, Ord, Show, Read, Generic, Data, Typeable, FromText, ToText, FromJSON, ToJSON)
105+dayParser :: Parser Day
106+dayParser = do
107+ y <- decimal <* char '-'
108+ m <- twoDigits <* char '-'
109+ d <- twoDigits
110+ maybe (fail "invalid date") pure (fromGregorianValid y m d)
28
111
29−newtype Date' = Date' Text -- LocalTime
112+-- | Parse a two-digit integer (e.g. day of month, hour).
30− deriving (Eq, Ord, Show, Read, Generic, Data, Typeable, FromText, ToText, FromJSON, ToJSON)
113+twoDigits :: Parser Int
114+twoDigits = do
115+ a <- digit
116+ b <- digit
117+ let c2d c = ord c .&. 15
118+ pure $! c2d a * 10 + c2d b
31
119
32−newtype DateTime' = DateTime' Text -- UTCTime
120+-- | Run an attoparsec parser as an aeson parser.
33− deriving (Eq, Ord, Show, Read, Generic, Data, Typeable, FromText, ToText, FromJSON, ToJSON)
121+run :: Parser a -> Text -> Aeson.Parser a
122+run p t =
123+ case parseOnly (p <* endOfInput) t of
124+ Left err -> fail $ "could not parse date: " ++ err
125+ Right r -> pure r
gogol/gogol.cabal+20−21
@@ -35,24 +35,23 @@ library
35 Network.Google.Internal.HTTP
35 Network.Google.Internal.HTTP
36
36
37 build-depends:
37 build-depends:
38+ aeson >= 0.8
38− base >= 4.7 && < 5
39+ , base >= 4.7 && < 5
40+ , bytestring >= 0.9
39− , data-default-class >= 0.0.1
41+ , data-default-class >= 0.0.1
42+ , directory >= 1.2
40− , exceptions >= 0.6
43+ , exceptions >= 0.6
44+ , filepath >= 1.2
41− , gogol-core == 0.0.1.*
45+ , gogol-core == 0.0.1.*
42− , http-conduit >= 2.1.4
46+ , http-conduit >= 2.1.4
43− , http-media >= 0.6
47+ , http-media >= 0.6
44− , http-types >= 0.8.6
48+ , http-types >= 0.8.6
45− , lens >= 4.4
49+ , lens >= 4.4
46− , monad-control >= 1
50+ , monad-control >= 1
47− , mtl >= 2.1.3.1
51+ , mtl >= 2.1.3.1
48− , resourcet >= 1.1
52+ , resourcet >= 1.1
49− , text >= 1.1
53+ , text >= 1.1
50− , transformers >= 0.2
51− , transformers-base >= 0.4
52− , bytestring
53− , time
54+ , time >= 1.2
54− , aeson
55+ , transformers >= 0.2
55− , exceptions
56+ , transformers-base >= 0.4
56− , unordered-containers
57+ , unordered-containers >= 0.2.5
57− , filepath
58− , directory