-
-
Notifications
You must be signed in to change notification settings - Fork 321
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
web: better ToJSON instances, new FromJSON instances, utilities (#316)
- Loading branch information
1 parent
782e6d3
commit b46212a
Showing
4 changed files
with
149 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
{-# OPTIONS_GHC -fno-warn-orphans #-} | ||
|
||
--{-# LANGUAGE CPP #-} | ||
--{-# LANGUAGE DataKinds #-} | ||
--{-# LANGUAGE DeriveAnyClass #-} | ||
{-# LANGUAGE DeriveGeneric #-} | ||
--{-# LANGUAGE FlexibleContexts #-} | ||
{-# LANGUAGE FlexibleInstances #-} | ||
--{-# LANGUAGE NamedFieldPuns #-} | ||
--{-# LANGUAGE OverloadedStrings #-} | ||
{-# LANGUAGE OverloadedStrings #-} | ||
--{-# LANGUAGE PolyKinds #-} | ||
--{-# LANGUAGE QuasiQuotes #-} | ||
--{-# LANGUAGE QuasiQuotes #-} | ||
--{-# LANGUAGE Rank2Types #-} | ||
--{-# LANGUAGE RankNTypes #-} | ||
{-# LANGUAGE RecordWildCards #-} | ||
--{-# LANGUAGE ScopedTypeVariables #-} | ||
{-# LANGUAGE StandaloneDeriving #-} | ||
--{-# LANGUAGE TemplateHaskell #-} | ||
--{-# LANGUAGE TypeFamilies #-} | ||
--{-# LANGUAGE TypeOperators #-} | ||
|
||
module Hledger.Web.Json ( | ||
-- * Instances | ||
-- * Utilities | ||
readJsonFile | ||
,writeJsonFile | ||
) where | ||
|
||
import Data.Aeson | ||
--import Data.Aeson.TH | ||
import qualified Data.ByteString.Lazy as BL | ||
import Data.Decimal | ||
import Data.Maybe | ||
import GHC.Generics (Generic) | ||
|
||
import Hledger.Data | ||
|
||
-- JSON instances. See also hledger-api. | ||
-- Should they be in hledger-lib Types.hs ? | ||
|
||
-- To JSON | ||
|
||
instance ToJSON Status | ||
instance ToJSON GenericSourcePos | ||
instance ToJSON Decimal | ||
instance ToJSON Amount | ||
instance ToJSON AmountStyle | ||
instance ToJSON Side | ||
instance ToJSON DigitGroupStyle | ||
instance ToJSON MixedAmount | ||
instance ToJSON BalanceAssertion | ||
instance ToJSON Price | ||
instance ToJSON MarketPrice | ||
instance ToJSON PostingType | ||
instance ToJSON Posting where | ||
toJSON Posting{..} = object | ||
["pdate" .= toJSON pdate | ||
,"pdate2" .= toJSON pdate2 | ||
,"pstatus" .= toJSON pstatus | ||
,"paccount" .= toJSON paccount | ||
,"pamount" .= toJSON pamount | ||
,"pcomment" .= toJSON pcomment | ||
,"ptype" .= toJSON ptype | ||
,"ptags" .= toJSON ptags | ||
,"pbalanceassertion" .= toJSON pbalanceassertion | ||
-- To avoid a cycle, show just the parent transaction's index number | ||
-- in a dummy field. When re-parsed, there will be no parent. | ||
,"ptransaction_" .= toJSON (maybe "" (show.tindex) ptransaction) | ||
-- This is probably not wanted in json, we discard it. | ||
,"porigin" .= toJSON (Nothing :: Maybe Posting) | ||
] | ||
instance ToJSON Transaction | ||
instance ToJSON Account where | ||
toJSON a = object | ||
["aname" .= toJSON (aname a) | ||
,"aebalance" .= toJSON (aebalance a) | ||
,"aibalance" .= toJSON (aibalance a) | ||
,"anumpostings" .= toJSON (anumpostings a) | ||
,"aboring" .= toJSON (aboring a) | ||
-- To avoid a cycle, show just the parent account's name | ||
-- in a dummy field. When re-parsed, there will be no parent. | ||
,"aparent_" .= toJSON (maybe "" aname $ aparent a) | ||
-- To avoid a cycle, drop the subaccounts, showing just their names | ||
-- in a dummy field. When re-parsed, there will be no subaccounts. | ||
,"asubs" .= toJSON ([]::[Account]) | ||
,"asubs_" .= toJSON (map aname $ asubs a) | ||
] | ||
|
||
-- From JSON | ||
|
||
instance FromJSON Status | ||
instance FromJSON GenericSourcePos | ||
-- | ||
-- Decimal | ||
-- | ||
-- https://stackoverflow.com/questions/40331851/haskell-data-decimal-as-aeson-type | ||
----instance FromJSON Decimal where parseJSON = | ||
---- A.withScientific "Decimal" (return . right . eitherFromRational . toRational) | ||
-- | ||
-- https://github.com/PaulJohnson/Haskell-Decimal/issues/6 | ||
--deriving instance Generic Decimal | ||
--instance FromJSON Decimal | ||
deriving instance Generic (DecimalRaw Integer) | ||
instance FromJSON (DecimalRaw Integer) | ||
-- | ||
-- https://github.com/bos/aeson/issues/474 | ||
-- http://hackage.haskell.org/package/aeson-1.4.2.0/docs/Data-Aeson-TH.html | ||
-- $(deriveFromJSON defaultOptions ''Decimal) -- doesn't work | ||
-- $(deriveFromJSON defaultOptions ''DecimalRaw) -- works; requires TH, but gives better parse error messages | ||
-- | ||
instance FromJSON Amount | ||
instance FromJSON AmountStyle | ||
instance FromJSON Side | ||
instance FromJSON DigitGroupStyle | ||
instance FromJSON MixedAmount | ||
instance FromJSON BalanceAssertion | ||
instance FromJSON Price | ||
instance FromJSON MarketPrice | ||
instance FromJSON PostingType | ||
instance FromJSON Posting | ||
instance FromJSON Transaction | ||
instance FromJSON AccountDeclarationInfo | ||
instance FromJSON Account | ||
|
||
|
||
-- Utilities | ||
|
||
-- | Read a json from a file and decode/parse it as the target type, if we can. | ||
-- Example: | ||
-- >>> readJsonFile "in.json" :: IO MixedAmount | ||
readJsonFile :: FromJSON a => FilePath -> IO a | ||
readJsonFile f = do | ||
bs <- BL.readFile f | ||
let v = fromMaybe (error "could not decode bytestring as json value") (decode bs :: Maybe Value) | ||
case fromJSON v :: FromJSON a => Result a of | ||
Error e -> error e | ||
Success t -> return t | ||
|
||
-- | Write some to-JSON-convertible haskell value to a json file, if we can. | ||
-- Example: | ||
-- >>> writeJsonFile "out.json" nullmixedamt | ||
writeJsonFile :: ToJSON a => FilePath -> a -> IO () | ||
writeJsonFile f v = BL.writeFile f (encode $ toJSON v) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters