diff options
Diffstat (limited to 'Model.hs')
-rw-r--r-- | Model.hs | 90 |
1 files changed, 81 insertions, 9 deletions
@@ -10,7 +10,10 @@ import Control.Monad.Writer | |||
10 | import Data.Text (Text) | 10 | import Data.Text (Text) |
11 | import qualified Data.Text as Text | 11 | import qualified Data.Text as Text |
12 | 12 | ||
13 | import qualified Data.HashMap.Lazy as HashMap | ||
14 | |||
13 | import Data.Aeson | 15 | import Data.Aeson |
16 | import Data.Aeson.Types (Parser, Value(..)) | ||
14 | 17 | ||
15 | -- You can define all of your database entities in the entities file. | 18 | -- You can define all of your database entities in the entities file. |
16 | -- You can find more information on persistent and how to declare entities | 19 | -- You can find more information on persistent and how to declare entities |
@@ -19,6 +22,28 @@ import Data.Aeson | |||
19 | share [mkPersist sqlSettings, mkMigrate "migrateAll"] | 22 | share [mkPersist sqlSettings, mkMigrate "migrateAll"] |
20 | $(persistFileWith lowerCaseSettings "config/models") | 23 | $(persistFileWith lowerCaseSettings "config/models") |
21 | 24 | ||
25 | class HasType a where | ||
26 | getType :: ( BaseBackend backend ~ SqlBackend | ||
27 | , MonadIO m | ||
28 | , PersistStoreRead backend | ||
29 | ) => a -> ReaderT backend m Kind | ||
30 | |||
31 | instance HasType Item where | ||
32 | getType = belongsToJust itemFkType | ||
33 | |||
34 | instance HasType Reference where | ||
35 | getType = belongsToJust referenceFkType | ||
36 | |||
37 | instance HasType a => HasType (Entity a) where | ||
38 | getType Entity{..} = getType entityVal | ||
39 | |||
40 | withType :: ( BaseBackend backend ~ SqlBackend | ||
41 | , MonadIO m | ||
42 | , PersistStoreRead backend | ||
43 | , HasType a | ||
44 | ) => a -> ReaderT backend m (WithType a) | ||
45 | withType val = (val `WithType`) . kindType <$> getType val | ||
46 | |||
22 | instance Ord Item where | 47 | instance Ord Item where |
23 | x `compare` y = mconcat | 48 | x `compare` y = mconcat |
24 | [ (isNothing $ itemOpened x) `compare` (isNothing $ itemOpened y) | 49 | [ (isNothing $ itemOpened x) `compare` (isNothing $ itemOpened y) |
@@ -71,6 +96,7 @@ normalizeKind :: Text -> Text | |||
71 | normalizeKind = Text.strip . Text.toCaseFold | 96 | normalizeKind = Text.strip . Text.toCaseFold |
72 | 97 | ||
73 | data ItemDiff = DiffKind Text | 98 | data ItemDiff = DiffKind Text |
99 | | DiffType Text | ||
74 | | DiffBought (Maybe Day) | 100 | | DiffBought (Maybe Day) |
75 | | DiffExpires (Maybe Day) | 101 | | DiffExpires (Maybe Day) |
76 | | DiffOpened (Maybe Day) | 102 | | DiffOpened (Maybe Day) |
@@ -80,17 +106,63 @@ newtype ItemDiffs = ItemDiffs [ItemDiff] | |||
80 | instance FromJSON ItemDiffs where | 106 | instance FromJSON ItemDiffs where |
81 | parseJSON = withObject "ItemDiff" $ \obj -> fmap ItemDiffs . execWriterT $ do | 107 | parseJSON = withObject "ItemDiff" $ \obj -> fmap ItemDiffs . execWriterT $ do |
82 | tell =<< maybe [] (pure . DiffKind) <$> lift (obj .:? "kind") | 108 | tell =<< maybe [] (pure . DiffKind) <$> lift (obj .:? "kind") |
109 | tell =<< maybe [] (pure . DiffType) <$> lift (obj .:? "type") | ||
83 | tell =<< maybe [] (pure . DiffBought) <$> lift (obj .:! "bought") | 110 | tell =<< maybe [] (pure . DiffBought) <$> lift (obj .:! "bought") |
84 | tell =<< maybe [] (pure . DiffExpires) <$> lift (obj .:! "expires") | 111 | tell =<< maybe [] (pure . DiffExpires) <$> lift (obj .:! "expires") |
85 | tell =<< maybe [] (pure . DiffOpened) <$> lift (obj .:! "opened") | 112 | tell =<< maybe [] (pure . DiffOpened) <$> lift (obj .:! "opened") |
86 | 113 | ||
87 | toUpdate :: ItemDiffs -> [Update Item] | 114 | toUpdate :: ItemDiffs -> ([Update Item], [Update Kind]) |
88 | toUpdate (ItemDiffs ds) = do | 115 | toUpdate (ItemDiffs ds) = mconcat $ do |
89 | x <- ds | 116 | x <- ds |
90 | case x of | 117 | return $ case x of |
91 | DiffKind t -> [ ItemKind =. t | 118 | DiffKind t -> (, []) [ ItemKind =. t |
92 | , ItemNormKind =. normalizeKind t | 119 | , ItemNormKind =. normalizeKind t |
93 | ] | 120 | ] |
94 | DiffBought d -> [ ItemBought =. d ] | 121 | DiffType t -> ([], ) [ KindType =. t ] |
95 | DiffExpires d -> [ ItemExpires =. d ] | 122 | DiffBought d -> (, []) [ ItemBought =. d ] |
96 | DiffOpened d -> [ ItemOpened =. d ] | 123 | DiffExpires d -> (, []) [ ItemExpires =. d ] |
124 | DiffOpened d -> (, []) [ ItemOpened =. d ] | ||
125 | |||
126 | data WithType a = WithType { typedVal :: a, valType :: Text } | ||
127 | deriving (Eq, Ord) | ||
128 | |||
129 | typeToJSON :: ToJSON a | ||
130 | => Text -- ^ Key for value, if needed | ||
131 | -> WithType a -> Value | ||
132 | typeToJSON valKey (record `WithType` t) = Object $ HashMap.insert "type" (toJSON t) o | ||
133 | where | ||
134 | o | ||
135 | | Object o' <- toJSON record = o' | ||
136 | | otherwise = HashMap.singleton valKey $ toJSON record | ||
137 | |||
138 | typeFromJSON :: FromJSON a | ||
139 | => Maybe Text -- ^ Key for value, if needed | ||
140 | -> Value -> Parser (WithType a) | ||
141 | typeFromJSON valKey = withObject "value with type" $ \obj -> do | ||
142 | t <- obj .: "type" | ||
143 | value <- case valKey of | ||
144 | Just key -> parseJSON =<< obj .: key | ||
145 | Nothing -> parseJSON $ Object obj | ||
146 | return $ value `WithType` t | ||
147 | |||
148 | instance ToJSON (WithType Item) where | ||
149 | toJSON = typeToJSON $ error "Item is not serializing correctly" | ||
150 | |||
151 | instance ToJSON (WithType (Entity Item)) where | ||
152 | toJSON = typeToJSON $ error "Entity Item is not serializing correctly" | ||
153 | |||
154 | instance ToJSON (WithType Reference) where | ||
155 | toJSON = typeToJSON "kind" | ||
156 | |||
157 | instance ToJSON (WithType (Entity Reference)) where | ||
158 | toJSON ((Entity eId ref) `WithType` t) = object | ||
159 | [ "id" .= eId | ||
160 | , "type" .= t | ||
161 | , "kind" .= referenceKind ref | ||
162 | ] | ||
163 | |||
164 | instance FromJSON (WithType Item) where | ||
165 | parseJSON = typeFromJSON Nothing | ||
166 | |||
167 | instance FromJSON (WithType Reference) where | ||
168 | parseJSON = typeFromJSON $ Just "kind" | ||