cln: Move column grouping functions form Report.PostingsReport to Data.Dates.

This commit is contained in:
Stephen Morgan 2021-09-17 16:15:32 +10:00 committed by Simon Michael
parent 8a6d824900
commit 35c33f342b
2 changed files with 31 additions and 21 deletions

View File

@ -66,6 +66,7 @@ module Hledger.Data.Dates (
latestSpanContaining, latestSpanContaining,
smartdate, smartdate,
splitSpan, splitSpan,
groupByDateSpan,
fixSmartDate, fixSmartDate,
fixSmartDateStr, fixSmartDateStr,
fixSmartDateStrEither, fixSmartDateStrEither,
@ -86,25 +87,28 @@ import Control.Applicative.Permutations
import Control.Monad (guard, unless) import Control.Monad (guard, unless)
import "base-compat-batteries" Data.List.Compat import "base-compat-batteries" Data.List.Compat
import Data.Char (digitToInt, isDigit, ord) import Data.Char (digitToInt, isDigit, ord)
import Data.Default import Data.Default (def)
import Data.Foldable (asum) import Data.Foldable (asum)
import Data.Function (on) import Data.Function (on)
import Data.Functor (($>)) import Data.Functor (($>))
import Data.Maybe import Data.Maybe (catMaybes, fromMaybe, isJust, mapMaybe)
import Data.Ord (comparing)
import qualified Data.Set as Set import qualified Data.Set as Set
import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as T import qualified Data.Text as T
import Data.Time.Format hiding (months) import Data.Time.Format hiding (months)
import Data.Time.Calendar import Data.Time.Calendar
import Data.Time.Calendar.OrdinalDate (Day, addDays, addGregorianYearsClip, addGregorianMonthsClip, diffDays,
import Data.Time.Clock fromGregorian, fromGregorianValid, toGregorian)
import Data.Time.LocalTime import Data.Time.Calendar.OrdinalDate (fromMondayStartWeek, mondayStartWeek)
import Data.Time.Clock (UTCTime, diffUTCTime)
import Data.Time.LocalTime (getZonedTime, localDay, zonedTimeToLocalTime)
import Safe (headMay, lastMay, maximumMay, minimumMay) import Safe (headMay, lastMay, maximumMay, minimumMay)
import Text.Megaparsec import Text.Megaparsec
import Text.Megaparsec.Char import Text.Megaparsec.Char (char, char', digitChar, string, string')
import Text.Megaparsec.Char.Lexer (decimal) import Text.Megaparsec.Char.Lexer (decimal)
import Text.Megaparsec.Custom import Text.Megaparsec.Custom (customErrorBundlePretty)
import Text.Printf import Text.Printf (printf)
import Hledger.Data.Types import Hledger.Data.Types
import Hledger.Data.Period import Hledger.Data.Period
@ -273,6 +277,22 @@ spanContainsDate (DateSpan (Just b) (Just e)) d = d >= b && d < e
periodContainsDate :: Period -> Day -> Bool periodContainsDate :: Period -> Day -> Bool
periodContainsDate p = spanContainsDate (periodAsDateSpan p) periodContainsDate p = spanContainsDate (periodAsDateSpan p)
-- | Group elements based on where they fall in a list of 'DateSpan's without
-- gaps. The precondition is not checked.
groupByDateSpan :: Bool -> (a -> Day) -> [DateSpan] -> [a] -> [(DateSpan, [a])]
groupByDateSpan showempty date colspans =
groupByCols colspans
. dropWhile (beforeStart . fst)
. sortBy (comparing fst)
. map (\x -> (date x, x))
where
groupByCols [] _ = []
groupByCols (c:cs) [] = if showempty then (c, []) : groupByCols cs [] else []
groupByCols (c:cs) ps = (c, map snd matches) : groupByCols cs later
where (matches, later) = span ((spanEnd c >) . Just . fst) ps
beforeStart = maybe (const True) (>) $ spanStart =<< headMay colspans
-- | Calculate the intersection of a number of datespans. -- | Calculate the intersection of a number of datespans.
spansIntersect [] = nulldatespan spansIntersect [] = nulldatespan
spansIntersect [d] = d spansIntersect [d] = d

View File

@ -21,10 +21,9 @@ module Hledger.Reports.PostingsReport (
) )
where where
import Data.List (nub, sortBy, sortOn) import Data.List (nub, sortOn)
import Data.List.Extra (nubSort) import Data.List.Extra (nubSort)
import Data.Maybe (fromMaybe, isJust, isNothing) import Data.Maybe (fromMaybe, isJust, isNothing)
import Data.Ord (comparing)
import Data.Text (Text) import Data.Text (Text)
import Data.Time.Calendar (Day) import Data.Time.Calendar (Day)
import Safe (headMay) import Safe (headMay)
@ -176,22 +175,13 @@ mkpostingsReportItem showdate showdesc wd mperiod p b =
-- Each summary posting will have a non-Nothing interval end date. -- Each summary posting will have a non-Nothing interval end date.
summarisePostingsByInterval :: Interval -> WhichDate -> Maybe Int -> Bool -> DateSpan -> [Posting] -> [SummaryPosting] summarisePostingsByInterval :: Interval -> WhichDate -> Maybe Int -> Bool -> DateSpan -> [Posting] -> [SummaryPosting]
summarisePostingsByInterval interval wd mdepth showempty reportspan = summarisePostingsByInterval interval wd mdepth showempty reportspan =
concatMap (\(s,ps) -> summarisePostingsInDateSpan s wd mdepth showempty $ map snd ps) concatMap (\(s,ps) -> summarisePostingsInDateSpan s wd mdepth showempty ps)
-- Group postings into their columns. We try to be efficient, since -- Group postings into their columns. We try to be efficient, since
-- there can possibly be a very large number of intervals (cf #1683) -- there can possibly be a very large number of intervals (cf #1683)
. groupByCols colspans . groupByDateSpan showempty getDate colspans
. dropWhile (beforeStart . fst)
. sortBy (comparing fst)
. map (\p -> (getDate p, p))
where where
groupByCols [] _ = []
groupByCols (c:cs) [] = if showempty then (c,[]) : groupByCols cs [] else []
groupByCols (c:cs) ps = (c, matches) : groupByCols cs later
where (matches, later) = span ((spanEnd c >) . Just . fst) ps
-- The date spans to be included as report columns. -- The date spans to be included as report columns.
colspans = splitSpan interval reportspan colspans = splitSpan interval reportspan
beforeStart = maybe (const True) (>) $ spanStart =<< headMay colspans
getDate = case wd of getDate = case wd of
PrimaryDate -> postingDate PrimaryDate -> postingDate
SecondaryDate -> postingDate2 SecondaryDate -> postingDate2