Skip to content

Commit 383f877

Browse files
author
Antonio Alonso Dominguez
committed
Got schema for sum types working
1 parent bd8c688 commit 383f877

File tree

5 files changed

+91
-51
lines changed

5 files changed

+91
-51
lines changed

src/Data/Schema.hs

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ module Data.Schema
33
, module Data.Schema.Types
44
) where
55

6-
import Data.Schema.JSON
7-
import Data.Schema.Types
6+
import Data.Schema.JSON
7+
import Data.Schema.Types

src/Data/Schema/JSON.hs

+28-16
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
1-
{-# LANGUAGE GADTs #-}
2-
{-# LANGUAGE OverloadedStrings #-}
31
{-# LANGUAGE ExistentialQuantification #-}
2+
{-# LANGUAGE GADTs #-}
3+
{-# LANGUAGE OverloadedStrings #-}
44

55
module Data.Schema.JSON
66
( serializer
77
, deserializer
88
) where
99

10-
import Data.Aeson (parseJSON)
11-
import qualified Data.Aeson as Json
12-
import qualified Data.Aeson.Types as Json
13-
import Data.Schema.Types
14-
import Control.Applicative.Free
15-
import Control.Lens
16-
import Control.Monad.State (State)
17-
import qualified Control.Monad.State as ST
18-
import Data.HashMap.Strict (HashMap)
19-
import qualified Data.HashMap.Strict as Map
20-
import Data.Text (Text)
10+
import Control.Applicative.Free
11+
import Control.Lens
12+
import Control.Monad.State (State)
13+
import qualified Control.Monad.State as ST
14+
import Data.Aeson (parseJSON)
15+
import qualified Data.Aeson as Json
16+
import qualified Data.Aeson.Types as Json
17+
import Data.HashMap.Strict (HashMap)
18+
import qualified Data.HashMap.Strict as Map
19+
import Data.Maybe
20+
import Data.Schema.Types
21+
import Data.Text (Text)
2122

22-
serializer :: Serializer a Json.Value
23+
serializer :: Schema a -> (a -> Json.Value)
2324
serializer IntSchema = Json.Number . fromIntegral
2425
serializer BoolSchema = Json.Bool
2526
serializer StringSchema = Json.String
@@ -30,7 +31,12 @@ serializer (RecordSchema ps) = \value -> Json.Object $ ST.execState (runAp (step
3031
let el = view getter obj
3132
ST.modify $ Map.insert name (serializer schema $ el)
3233
return el
33-
serializer (UnionSchema alts) = undefined
34+
serializer (UnionSchema alts) = \value -> head . catMaybes $ fmap (decodeAlt value) alts
35+
where objSingleAttr :: Text -> Json.Value -> Json.Value
36+
objSingleAttr n v = Json.Object $ Map.insert n v Map.empty
37+
38+
decodeAlt :: o -> AltDef o -> Maybe Json.Value
39+
decodeAlt obj (AltDef i schema pr) = (objSingleAttr i) <$> (serializer schema) <$> (obj ^? pr)
3440

3541
deserializer :: Schema a -> (Json.Value -> Json.Parser a)
3642
deserializer IntSchema = parseJSON
@@ -45,4 +51,10 @@ deserializer (RecordSchema ps) = \json -> case json of
4551
step jsonObj (PropDef name schema _) =
4652
Json.explicitParseField (\v -> deserializer schema $ v) jsonObj name
4753
other -> fail $ "Expected JSON Object but got: " ++ (show other)
48-
deserializer (UnionSchema alts) = undefined
54+
deserializer (UnionSchema alts) = \json -> case json of
55+
Json.Object obj -> head . catMaybes $ fmap lookupParser alts
56+
where lookupParser :: AltDef a -> Maybe (Json.Parser a)
57+
lookupParser (AltDef i schema pr) = do
58+
altParser <- (deserializer schema) <$> Map.lookup i obj
59+
return $ (view $ re pr) <$> altParser
60+
other -> fail $ "Expected JSON Object but got: " ++ (show other)

src/Data/Schema/Types.hs

+15-14
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1-
{-# LANGUAGE GADTs #-}
2-
{-# LANGUAGE RankNTypes #-}
1+
{-# LANGUAGE ExistentialQuantification #-}
2+
{-# LANGUAGE GADTs #-}
3+
{-# LANGUAGE RankNTypes #-}
34

45
module Data.Schema.Types where
56

6-
import Control.Applicative.Free
7-
import Control.Lens
8-
import Data.Text (Text)
9-
import qualified Data.Text as T
10-
import Data.Vector (Vector)
7+
import Control.Applicative.Free
8+
import Control.Lens
9+
import Data.Text (Text)
10+
import qualified Data.Text as T
11+
import Data.Vector (Vector)
1112

1213
data PropDef o a = PropDef
13-
{ propName :: Text
14-
, propSchema :: Schema a
14+
{ propName :: Text
15+
, propSchema :: Schema a
1516
, propAccessor :: Getter o a
1617
}
1718

@@ -28,10 +29,10 @@ type Props o = Ap (PropDef o) o
2829
-- emptyProps :: forall a. Props' a ()
2930
-- emptyProps = Pure ()
3031

31-
data Alt a = forall b. Alt
32-
{ altId :: Text
32+
data AltDef a = forall b. AltDef
33+
{ altId :: Text
3334
, altSchema :: Schema b
34-
, altPrism :: Prism' a b
35+
, altPrism :: Prism' a b
3536
}
3637

3738
data Schema a where
@@ -41,7 +42,7 @@ data Schema a where
4142
NoSchema :: Schema ()
4243
ListSchema :: Schema a -> Schema (Vector a)
4344
RecordSchema :: Props o -> Schema o
44-
UnionSchema :: [Alt a] -> Schema a
45+
UnionSchema :: [AltDef a] -> Schema a
4546

4647
-- voidGetter :: forall a. Getter a ()
4748
-- voidGetter = to (const ())
@@ -56,4 +57,4 @@ data Schema a where
5657
-- in RecordSchema lifted
5758

5859
type Serializer a b = Schema a -> (a -> b)
59-
type Deserializer a b = Schema b -> (a -> Either String b)
60+
type Deserializer a b = Schema b -> (a -> Either String b)

src/Lib.hs

+17-19
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
{-# LANGUAGE RankNTypes #-}
2-
{-# LANGUAGE DeriveFunctor #-}
3-
{-# LANGUAGE GADTs #-}
4-
{-# LANGUAGE TypeOperators #-}
5-
{-# LANGUAGE FlexibleContexts #-}
1+
{-# LANGUAGE DeriveFunctor #-}
2+
{-# LANGUAGE FlexibleContexts #-}
3+
{-# LANGUAGE GADTs #-}
4+
{-# LANGUAGE LambdaCase #-}
65
{-# LANGUAGE OverloadedStrings #-}
7-
{-# LANGUAGE LambdaCase #-}
6+
{-# LANGUAGE RankNTypes #-}
7+
{-# LANGUAGE TypeOperators #-}
88

99
module Lib
1010
( someFunc
1111
) where
1212

13-
import Control.Applicative.Free
14-
import Control.Lens
15-
import Data.Schema
16-
import Data.Text (Text)
17-
import qualified Data.Text as T
18-
import Data.Time.Clock
13+
import Control.Applicative.Free
14+
import Control.Lens
15+
import Data.Schema
16+
import Data.Text (Text)
17+
import qualified Data.Text as T
18+
import Data.Time.Clock
1919

2020
stringIso :: Iso' String Text
2121
stringIso = iso T.pack T.unpack
@@ -48,18 +48,16 @@ subordinateCountGetter :: Getter AdminRole Int
4848
subordinateCountGetter = to subordinateCount
4949

5050
userNameProp = liftAp $ PropDef "name" StringSchema (to userName)
51-
userRoleAlt = Alt "user" (RecordSchema (UserRole' <$> userNameProp)) _UserRole
51+
userRoleAlt = AltDef "user" (RecordSchema (UserRole' <$> userNameProp)) _UserRole
5252

5353
departmentProp = liftAp $ PropDef "department" StringSchema adminDept
5454
subordinateCountProp = liftAp $ PropDef "subordinateCount" IntSchema subordinateCountGetter
55-
adminRoleAlt = Alt "admin" (RecordSchema (AdminRole' <$> departmentProp <*> subordinateCountProp)) _AdminRole
55+
adminRoleAlt = AltDef "admin" (RecordSchema (AdminRole' <$> departmentProp <*> subordinateCountProp)) _AdminRole
5656

57-
userSchema :: Schema Role
58-
userSchema = UnionSchema [userRoleAlt, adminRoleAlt]
57+
roleSchema :: Schema Role
58+
roleSchema = UnionSchema [userRoleAlt, adminRoleAlt]
5959

60-
data Person1 = Person1 { aName :: String, aAge :: Int }
61-
62-
data Person = Person { name :: String, birthDate :: UTCTime, roles :: [Role] }
60+
data Person = Person { name :: Text, birthDate :: UTCTime, roles :: [Role] }
6361

6462
someFunc :: IO ()
6563
someFunc = putStrLn "someFunc"

stylize.sh

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env bash
2+
3+
command -v stylish-haskell >/dev/null 2>&1 || { echo "Could not find stylish-haskell. Aborting." >&2; exit 1; }
4+
5+
find . -name \*.hs -and \( -not \( -name Setup.hs -or -path ./.stack-work/\* -or -path ./dist/\* \) \) | xargs stylish-haskell -i > stylish-out 2>&1
6+
7+
# It doesn't do exit codes properly, so we just check if it outputted anything.
8+
if [ -s stylish-out ];
9+
then
10+
echo "Stylish-haskell reported an error :("
11+
cat stylish-out
12+
exit 1
13+
fi
14+
15+
rm stylish-out
16+
17+
if git status --porcelain|grep .; # true if there was any output
18+
then
19+
echo "Git tree is dirty after stylizing.";
20+
if [ -n "$TRAVIS" ];
21+
then
22+
echo "Since we're on Travis, this is a build failure."
23+
echo "Run ./stylize.sh to stylize your tree and push the changes."
24+
exit 1
25+
fi
26+
else
27+
echo "Stylish didn't change anything :)"
28+
exit 0;
29+
fi

0 commit comments

Comments
 (0)