fix:PeriodData: simplify, use Day keys [#2479]
This is clearer and slightly better-performing than using Integer.
This commit is contained in:
parent
438c4a0469
commit
bd0a45d448
@ -387,7 +387,7 @@ tests_Account = testGroup "Account" [
|
|||||||
testCase "no postings, no days" $
|
testCase "no postings, no days" $
|
||||||
accountFromPostings undefined [] @?= accountTree "root" []
|
accountFromPostings undefined [] @?= accountTree "root" []
|
||||||
,testCase "no postings, only 2000-01-01" $
|
,testCase "no postings, only 2000-01-01" $
|
||||||
allAccounts (all (\d -> (ModifiedJulianDay $ toInteger d) == fromGregorian 2000 01 01) . M.keys . pdperiods . adata)
|
allAccounts (all (== fromGregorian 2000 01 01) . M.keys . pdperiods . adata)
|
||||||
(accountFromPostings undefined []) @? "Not all adata have exactly 2000-01-01"
|
(accountFromPostings undefined []) @? "Not all adata have exactly 2000-01-01"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@ -128,7 +128,7 @@ unionDayPartitions (DayPartition (PeriodData h as)) (DayPartition (PeriodData h'
|
|||||||
dayPartitionStartEnd :: DayPartition -> (Day, Day)
|
dayPartitionStartEnd :: DayPartition -> (Day, Day)
|
||||||
dayPartitionStartEnd (DayPartition (PeriodData _ ds)) =
|
dayPartitionStartEnd (DayPartition (PeriodData _ ds)) =
|
||||||
-- Guaranteed not to error because the IntMap is non-empty.
|
-- Guaranteed not to error because the IntMap is non-empty.
|
||||||
(intToDay . fst $ M.findMin ds, snd $ M.findMax ds)
|
(fst $ M.findMin ds, snd $ M.findMax ds)
|
||||||
|
|
||||||
-- | Find the start and end dates of the period within a 'DayPartition' which contains a given day.
|
-- | Find the start and end dates of the period within a 'DayPartition' which contains a given day.
|
||||||
-- If the day is after the end of the last period, it is assumed to be within the last period.
|
-- If the day is after the end of the last period, it is assumed to be within the last period.
|
||||||
@ -241,8 +241,6 @@ intervalBoundaryBefore i d =
|
|||||||
Just ((start, _) :| _ ) -> start
|
Just ((start, _) :| _ ) -> start
|
||||||
_ -> d
|
_ -> d
|
||||||
|
|
||||||
intToDay = ModifiedJulianDay . toInteger
|
|
||||||
|
|
||||||
|
|
||||||
-- tests:
|
-- tests:
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,6 @@ import Data.Maybe (fromMaybe)
|
|||||||
import Data.Text.Lazy qualified as TL
|
import Data.Text.Lazy qualified as TL
|
||||||
import Data.Text.Lazy.Builder qualified as TB
|
import Data.Text.Lazy.Builder qualified as TB
|
||||||
import Data.Map qualified as M
|
import Data.Map qualified as M
|
||||||
import Data.Time (Day (..))
|
|
||||||
import Text.Megaparsec (Pos, SourcePos, mkPos, unPos)
|
import Text.Megaparsec (Pos, SourcePos, mkPos, unPos)
|
||||||
|
|
||||||
import Hledger.Data.Types
|
import Hledger.Data.Types
|
||||||
@ -161,7 +160,7 @@ instance ToJSON BalanceData
|
|||||||
instance ToJSON a => ToJSON (PeriodData a) where
|
instance ToJSON a => ToJSON (PeriodData a) where
|
||||||
toJSON a = object
|
toJSON a = object
|
||||||
[ "pdpre" .= pdpre a
|
[ "pdpre" .= pdpre a
|
||||||
, "pdperiods" .= map (\(d, x) -> (ModifiedJulianDay (toInteger d), x)) (M.toList $ pdperiods a)
|
, "pdperiods" .= (M.toList $ pdperiods a)
|
||||||
]
|
]
|
||||||
|
|
||||||
instance ToJSON a => ToJSON (Account a) where
|
instance ToJSON a => ToJSON (Account a) where
|
||||||
@ -227,7 +226,7 @@ instance FromJSON BalanceData
|
|||||||
instance FromJSON a => FromJSON (PeriodData a) where
|
instance FromJSON a => FromJSON (PeriodData a) where
|
||||||
parseJSON = withObject "PeriodData" $ \v -> PeriodData
|
parseJSON = withObject "PeriodData" $ \v -> PeriodData
|
||||||
<$> v .: "pdpre"
|
<$> v .: "pdpre"
|
||||||
<*> (M.fromList . map (\(d, x) -> (fromInteger $ toModifiedJulianDay d, x)) <$> v .: "pdperiods")
|
<*> (M.fromList <$> v .: "pdperiods")
|
||||||
|
|
||||||
-- XXX The ToJSON instance replaces subaccounts with just names.
|
-- XXX The ToJSON instance replaces subaccounts with just names.
|
||||||
-- Here we should try to make use of those to reconstruct the
|
-- Here we should try to make use of those to reconstruct the
|
||||||
|
|||||||
@ -26,7 +26,6 @@ import Data.Foldable1 (Foldable1(..))
|
|||||||
#else
|
#else
|
||||||
import Control.Applicative (liftA2)
|
import Control.Applicative (liftA2)
|
||||||
#endif
|
#endif
|
||||||
import Data.Bifunctor (first)
|
|
||||||
#if !MIN_VERSION_base(4,20,0)
|
#if !MIN_VERSION_base(4,20,0)
|
||||||
import Data.List (foldl')
|
import Data.List (foldl')
|
||||||
#endif
|
#endif
|
||||||
@ -44,7 +43,7 @@ instance Show a => Show (PeriodData a) where
|
|||||||
showString "PeriodData"
|
showString "PeriodData"
|
||||||
. showString "{ pdpre = " . shows h
|
. showString "{ pdpre = " . shows h
|
||||||
. showString ", pdperiods = "
|
. showString ", pdperiods = "
|
||||||
. showString "fromList " . shows (map (\(day, x) -> (intToDay day, x)) $ M.toList ds)
|
. showString "fromList " . shows (M.toList ds)
|
||||||
. showChar '}'
|
. showChar '}'
|
||||||
|
|
||||||
instance Foldable PeriodData where
|
instance Foldable PeriodData where
|
||||||
@ -73,17 +72,17 @@ instance Monoid a => Monoid (PeriodData a) where
|
|||||||
|
|
||||||
-- | Construct a 'PeriodData' from a historical data value and a list of (period start, period data) pairs.
|
-- | Construct a 'PeriodData' from a historical data value and a list of (period start, period data) pairs.
|
||||||
periodDataFromList :: a -> [(Day, a)] -> PeriodData a
|
periodDataFromList :: a -> [(Day, a)] -> PeriodData a
|
||||||
periodDataFromList h = PeriodData h . M.fromList . map (\(d, a) -> (dayToInt d, a))
|
periodDataFromList h = PeriodData h . M.fromList
|
||||||
|
|
||||||
-- | Convert 'PeriodData' to a historical data value and a list of (period start, period data) pairs.
|
-- | Convert 'PeriodData' to a historical data value and a list of (period start, period data) pairs.
|
||||||
periodDataToList :: PeriodData a -> (a, [(Day, a)])
|
periodDataToList :: PeriodData a -> (a, [(Day, a)])
|
||||||
periodDataToList (PeriodData h as) = (h, map (\(s, e) -> (intToDay s, e)) $ M.toList as)
|
periodDataToList (PeriodData h as) = (h, M.toList as)
|
||||||
|
|
||||||
-- | Get the data for the period containing the given 'Day', and that period's start date.
|
-- | Get the data for the period containing the given 'Day', and that period's start date.
|
||||||
-- If the day is after the end of the last period, it is assumed to be within the last period.
|
-- If the day is after the end of the last period, it is assumed to be within the last period.
|
||||||
-- If the day is before the start of the first period (ie, in the historical period), return Nothing.
|
-- If the day is before the start of the first period (ie, in the historical period), return Nothing.
|
||||||
lookupPeriodData :: Day -> PeriodData a -> Maybe (Day, a)
|
lookupPeriodData :: Day -> PeriodData a -> Maybe (Day, a)
|
||||||
lookupPeriodData d (PeriodData _ as) = first intToDay <$> M.lookupLE (dayToInt d) as
|
lookupPeriodData d (PeriodData _ as) = M.lookupLE d as
|
||||||
|
|
||||||
-- | Get the data for the period containing the given 'Day', and that period's start date.
|
-- | Get the data for the period containing the given 'Day', and that period's start date.
|
||||||
-- If the day is after the end of the last period, it is assumed to be within the last period.
|
-- If the day is after the end of the last period, it is assumed to be within the last period.
|
||||||
@ -98,7 +97,7 @@ lookupPeriodDataOrHistorical d pd@(PeriodData h _) = case lookupPeriodData d pd
|
|||||||
insertPeriodData :: Semigroup a => Maybe Day -> a -> PeriodData a -> PeriodData a
|
insertPeriodData :: Semigroup a => Maybe Day -> a -> PeriodData a -> PeriodData a
|
||||||
insertPeriodData mday b balances = case mday of
|
insertPeriodData mday b balances = case mday of
|
||||||
Nothing -> balances{pdpre = pdpre balances <> b}
|
Nothing -> balances{pdpre = pdpre balances <> b}
|
||||||
Just day -> balances{pdperiods = M.insertWith (<>) (dayToInt day) b $ pdperiods balances}
|
Just day -> balances{pdperiods = M.insertWith (<>) day b $ pdperiods balances}
|
||||||
|
|
||||||
-- | Merge two 'PeriodData', using the given operation to combine their data values.
|
-- | Merge two 'PeriodData', using the given operation to combine their data values.
|
||||||
--
|
--
|
||||||
@ -119,8 +118,6 @@ mergePeriodData only1 only2 f = \(PeriodData h1 as1) (PeriodData h2 as2) ->
|
|||||||
padPeriodData :: a -> PeriodData b -> PeriodData a -> PeriodData a
|
padPeriodData :: a -> PeriodData b -> PeriodData a -> PeriodData a
|
||||||
padPeriodData x pad bal = bal{pdperiods = pdperiods bal <> (x <$ pdperiods pad)}
|
padPeriodData x pad bal = bal{pdperiods = pdperiods bal <> (x <$ pdperiods pad)}
|
||||||
|
|
||||||
intToDay = ModifiedJulianDay . toInteger
|
|
||||||
dayToInt = fromInteger . toModifiedJulianDay
|
|
||||||
|
|
||||||
-- tests
|
-- tests
|
||||||
|
|
||||||
|
|||||||
@ -754,10 +754,9 @@ data Account a = Account {
|
|||||||
-- The report periods are typically all the same length, but need not be.
|
-- The report periods are typically all the same length, but need not be.
|
||||||
--
|
--
|
||||||
-- Report periods are represented only by their start dates, used as the keys of a Map.
|
-- Report periods are represented only by their start dates, used as the keys of a Map.
|
||||||
-- (As integers, like the one inside the Day type, representing days before/after 1858-11-17.)
|
|
||||||
data PeriodData a = PeriodData {
|
data PeriodData a = PeriodData {
|
||||||
pdpre :: a -- ^ data for the period before the report
|
pdpre :: a -- ^ data for the period before the report
|
||||||
,pdperiods :: M.Map Integer a -- ^ data for each period within the report
|
,pdperiods :: M.Map Day a -- ^ data for each period within the report
|
||||||
} deriving (Eq, Ord, Functor, Generic)
|
} deriving (Eq, Ord, Functor, Generic)
|
||||||
|
|
||||||
-- | Data that's useful in "balance" reports:
|
-- | Data that's useful in "balance" reports:
|
||||||
|
|||||||
@ -454,7 +454,7 @@ makeMultiBalanceReportRow = makePeriodicReportRow nullmixedamt sumAndAverageMixe
|
|||||||
-- | Build a report row.
|
-- | Build a report row.
|
||||||
--
|
--
|
||||||
-- Calculate the column totals. These are always the sum of column amounts.
|
-- Calculate the column totals. These are always the sum of column amounts.
|
||||||
makePeriodicReportRow :: c -> (M.Map Integer c -> (c, c))
|
makePeriodicReportRow :: c -> (M.Map Day c -> (c, c))
|
||||||
-> ReportOpts -> (b -> c)
|
-> ReportOpts -> (b -> c)
|
||||||
-> a -> Account b -> PeriodicReportRow a c
|
-> a -> Account b -> PeriodicReportRow a c
|
||||||
makePeriodicReportRow nullEntry totalAndAverage ropts balance name acct =
|
makePeriodicReportRow nullEntry totalAndAverage ropts balance name acct =
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user