    {-|

    A general query system for matching things (accounts, postings,
    transactions..)  by various criteria, and a SimpleTextParser for query expressions.

    -}

    -- Silence safe 0.3.18's deprecation warnings for (max|min)imum(By)?Def for now
    -- (may hide other deprecation warnings too). https://github.com/ndmitchell/safe/issues/26
    {-# OPTIONS_GHC -Wno-warnings-deprecations #-}

    {-# LANGUAGE CPP                #-}
    {-# LANGUAGE FlexibleContexts   #-}
    {-# LANGUAGE OverloadedStrings  #-}
    {-# LANGUAGE ViewPatterns       #-}

    module Hledger.Query (
      -- * Query and QueryOpt
      Query(..),
      QueryOpt(..),
      payeeTag,
      noteTag,
      generatedTransactionTag,
      -- * parsing
      parseQuery,
      simplifyQuery,
      filterQuery,
      -- * accessors
      queryIsNull,
      queryIsAcct,
      queryIsAmt,
      queryIsDepth,
      queryIsDate,
      queryIsDate2,
      queryIsDateOrDate2,
      queryIsStartDateOnly,
      queryIsSym,
      queryIsReal,
      queryIsStatus,
      queryIsEmpty,
      queryStartDate,
      queryEndDate,
      queryDateSpan,
      queryDateSpan',
      queryDepth,
      inAccount,
      inAccountQuery,
      -- * matching
      matchesTransaction,
      matchesPosting,
      matchesAccount,
      matchesMixedAmount,
      matchesAmount,
      matchesCommodity,
      matchesTags,
      matchesPriceDirective,
      words'',
      prefixes,
      -- * tests
      tests_Query
    )
    where

    import Control.Applicative ((<|>), many, optional)
    import Data.Either (partitionEithers)
    import Data.List (partition)
    import Data.Maybe (fromMaybe, isJust, mapMaybe)
    #if !(MIN_VERSION_base(4,11,0))
    import Data.Monoid ((<>))
    #endif
    import qualified Data.Text as T
    import Data.Time.Calendar (Day, fromGregorian )
    import Safe (readDef, readMay, maximumByMay, maximumMay, minimumMay)
    import Text.Megaparsec (between, noneOf, sepBy)
    import Text.Megaparsec.Char (char, string)

    import Hledger.Utils hiding (words')
    import Hledger.Data.Types
    import Hledger.Data.AccountName
    import Hledger.Data.Amount (nullamt, usd)
    import Hledger.Data.Dates
    import Hledger.Data.Posting
    import Hledger.Data.Transaction

    -- | A query is a composition of search criteria, which can be used to
    -- match postings, transactions, accounts and more.
    data Query = Any              -- ^ always match
               | None             -- ^ never match
               | Not Query        -- ^ negate this match
               | Or [Query]       -- ^ match if any of these match
               | And [Query]      -- ^ match if all of these match
               | Code Regexp      -- ^ match if code matches this regexp
               | Desc Regexp      -- ^ match if description matches this regexp
               | Acct Regexp      -- ^ match postings whose account matches this regexp
               | Date DateSpan    -- ^ match if primary date in this date span
               | Date2 DateSpan   -- ^ match if secondary date in this date span
               | StatusQ Status  -- ^ match txns/postings with this status
               | Real Bool        -- ^ match if "realness" (involves a real non-virtual account ?) has this value
               | Amt OrdPlus Quantity  -- ^ match if the amount's numeric quantity is less than/greater than/equal to/unsignedly equal to some value
               | Sym Regexp       -- ^ match if the entire commodity symbol is matched by this regexp
               | Empty Bool       -- ^ if true, show zero-amount postings/accounts which are usually not shown
                                  --   more of a query option than a query criteria ?
               | Depth Int        -- ^ match if account depth is less than or equal to this value.
                                  --   Depth is sometimes used like a query (for filtering report data)
                                  --   and sometimes like a query option (for controlling display)
               | Tag Regexp (Maybe Regexp)  -- ^ match if a tag's name, and optionally its value, is matched by these respective regexps
                                            -- matching the regexp if provided, exists
        deriving (Query -> Query -> Bool
    (Query -> Query -> Bool) -> (Query -> Query -> Bool) -> Eq Query
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Query -> Query -> Bool
    $c/= :: Query -> Query -> Bool
    == :: Query -> Query -> Bool
    $c== :: Query -> Query -> Bool
    Eq,Int -> Query -> ShowS
    [Query] -> ShowS
    Query -> String
    (Int -> Query -> ShowS)
    -> (Query -> String) -> ([Query] -> ShowS) -> Show Query
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [Query] -> ShowS
    $cshowList :: [Query] -> ShowS
    show :: Query -> String
    $cshow :: Query -> String
    showsPrec :: Int -> Query -> ShowS
    $cshowsPrec :: Int -> Query -> ShowS
    Show)

    -- | Construct a payee tag
    payeeTag :: Maybe String -> Either RegexError Query
    payeeTag :: Maybe String -> Either String Query
    payeeTag = (Maybe Regexp -> Query)
    -> Either String (Maybe Regexp) -> Either String Query
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegexCI' "payee")) (Either String (Maybe Regexp) -> Either String Query)
    -> (Maybe String -> Either String (Maybe Regexp))
    -> Maybe String
    -> Either String Query
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Either String (Maybe Regexp)
    -> (String -> Either String (Maybe Regexp))
    -> Maybe String
    -> Either String (Maybe Regexp)
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe (Maybe Regexp -> Either String (Maybe Regexp)
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure Maybe Regexp
    forall a. Maybe a
    Nothing) ((Regexp -> Maybe Regexp)
    -> Either String Regexp -> Either String (Maybe Regexp)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Regexp -> Maybe Regexp
    forall a. a -> Maybe a
    Just (Either String Regexp -> Either String (Maybe Regexp))
    -> (String -> Either String Regexp)
    -> String
    -> Either String (Maybe Regexp)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Either String Regexp
    toRegexCI)

    -- | Construct a note tag
    noteTag :: Maybe String -> Either RegexError Query
    noteTag :: Maybe String -> Either String Query
    noteTag = (Maybe Regexp -> Query)
    -> Either String (Maybe Regexp) -> Either String Query
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegexCI' "note")) (Either String (Maybe Regexp) -> Either String Query)
    -> (Maybe String -> Either String (Maybe Regexp))
    -> Maybe String
    -> Either String Query
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Either String (Maybe Regexp)
    -> (String -> Either String (Maybe Regexp))
    -> Maybe String
    -> Either String (Maybe Regexp)
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe (Maybe Regexp -> Either String (Maybe Regexp)
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure Maybe Regexp
    forall a. Maybe a
    Nothing) ((Regexp -> Maybe Regexp)
    -> Either String Regexp -> Either String (Maybe Regexp)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Regexp -> Maybe Regexp
    forall a. a -> Maybe a
    Just (Either String Regexp -> Either String (Maybe Regexp))
    -> (String -> Either String Regexp)
    -> String
    -> Either String (Maybe Regexp)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Either String Regexp
    toRegexCI)

    -- | Construct a generated-transaction tag
    generatedTransactionTag :: Query
    generatedTransactionTag :: Query
    generatedTransactionTag = Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegexCI' "generated-transaction") Maybe Regexp
    forall a. Maybe a
    Nothing

    -- | A more expressive Ord, used for amt: queries. The Abs* variants
    -- compare with the absolute value of a number, ignoring sign.
    data OrdPlus = Lt | LtEq | Gt | GtEq | Eq | AbsLt | AbsLtEq | AbsGt | AbsGtEq | AbsEq
     deriving (Int -> OrdPlus -> ShowS
    [OrdPlus] -> ShowS
    OrdPlus -> String
    (Int -> OrdPlus -> ShowS)
    -> (OrdPlus -> String) -> ([OrdPlus] -> ShowS) -> Show OrdPlus
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [OrdPlus] -> ShowS
    $cshowList :: [OrdPlus] -> ShowS
    show :: OrdPlus -> String
    $cshow :: OrdPlus -> String
    showsPrec :: Int -> OrdPlus -> ShowS
    $cshowsPrec :: Int -> OrdPlus -> ShowS
    Show,OrdPlus -> OrdPlus -> Bool
    (OrdPlus -> OrdPlus -> Bool)
    -> (OrdPlus -> OrdPlus -> Bool) -> Eq OrdPlus
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: OrdPlus -> OrdPlus -> Bool
    $c/= :: OrdPlus -> OrdPlus -> Bool
    == :: OrdPlus -> OrdPlus -> Bool
    $c== :: OrdPlus -> OrdPlus -> Bool
    Eq)

    -- | A query option changes a query's/report's behaviour and output in some way.
    data QueryOpt = QueryOptInAcctOnly AccountName  -- ^ show an account register focussed on this account
                  | QueryOptInAcct AccountName      -- ^ as above but include sub-accounts in the account register
               -- | QueryOptCostBasis      -- ^ show amounts converted to cost where possible
               -- | QueryOptDate2  -- ^ show secondary dates instead of primary dates
        deriving (Int -> QueryOpt -> ShowS
    [QueryOpt] -> ShowS
    QueryOpt -> String
    (Int -> QueryOpt -> ShowS)
    -> (QueryOpt -> String) -> ([QueryOpt] -> ShowS) -> Show QueryOpt
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [QueryOpt] -> ShowS
    $cshowList :: [QueryOpt] -> ShowS
    show :: QueryOpt -> String
    $cshow :: QueryOpt -> String
    showsPrec :: Int -> QueryOpt -> ShowS
    $cshowsPrec :: Int -> QueryOpt -> ShowS
    Show, QueryOpt -> QueryOpt -> Bool
    (QueryOpt -> QueryOpt -> Bool)
    -> (QueryOpt -> QueryOpt -> Bool) -> Eq QueryOpt
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: QueryOpt -> QueryOpt -> Bool
    $c/= :: QueryOpt -> QueryOpt -> Bool
    == :: QueryOpt -> QueryOpt -> Bool
    $c== :: QueryOpt -> QueryOpt -> Bool
    Eq)

    -- parsing

    -- -- | A query restricting the account(s) to be shown in the sidebar, if any.
    -- -- Just looks at the first query option.
    -- showAccountMatcher :: [QueryOpt] -> Maybe Query
    -- showAccountMatcher (QueryOptInAcctSubsOnly a:_) = Just $ Acct True $ accountNameToAccountRegex a
    -- showAccountMatcher _ = Nothing

    -- | Convert a query expression containing zero or more
    -- space-separated terms to a query and zero or more query options; or
    -- return an error message if query parsing fails.
    --
    -- A query term is either:
    --
    -- 1. a search pattern, which matches on one or more fields, eg:
    --
    --      acct:REGEXP     - match the account name with a regular expression
    --      desc:REGEXP     - match the transaction description
    --      date:PERIODEXP  - match the date with a period expression
    --
    --    The prefix indicates the field to match, or if there is no prefix
    --    account name is assumed.
    --
    -- 2. a query option, which modifies the reporting behaviour in some
    --    way. There is currently one of these, which may appear only once:
    --
    --      inacct:FULLACCTNAME
    --
    -- The usual shell quoting rules are assumed. When a pattern contains
    -- whitespace, it (or the whole term including prefix) should be enclosed
    -- in single or double quotes.
    --
    -- Period expressions may contain relative dates, so a reference date is
    -- required to fully parse these.
    --
    -- Multiple terms are combined as follows:
    -- 1. multiple account patterns are OR'd together
    -- 2. multiple description patterns are OR'd together
    -- 3. multiple status patterns are OR'd together
    -- 4. then all terms are AND'd together
    --
    -- >>> parseQuery nulldate "expenses:dining out"
    -- Right (Or [Acct (RegexpCI "expenses:dining"),Acct (RegexpCI "out")],[])
    --
    -- >>> parseQuery nulldate "\"expenses:dining out\""
    -- Right (Acct (RegexpCI "expenses:dining out"),[])
    parseQuery :: Day -> T.Text -> Either String (Query,[QueryOpt])
    parseQuery :: Day -> Text -> Either String (Query, [QueryOpt])
    parseQuery d :: Day
    d s :: Text
    s = do
      let termstrs :: [Text]
    termstrs = [Text] -> Text -> [Text]
    words'' [Text]
    prefixes Text
    s
      [Either Query QueryOpt]
    eterms <- [Either String (Either Query QueryOpt)]
    -> Either String [Either Query QueryOpt]
    forall (t :: * -> *) (m :: * -> *) a.
    (Traversable t, Monad m) =>
    t (m a) -> m (t a)
    sequence ([Either String (Either Query QueryOpt)]
     -> Either String [Either Query QueryOpt])
    -> [Either String (Either Query QueryOpt)]
    -> Either String [Either Query QueryOpt]
    forall a b. (a -> b) -> a -> b
    $ (Text -> Either String (Either Query QueryOpt))
    -> [Text] -> [Either String (Either Query QueryOpt)]
    forall a b. (a -> b) -> [a] -> [b]
    map (Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    d) [Text]
    termstrs
      let (pats :: [Query]
    pats, opts :: [QueryOpt]
    opts) = [Either Query QueryOpt] -> ([Query], [QueryOpt])
    forall a b. [Either a b] -> ([a], [b])
    partitionEithers [Either Query QueryOpt]
    eterms
          (descpats :: [Query]
    descpats, pats' :: [Query]
    pats') = (Query -> Bool) -> [Query] -> ([Query], [Query])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    partition Query -> Bool
    queryIsDesc [Query]
    pats
          (acctpats :: [Query]
    acctpats, pats'' :: [Query]
    pats'') = (Query -> Bool) -> [Query] -> ([Query], [Query])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    partition Query -> Bool
    queryIsAcct [Query]
    pats'
          (statuspats :: [Query]
    statuspats, otherpats :: [Query]
    otherpats) = (Query -> Bool) -> [Query] -> ([Query], [Query])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    partition Query -> Bool
    queryIsStatus [Query]
    pats''
          q :: Query
    q = Query -> Query
    simplifyQuery (Query -> Query) -> Query -> Query
    forall a b. (a -> b) -> a -> b
    $ [Query] -> Query
    And ([Query] -> Query) -> [Query] -> Query
    forall a b. (a -> b) -> a -> b
    $ [[Query] -> Query
    Or [Query]
    acctpats, [Query] -> Query
    Or [Query]
    descpats, [Query] -> Query
    Or [Query]
    statuspats] [Query] -> [Query] -> [Query]
    forall a. [a] -> [a] -> [a]
    ++ [Query]
    otherpats
      (Query, [QueryOpt]) -> Either String (Query, [QueryOpt])
    forall a b. b -> Either a b
    Right (Query
    q, [QueryOpt]
    opts)

    -- XXX
    -- | Quote-and-prefix-aware version of words - don't split on spaces which
    -- are inside quotes, including quotes which may have one of the specified
    -- prefixes in front, and maybe an additional not: prefix in front of that.
    words'' :: [T.Text] -> T.Text -> [T.Text]
    words'' :: [Text] -> Text -> [Text]
    words'' prefixes :: [Text]
    prefixes = Either (ParseErrorBundle Text CustomErr) [Text] -> [Text]
    forall t e a.
    (Show t, Show (Token t), Show e) =>
    Either (ParseErrorBundle t e) a -> a
    fromparse (Either (ParseErrorBundle Text CustomErr) [Text] -> [Text])
    -> (Text -> Either (ParseErrorBundle Text CustomErr) [Text])
    -> Text
    -> [Text]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Parsec CustomErr Text [Text]
    -> Text -> Either (ParseErrorBundle Text CustomErr) [Text]
    forall e a.
    Parsec e Text a -> Text -> Either (ParseErrorBundle Text e) a
    parsewith Parsec CustomErr Text [Text]
    maybeprefixedquotedphrases -- XXX
        where
          maybeprefixedquotedphrases :: SimpleTextParser [T.Text]
          maybeprefixedquotedphrases :: Parsec CustomErr Text [Text]
    maybeprefixedquotedphrases = [TextParser Identity Text] -> TextParser Identity Text
    forall (m :: * -> *) a. [TextParser m a] -> TextParser m a
    choice' [TextParser Identity Text
    prefixedQuotedPattern, TextParser Identity Text
    singleQuotedPattern, TextParser Identity Text
    doubleQuotedPattern, TextParser Identity Text
    pattern] TextParser Identity Text
    -> ParsecT CustomErr Text Identity ()
    -> Parsec CustomErr Text [Text]
    forall (m :: * -> *) a sep. MonadPlus m => m a -> m sep -> m [a]
    `sepBy` ParsecT CustomErr Text Identity ()
    forall s (m :: * -> *).
    (Stream s, Token s ~ Char) =>
    ParsecT CustomErr s m ()
    skipNonNewlineSpaces1
          prefixedQuotedPattern :: SimpleTextParser T.Text
          prefixedQuotedPattern :: TextParser Identity Text
    prefixedQuotedPattern = do
            Text
    not' <- Text -> Maybe Text -> Text
    forall a. a -> Maybe a -> a
    fromMaybe "" (Maybe Text -> Text)
    -> ParsecT CustomErr Text Identity (Maybe Text)
    -> TextParser Identity Text
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    `fmap` (TextParser Identity Text
    -> ParsecT CustomErr Text Identity (Maybe Text)
    forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
    optional (TextParser Identity Text
     -> ParsecT CustomErr Text Identity (Maybe Text))
    -> TextParser Identity Text
    -> ParsecT CustomErr Text Identity (Maybe Text)
    forall a b. (a -> b) -> a -> b
    $ Tokens Text -> ParsecT CustomErr Text Identity (Tokens Text)
    forall e s (m :: * -> *).
    MonadParsec e s m =>
    Tokens s -> m (Tokens s)
    string "not:")
            let allowednexts :: [Text]
    allowednexts | Text -> Bool
    T.null Text
    not' = [Text]
    prefixes
                             | Bool
    otherwise   = [Text]
    prefixes [Text] -> [Text] -> [Text]
    forall a. [a] -> [a] -> [a]
    ++ [""]
            Text
    next <- [TextParser Identity Text] -> TextParser Identity Text
    forall (m :: * -> *) a. [TextParser m a] -> TextParser m a
    choice' ([TextParser Identity Text] -> TextParser Identity Text)
    -> [TextParser Identity Text] -> TextParser Identity Text
    forall a b. (a -> b) -> a -> b
    $ (Text -> TextParser Identity Text)
    -> [Text] -> [TextParser Identity Text]
    forall a b. (a -> b) -> [a] -> [b]
    map Text -> TextParser Identity Text
    forall e s (m :: * -> *).
    MonadParsec e s m =>
    Tokens s -> m (Tokens s)
    string [Text]
    allowednexts
            let prefix :: T.Text
                prefix :: Text
    prefix = Text
    not' Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    next
            Text
    p <- TextParser Identity Text
    singleQuotedPattern TextParser Identity Text
    -> TextParser Identity Text -> TextParser Identity Text
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> TextParser Identity Text
    doubleQuotedPattern
            Text -> TextParser Identity Text
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Text -> TextParser Identity Text)
    -> Text -> TextParser Identity Text
    forall a b. (a -> b) -> a -> b
    $ Text
    prefix Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text -> Text
    stripquotes Text
    p
          singleQuotedPattern :: SimpleTextParser T.Text
          singleQuotedPattern :: TextParser Identity Text
    singleQuotedPattern = ParsecT CustomErr Text Identity Char
    -> ParsecT CustomErr Text Identity Char
    -> ParsecT CustomErr Text Identity String
    -> ParsecT CustomErr Text Identity String
    forall (m :: * -> *) open close a.
    Applicative m =>
    m open -> m close -> m a -> m a
    between (Token Text -> ParsecT CustomErr Text Identity (Token Text)
    forall e s (m :: * -> *).
    (MonadParsec e s m, Token s ~ Char) =>
    Token s -> m (Token s)
    char Token Text
    '\'') (Token Text -> ParsecT CustomErr Text Identity (Token Text)
    forall e s (m :: * -> *).
    (MonadParsec e s m, Token s ~ Char) =>
    Token s -> m (Token s)
    char Token Text
    '\'') (ParsecT CustomErr Text Identity Char
    -> ParsecT CustomErr Text Identity String
    forall (f :: * -> *) a. Alternative f => f a -> f [a]
    many (ParsecT CustomErr Text Identity Char
     -> ParsecT CustomErr Text Identity String)
    -> ParsecT CustomErr Text Identity Char
    -> ParsecT CustomErr Text Identity String
    forall a b. (a -> b) -> a -> b
    $ [Token Text] -> ParsecT CustomErr Text Identity (Token Text)
    forall (f :: * -> *) e s (m :: * -> *).
    (Foldable f, MonadParsec e s m) =>
    f (Token s) -> m (Token s)
    noneOf ("'" :: [Char])) ParsecT CustomErr Text Identity String
    -> (String -> TextParser Identity Text) -> TextParser Identity Text
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Text -> TextParser Identity Text
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Text -> TextParser Identity Text)
    -> (String -> Text) -> String -> TextParser Identity Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Text
    stripquotes (Text -> Text) -> (String -> Text) -> String -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Text
    T.pack
          doubleQuotedPattern :: SimpleTextParser T.Text
          doubleQuotedPattern :: TextParser Identity Text
    doubleQuotedPattern = ParsecT CustomErr Text Identity Char
    -> ParsecT CustomErr Text Identity Char
    -> ParsecT CustomErr Text Identity String
    -> ParsecT CustomErr Text Identity String
    forall (m :: * -> *) open close a.
    Applicative m =>
    m open -> m close -> m a -> m a
    between (Token Text -> ParsecT CustomErr Text Identity (Token Text)
    forall e s (m :: * -> *).
    (MonadParsec e s m, Token s ~ Char) =>
    Token s -> m (Token s)
    char Token Text
    '"') (Token Text -> ParsecT CustomErr Text Identity (Token Text)
    forall e s (m :: * -> *).
    (MonadParsec e s m, Token s ~ Char) =>
    Token s -> m (Token s)
    char Token Text
    '"') (ParsecT CustomErr Text Identity Char
    -> ParsecT CustomErr Text Identity String
    forall (f :: * -> *) a. Alternative f => f a -> f [a]
    many (ParsecT CustomErr Text Identity Char
     -> ParsecT CustomErr Text Identity String)
    -> ParsecT CustomErr Text Identity Char
    -> ParsecT CustomErr Text Identity String
    forall a b. (a -> b) -> a -> b
    $ [Token Text] -> ParsecT CustomErr Text Identity (Token Text)
    forall (f :: * -> *) e s (m :: * -> *).
    (Foldable f, MonadParsec e s m) =>
    f (Token s) -> m (Token s)
    noneOf ("\"" :: [Char])) ParsecT CustomErr Text Identity String
    -> (String -> TextParser Identity Text) -> TextParser Identity Text
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Text -> TextParser Identity Text
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Text -> TextParser Identity Text)
    -> (String -> Text) -> String -> TextParser Identity Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Text
    stripquotes (Text -> Text) -> (String -> Text) -> String -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Text
    T.pack
          pattern :: SimpleTextParser T.Text
          pattern :: TextParser Identity Text
    pattern = (String -> Text)
    -> ParsecT CustomErr Text Identity String
    -> TextParser Identity Text
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap String -> Text
    T.pack (ParsecT CustomErr Text Identity String
     -> TextParser Identity Text)
    -> ParsecT CustomErr Text Identity String
    -> TextParser Identity Text
    forall a b. (a -> b) -> a -> b
    $ ParsecT CustomErr Text Identity Char
    -> ParsecT CustomErr Text Identity String
    forall (f :: * -> *) a. Alternative f => f a -> f [a]
    many ([Token Text] -> ParsecT CustomErr Text Identity (Token Text)
    forall (f :: * -> *) e s (m :: * -> *).
    (Foldable f, MonadParsec e s m) =>
    f (Token s) -> m (Token s)
    noneOf (" \n\r" :: [Char]))

    -- XXX
    -- keep synced with patterns below, excluding "not"
    prefixes :: [T.Text]
    prefixes :: [Text]
    prefixes = (Text -> Text) -> [Text] -> [Text]
    forall a b. (a -> b) -> [a] -> [b]
    map (Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <>":") [
         "inacctonly"
        ,"inacct"
        ,"amt"
        ,"code"
        ,"desc"
        ,"payee"
        ,"note"
        ,"acct"
        ,"date"
        ,"date2"
        ,"status"
        ,"cur"
        ,"real"
        ,"empty"
        ,"depth"
        ,"tag"
        ]

    defaultprefix :: T.Text
    defaultprefix :: Text
    defaultprefix = "acct"

    -- -- | Parse the query string as a boolean tree of match patterns.
    -- parseQueryTerm :: String -> Query
    -- parseQueryTerm s = either (const (Any)) id $ runParser query () "" $ lexmatcher s

    -- lexmatcher :: String -> [String]
    -- lexmatcher s = words' s

    -- query :: GenParser String () Query
    -- query = undefined

    -- | Parse a single query term as either a query or a query option,
    -- or return an error message if parsing fails.
    parseQueryTerm :: Day -> T.Text -> Either String (Either Query QueryOpt)
    parseQueryTerm :: Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm _ (Text -> Text -> Maybe Text
    T.stripPrefix "inacctonly:" -> Just s :: Text
    s) = Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Either Query QueryOpt -> Either String (Either Query QueryOpt))
    -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ QueryOpt -> Either Query QueryOpt
    forall a b. b -> Either a b
    Right (QueryOpt -> Either Query QueryOpt)
    -> QueryOpt -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Text -> QueryOpt
    QueryOptInAcctOnly Text
    s
    parseQueryTerm _ (Text -> Text -> Maybe Text
    T.stripPrefix "inacct:" -> Just s :: Text
    s) = Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Either Query QueryOpt -> Either String (Either Query QueryOpt))
    -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ QueryOpt -> Either Query QueryOpt
    forall a b. b -> Either a b
    Right (QueryOpt -> Either Query QueryOpt)
    -> QueryOpt -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Text -> QueryOpt
    QueryOptInAcct Text
    s
    parseQueryTerm d :: Day
    d (Text -> Text -> Maybe Text
    T.stripPrefix "not:" -> Just s :: Text
    s) =
      case Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    d Text
    s of
        Right (Left m :: Query
    m)  -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Either Query QueryOpt -> Either String (Either Query QueryOpt))
    -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Query -> Query
    Not Query
    m
        Right (Right _) -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Either Query QueryOpt -> Either String (Either Query QueryOpt))
    -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left Query
    Any -- not:somequeryoption will be ignored
        Left err :: String
    err        -> String -> Either String (Either Query QueryOpt)
    forall a b. a -> Either a b
    Left String
    err
    parseQueryTerm _ (Text -> Text -> Maybe Text
    T.stripPrefix "code:" -> Just s :: Text
    s) = Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt)
    -> (Regexp -> Query) -> Regexp -> Either Query QueryOpt
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Regexp -> Query
    Code (Regexp -> Either Query QueryOpt)
    -> Either String Regexp -> Either String (Either Query QueryOpt)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> Either String Regexp
    toRegexCI (Text -> String
    T.unpack Text
    s)
    parseQueryTerm _ (Text -> Text -> Maybe Text
    T.stripPrefix "desc:" -> Just s :: Text
    s) = Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt)
    -> (Regexp -> Query) -> Regexp -> Either Query QueryOpt
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Regexp -> Query
    Desc (Regexp -> Either Query QueryOpt)
    -> Either String Regexp -> Either String (Either Query QueryOpt)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> Either String Regexp
    toRegexCI (Text -> String
    T.unpack Text
    s)
    parseQueryTerm _ (Text -> Text -> Maybe Text
    T.stripPrefix "payee:" -> Just s :: Text
    s) = Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt)
    -> Either String Query -> Either String (Either Query QueryOpt)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe String -> Either String Query
    payeeTag (String -> Maybe String
    forall a. a -> Maybe a
    Just (String -> Maybe String) -> String -> Maybe String
    forall a b. (a -> b) -> a -> b
    $ Text -> String
    T.unpack Text
    s)
    parseQueryTerm _ (Text -> Text -> Maybe Text
    T.stripPrefix "note:" -> Just s :: Text
    s) = Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt)
    -> Either String Query -> Either String (Either Query QueryOpt)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe String -> Either String Query
    noteTag (String -> Maybe String
    forall a. a -> Maybe a
    Just (String -> Maybe String) -> String -> Maybe String
    forall a b. (a -> b) -> a -> b
    $ Text -> String
    T.unpack Text
    s)
    parseQueryTerm _ (Text -> Text -> Maybe Text
    T.stripPrefix "acct:" -> Just s :: Text
    s) = Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt)
    -> (Regexp -> Query) -> Regexp -> Either Query QueryOpt
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Regexp -> Query
    Acct (Regexp -> Either Query QueryOpt)
    -> Either String Regexp -> Either String (Either Query QueryOpt)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> Either String Regexp
    toRegexCI (Text -> String
    T.unpack Text
    s)
    parseQueryTerm d :: Day
    d (Text -> Text -> Maybe Text
    T.stripPrefix "date2:" -> Just s :: Text
    s) =
            case Day
    -> Text
    -> Either (ParseErrorBundle Text CustomErr) (Interval, DateSpan)
    parsePeriodExpr Day
    d Text
    s of Left e :: ParseErrorBundle Text CustomErr
    e         -> String -> Either String (Either Query QueryOpt)
    forall a b. a -> Either a b
    Left (String -> Either String (Either Query QueryOpt))
    -> String -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ "\"date2:"String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++Text -> String
    T.unpack Text
    sString -> ShowS
    forall a. [a] -> [a] -> [a]
    ++"\" gave a "String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ParseErrorBundle Text CustomErr -> String
    forall t e.
    (Show t, Show (Token t), Show e) =>
    ParseErrorBundle t e -> String
    showDateParseError ParseErrorBundle Text CustomErr
    e
                                        Right (_,span :: DateSpan
    span) -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Either Query QueryOpt -> Either String (Either Query QueryOpt))
    -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ DateSpan -> Query
    Date2 DateSpan
    span
    parseQueryTerm d :: Day
    d (Text -> Text -> Maybe Text
    T.stripPrefix "date:" -> Just s :: Text
    s) =
            case Day
    -> Text
    -> Either (ParseErrorBundle Text CustomErr) (Interval, DateSpan)
    parsePeriodExpr Day
    d Text
    s of Left e :: ParseErrorBundle Text CustomErr
    e         -> String -> Either String (Either Query QueryOpt)
    forall a b. a -> Either a b
    Left (String -> Either String (Either Query QueryOpt))
    -> String -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ "\"date:"String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++Text -> String
    T.unpack Text
    sString -> ShowS
    forall a. [a] -> [a] -> [a]
    ++"\" gave a "String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ParseErrorBundle Text CustomErr -> String
    forall t e.
    (Show t, Show (Token t), Show e) =>
    ParseErrorBundle t e -> String
    showDateParseError ParseErrorBundle Text CustomErr
    e
                                        Right (_,span :: DateSpan
    span) -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Either Query QueryOpt -> Either String (Either Query QueryOpt))
    -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ DateSpan -> Query
    Date DateSpan
    span
    parseQueryTerm _ (Text -> Text -> Maybe Text
    T.stripPrefix "status:" -> Just s :: Text
    s) =
            case Text -> Either String Status
    parseStatus Text
    s of Left e :: String
    e   -> String -> Either String (Either Query QueryOpt)
    forall a b. a -> Either a b
    Left (String -> Either String (Either Query QueryOpt))
    -> String -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ "\"status:"String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++Text -> String
    T.unpack Text
    sString -> ShowS
    forall a. [a] -> [a] -> [a]
    ++"\" gave a parse error: " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    e
                                  Right st :: Status
    st -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Either Query QueryOpt -> Either String (Either Query QueryOpt))
    -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Status -> Query
    StatusQ Status
    st
    parseQueryTerm _ (Text -> Text -> Maybe Text
    T.stripPrefix "real:" -> Just s :: Text
    s) = Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Either Query QueryOpt -> Either String (Either Query QueryOpt))
    -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Bool -> Query
    Real (Bool -> Query) -> Bool -> Query
    forall a b. (a -> b) -> a -> b
    $ Text -> Bool
    parseBool Text
    s Bool -> Bool -> Bool
    || Text -> Bool
    T.null Text
    s
    parseQueryTerm _ (Text -> Text -> Maybe Text
    T.stripPrefix "amt:" -> Just s :: Text
    s) = Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Either Query QueryOpt -> Either String (Either Query QueryOpt))
    -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ OrdPlus -> Quantity -> Query
    Amt OrdPlus
    ord Quantity
    q where (ord :: OrdPlus
    ord, q :: Quantity
    q) = (String -> (OrdPlus, Quantity))
    -> ((OrdPlus, Quantity) -> (OrdPlus, Quantity))
    -> Either String (OrdPlus, Quantity)
    -> (OrdPlus, Quantity)
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either String -> (OrdPlus, Quantity)
    forall a. HasCallStack => String -> a
    error (OrdPlus, Quantity) -> (OrdPlus, Quantity)
    forall a. a -> a
    id (Either String (OrdPlus, Quantity) -> (OrdPlus, Quantity))
    -> Either String (OrdPlus, Quantity) -> (OrdPlus, Quantity)
    forall a b. (a -> b) -> a -> b
    $ Text -> Either String (OrdPlus, Quantity)
    parseAmountQueryTerm Text
    s  -- PARTIAL:
    parseQueryTerm _ (Text -> Text -> Maybe Text
    T.stripPrefix "empty:" -> Just s :: Text
    s) = Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Either Query QueryOpt -> Either String (Either Query QueryOpt))
    -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Bool -> Query
    Empty (Bool -> Query) -> Bool -> Query
    forall a b. (a -> b) -> a -> b
    $ Text -> Bool
    parseBool Text
    s
    parseQueryTerm _ (Text -> Text -> Maybe Text
    T.stripPrefix "depth:" -> Just s :: Text
    s)
      | Int
    n Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    >= 0    = Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Either Query QueryOpt -> Either String (Either Query QueryOpt))
    -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Int -> Query
    Depth Int
    n
      | Bool
    otherwise = String -> Either String (Either Query QueryOpt)
    forall a b. a -> Either a b
    Left "depth: should have a positive number"
      where n :: Int
    n = Int -> String -> Int
    forall a. Read a => a -> String -> a
    readDef 0 (Text -> String
    T.unpack Text
    s)

    parseQueryTerm _ (Text -> Text -> Maybe Text
    T.stripPrefix "cur:" -> Just s :: Text
    s) = Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt)
    -> (Regexp -> Query) -> Regexp -> Either Query QueryOpt
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Regexp -> Query
    Sym (Regexp -> Either Query QueryOpt)
    -> Either String Regexp -> Either String (Either Query QueryOpt)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> Either String Regexp
    toRegexCI ('^' Char -> ShowS
    forall a. a -> [a] -> [a]
    : Text -> String
    T.unpack Text
    s String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ "$") -- support cur: as an alias
    parseQueryTerm _ (Text -> Text -> Maybe Text
    T.stripPrefix "tag:" -> Just s :: Text
    s) = Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt)
    -> Either String Query -> Either String (Either Query QueryOpt)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Text -> Either String Query
    parseTag Text
    s
    parseQueryTerm _ "" = Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Either Query QueryOpt -> Either String (Either Query QueryOpt))
    -> Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Query
    Any
    parseQueryTerm d :: Day
    d s :: Text
    s = Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    d (Text -> Either String (Either Query QueryOpt))
    -> Text -> Either String (Either Query QueryOpt)
    forall a b. (a -> b) -> a -> b
    $ Text
    defaultprefixText -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <>":"Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <>Text
    s

    -- | Parse the argument of an amt query term ([OP][SIGN]NUM), to an
    -- OrdPlus and a Quantity, or if parsing fails, an error message. OP
    -- can be <=, <, >=, >, or = . NUM can be a simple integer or decimal.
    -- If a decimal, the decimal mark must be period, and it must have
    -- digits preceding it. Digit group marks are not allowed.
    parseAmountQueryTerm :: T.Text -> Either String (OrdPlus, Quantity)
    parseAmountQueryTerm :: Text -> Either String (OrdPlus, Quantity)
    parseAmountQueryTerm amtarg :: Text
    amtarg =
      case Text
    amtarg of
        -- number has a + sign, do a signed comparison
        (Text -> Text -> Maybe Quantity
    parse "<=+" -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    LtEq    ,Quantity
    q)
        (Text -> Text -> Maybe Quantity
    parse "<+"  -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    Lt      ,Quantity
    q)
        (Text -> Text -> Maybe Quantity
    parse ">=+" -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    GtEq    ,Quantity
    q)
        (Text -> Text -> Maybe Quantity
    parse ">+"  -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    Gt      ,Quantity
    q)
        (Text -> Text -> Maybe Quantity
    parse "=+"  -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    Eq      ,Quantity
    q)
        (Text -> Text -> Maybe Quantity
    parse "+"   -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    Eq      ,Quantity
    q)
        -- number has a - sign, do a signed comparison
        (Text -> Text -> Maybe Quantity
    parse "<-"  -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    Lt      ,-Quantity
    q)
        (Text -> Text -> Maybe Quantity
    parse "<=-" -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    LtEq    ,-Quantity
    q)
        (Text -> Text -> Maybe Quantity
    parse ">-"  -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    Gt      ,-Quantity
    q)
        (Text -> Text -> Maybe Quantity
    parse ">=-" -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    GtEq    ,-Quantity
    q)
        (Text -> Text -> Maybe Quantity
    parse "=-"  -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    Eq      ,-Quantity
    q)
        (Text -> Text -> Maybe Quantity
    parse "-"   -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    Eq      ,-Quantity
    q)
        -- number is unsigned and zero, do a signed comparison (more useful)
        (Text -> Text -> Maybe Quantity
    parse "<="  -> Just 0) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    LtEq    ,0)
        (Text -> Text -> Maybe Quantity
    parse "<"   -> Just 0) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    Lt      ,0)
        (Text -> Text -> Maybe Quantity
    parse ">="  -> Just 0) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    GtEq    ,0)
        (Text -> Text -> Maybe Quantity
    parse ">"   -> Just 0) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    Gt      ,0)
        -- number is unsigned and non-zero, do an absolute magnitude comparison
        (Text -> Text -> Maybe Quantity
    parse "<="  -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    AbsLtEq ,Quantity
    q)
        (Text -> Text -> Maybe Quantity
    parse "<"   -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    AbsLt   ,Quantity
    q)
        (Text -> Text -> Maybe Quantity
    parse ">="  -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    AbsGtEq ,Quantity
    q)
        (Text -> Text -> Maybe Quantity
    parse ">"   -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    AbsGt   ,Quantity
    q)
        (Text -> Text -> Maybe Quantity
    parse "="   -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    AbsEq   ,Quantity
    q)
        (Text -> Text -> Maybe Quantity
    parse ""    -> Just q :: Quantity
    q) -> (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    AbsEq   ,Quantity
    q)
        _ -> String -> Either String (OrdPlus, Quantity)
    forall a b. a -> Either a b
    Left (String -> Either String (OrdPlus, Quantity))
    -> String -> Either String (OrdPlus, Quantity)
    forall a b. (a -> b) -> a -> b
    $
             "could not parse as a comparison operator followed by an optionally-signed number: "
             String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ Text -> String
    T.unpack Text
    amtarg
      where
        -- Strip outer whitespace from the text, require and remove the
        -- specified prefix, remove all whitespace from the remainder, and
        -- read it as a simple integer or decimal if possible.
        parse :: T.Text -> T.Text -> Maybe Quantity
        parse :: Text -> Text -> Maybe Quantity
    parse p :: Text
    p s :: Text
    s = (Text -> Text -> Maybe Text
    T.stripPrefix Text
    p (Text -> Maybe Text) -> (Text -> Text) -> Text -> Maybe Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Text
    T.strip) Text
    s Maybe Text -> (Text -> Maybe Quantity) -> Maybe Quantity
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= String -> Maybe Quantity
    forall a. Read a => String -> Maybe a
    readMay (String -> Maybe Quantity)
    -> (Text -> String) -> Text -> Maybe Quantity
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Char -> Bool) -> ShowS
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Bool -> Bool
    not(Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .(Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    ==' ')) ShowS -> (Text -> String) -> Text -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> String
    T.unpack

    parseTag :: T.Text -> Either RegexError Query
    parseTag :: Text -> Either String Query
    parseTag s :: Text
    s = do
        Regexp
    tag <- String -> Either String Regexp
    toRegexCI (String -> Either String Regexp)
    -> (Text -> String) -> Text -> Either String Regexp
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> String
    T.unpack (Text -> Either String Regexp) -> Text -> Either String Regexp
    forall a b. (a -> b) -> a -> b
    $ if Text -> Bool
    T.null Text
    v then Text
    s else Text
    n
        Maybe Regexp
    body <- if Text -> Bool
    T.null Text
    v then Maybe Regexp -> Either String (Maybe Regexp)
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure Maybe Regexp
    forall a. Maybe a
    Nothing else Regexp -> Maybe Regexp
    forall a. a -> Maybe a
    Just (Regexp -> Maybe Regexp)
    -> Either String Regexp -> Either String (Maybe Regexp)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> Either String Regexp
    toRegexCI (ShowS
    forall a. [a] -> [a]
    tail ShowS -> ShowS
    forall a b. (a -> b) -> a -> b
    $ Text -> String
    T.unpack Text
    v)
        Query -> Either String Query
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Query -> Either String Query) -> Query -> Either String Query
    forall a b. (a -> b) -> a -> b
    $ Regexp -> Maybe Regexp -> Query
    Tag Regexp
    tag Maybe Regexp
    body
      where (n :: Text
    n,v :: Text
    v) = (Char -> Bool) -> Text -> (Text, Text)
    T.break (Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    =='=') Text
    s

    -- | Parse the value part of a "status:" query, or return an error.
    parseStatus :: T.Text -> Either String Status
    parseStatus :: Text -> Either String Status
    parseStatus s :: Text
    s | Text
    s Text -> [Text] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` ["*","1"] = Status -> Either String Status
    forall a b. b -> Either a b
    Right Status
    Cleared
                  | Text
    s Text -> [Text] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` ["!"]     = Status -> Either String Status
    forall a b. b -> Either a b
    Right Status
    Pending
                  | Text
    s Text -> [Text] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` ["","0"]  = Status -> Either String Status
    forall a b. b -> Either a b
    Right Status
    Unmarked
                  | Bool
    otherwise          = String -> Either String Status
    forall a b. a -> Either a b
    Left (String -> Either String Status) -> String -> Either String Status
    forall a b. (a -> b) -> a -> b
    $ "could not parse "String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++Text -> String
    forall a. Show a => a -> String
    show Text
    sString -> ShowS
    forall a. [a] -> [a] -> [a]
    ++" as a status (should be *, ! or empty)"

    -- | Parse the boolean value part of a "status:" query. "1" means true,
    -- anything else will be parsed as false without error.
    parseBool :: T.Text -> Bool
    parseBool :: Text -> Bool
    parseBool s :: Text
    s = Text
    s Text -> [Text] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [Text]
    truestrings

    truestrings :: [T.Text]
    truestrings :: [Text]
    truestrings = ["1"]

    simplifyQuery :: Query -> Query
    simplifyQuery :: Query -> Query
    simplifyQuery q :: Query
    q =
      let q' :: Query
    q' = Query -> Query
    simplify Query
    q
      in if Query
    q' Query -> Query -> Bool
    forall a. Eq a => a -> a -> Bool
    == Query
    q then Query
    q else Query -> Query
    simplifyQuery Query
    q'
      where
        simplify :: Query -> Query
    simplify (And []) = Query
    Any
        simplify (And [q :: Query
    q]) = Query -> Query
    simplify Query
    q
        simplify (And qs :: [Query]
    qs) | [Query] -> Bool
    forall a. Eq a => [a] -> Bool
    same [Query]
    qs = Query -> Query
    simplify (Query -> Query) -> Query -> Query
    forall a b. (a -> b) -> a -> b
    $ [Query] -> Query
    forall a. [a] -> a
    head [Query]
    qs
                          | (Query -> Bool) -> [Query] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Query -> Query -> Bool
    forall a. Eq a => a -> a -> Bool
    ==Query
    None) [Query]
    qs = Query
    None
                          | (Query -> Bool) -> [Query] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all Query -> Bool
    queryIsDate [Query]
    qs = DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ [DateSpan] -> DateSpan
    spansIntersect ([DateSpan] -> DateSpan) -> [DateSpan] -> DateSpan
    forall a b. (a -> b) -> a -> b
    $ (Query -> Maybe DateSpan) -> [Query] -> [DateSpan]
    forall a b. (a -> Maybe b) -> [a] -> [b]
    mapMaybe Query -> Maybe DateSpan
    queryTermDateSpan [Query]
    qs
                          | Bool
    otherwise = [Query] -> Query
    And ([Query] -> Query) -> [Query] -> Query
    forall a b. (a -> b) -> a -> b
    $ [[Query]] -> [Query]
    forall (t :: * -> *) a. Foldable t => t [a] -> [a]
    concat ([[Query]] -> [Query]) -> [[Query]] -> [Query]
    forall a b. (a -> b) -> a -> b
    $ [(Query -> Query) -> [Query] -> [Query]
    forall a b. (a -> b) -> [a] -> [b]
    map Query -> Query
    simplify [Query]
    dateqs, (Query -> Query) -> [Query] -> [Query]
    forall a b. (a -> b) -> [a] -> [b]
    map Query -> Query
    simplify [Query]
    otherqs]
                          where (dateqs :: [Query]
    dateqs, otherqs :: [Query]
    otherqs) = (Query -> Bool) -> [Query] -> ([Query], [Query])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    partition Query -> Bool
    queryIsDate ([Query] -> ([Query], [Query])) -> [Query] -> ([Query], [Query])
    forall a b. (a -> b) -> a -> b
    $ (Query -> Bool) -> [Query] -> [Query]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Query -> Query -> Bool
    forall a. Eq a => a -> a -> Bool
    /=Query
    Any) [Query]
    qs
        simplify (Or []) = Query
    Any
        simplify (Or [q :: Query
    q]) = Query -> Query
    simplifyQuery Query
    q
        simplify (Or qs :: [Query]
    qs) | [Query] -> Bool
    forall a. Eq a => [a] -> Bool
    same [Query]
    qs = Query -> Query
    simplify (Query -> Query) -> Query -> Query
    forall a b. (a -> b) -> a -> b
    $ [Query] -> Query
    forall a. [a] -> a
    head [Query]
    qs
                         | (Query -> Bool) -> [Query] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Query -> Query -> Bool
    forall a. Eq a => a -> a -> Bool
    ==Query
    Any) [Query]
    qs = Query
    Any
                         -- all queryIsDate qs = Date $ spansUnion $ mapMaybe queryTermDateSpan qs  ?
                         | Bool
    otherwise = [Query] -> Query
    Or ([Query] -> Query) -> [Query] -> Query
    forall a b. (a -> b) -> a -> b
    $ (Query -> Query) -> [Query] -> [Query]
    forall a b. (a -> b) -> [a] -> [b]
    map Query -> Query
    simplify ([Query] -> [Query]) -> [Query] -> [Query]
    forall a b. (a -> b) -> a -> b
    $ (Query -> Bool) -> [Query] -> [Query]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Query -> Query -> Bool
    forall a. Eq a => a -> a -> Bool
    /=Query
    None) [Query]
    qs
        simplify (Date (DateSpan Nothing Nothing)) = Query
    Any
        simplify (Date2 (DateSpan Nothing Nothing)) = Query
    Any
        simplify q :: Query
    q = Query
    q

    same :: [a] -> Bool
    same [] = Bool
    True
    same (a :: a
    a:as :: [a]
    as) = (a -> Bool) -> [a] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all (a
    aa -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    ==) [a]
    as

    -- | Remove query terms (or whole sub-expressions) not matching the given
    -- predicate from this query.  XXX Semantics not completely clear.
    filterQuery :: (Query -> Bool) -> Query -> Query
    filterQuery :: (Query -> Bool) -> Query -> Query
    filterQuery p :: Query -> Bool
    p = Query -> Query
    simplifyQuery (Query -> Query) -> (Query -> Query) -> Query -> Query
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Query -> Bool) -> Query -> Query
    filterQuery' Query -> Bool
    p

    filterQuery' :: (Query -> Bool) -> Query -> Query
    filterQuery' :: (Query -> Bool) -> Query -> Query
    filterQuery' p :: Query -> Bool
    p (And qs :: [Query]
    qs) = [Query] -> Query
    And ([Query] -> Query) -> [Query] -> Query
    forall a b. (a -> b) -> a -> b
    $ (Query -> Query) -> [Query] -> [Query]
    forall a b. (a -> b) -> [a] -> [b]
    map ((Query -> Bool) -> Query -> Query
    filterQuery Query -> Bool
    p) [Query]
    qs
    filterQuery' p :: Query -> Bool
    p (Or qs :: [Query]
    qs) = [Query] -> Query
    Or ([Query] -> Query) -> [Query] -> Query
    forall a b. (a -> b) -> a -> b
    $ (Query -> Query) -> [Query] -> [Query]
    forall a b. (a -> b) -> [a] -> [b]
    map ((Query -> Bool) -> Query -> Query
    filterQuery Query -> Bool
    p) [Query]
    qs
    -- filterQuery' p (Not q) = Not $ filterQuery p q
    filterQuery' p :: Query -> Bool
    p q :: Query
    q = if Query -> Bool
    p Query
    q then Query
    q else Query
    Any

    -- * accessors

    -- | Does this query match everything ?
    queryIsNull :: Query -> Bool
    queryIsNull :: Query -> Bool
    queryIsNull Any = Bool
    True
    queryIsNull (And []) = Bool
    True
    queryIsNull (Not (Or [])) = Bool
    True
    queryIsNull _ = Bool
    False

    queryIsDepth :: Query -> Bool
    queryIsDepth :: Query -> Bool
    queryIsDepth (Depth _) = Bool
    True
    queryIsDepth _ = Bool
    False

    queryIsDate :: Query -> Bool
    queryIsDate :: Query -> Bool
    queryIsDate (Date _) = Bool
    True
    queryIsDate _ = Bool
    False

    queryIsDate2 :: Query -> Bool
    queryIsDate2 :: Query -> Bool
    queryIsDate2 (Date2 _) = Bool
    True
    queryIsDate2 _ = Bool
    False

    queryIsDateOrDate2 :: Query -> Bool
    queryIsDateOrDate2 :: Query -> Bool
    queryIsDateOrDate2 (Date _) = Bool
    True
    queryIsDateOrDate2 (Date2 _) = Bool
    True
    queryIsDateOrDate2 _ = Bool
    False

    queryIsDesc :: Query -> Bool
    queryIsDesc :: Query -> Bool
    queryIsDesc (Desc _) = Bool
    True
    queryIsDesc _ = Bool
    False

    queryIsAcct :: Query -> Bool
    queryIsAcct :: Query -> Bool
    queryIsAcct (Acct _) = Bool
    True
    queryIsAcct _ = Bool
    False

    queryIsAmt :: Query -> Bool
    queryIsAmt :: Query -> Bool
    queryIsAmt (Amt _ _) = Bool
    True
    queryIsAmt _         = Bool
    False

    queryIsSym :: Query -> Bool
    queryIsSym :: Query -> Bool
    queryIsSym (Sym _) = Bool
    True
    queryIsSym _ = Bool
    False

    queryIsReal :: Query -> Bool
    queryIsReal :: Query -> Bool
    queryIsReal (Real _) = Bool
    True
    queryIsReal _ = Bool
    False

    queryIsStatus :: Query -> Bool
    queryIsStatus :: Query -> Bool
    queryIsStatus (StatusQ _) = Bool
    True
    queryIsStatus _ = Bool
    False

    queryIsEmpty :: Query -> Bool
    queryIsEmpty :: Query -> Bool
    queryIsEmpty (Empty _) = Bool
    True
    queryIsEmpty _ = Bool
    False

    -- | Does this query specify a start date and nothing else (that would
    -- filter postings prior to the date) ?
    -- When the flag is true, look for a starting secondary date instead.
    queryIsStartDateOnly :: Bool -> Query -> Bool
    queryIsStartDateOnly :: Bool -> Query -> Bool
    queryIsStartDateOnly _ Any = Bool
    False
    queryIsStartDateOnly _ None = Bool
    False
    queryIsStartDateOnly secondary :: Bool
    secondary (Or ms :: [Query]
    ms) = [Bool] -> Bool
    forall (t :: * -> *). Foldable t => t Bool -> Bool
    and ([Bool] -> Bool) -> [Bool] -> Bool
    forall a b. (a -> b) -> a -> b
    $ (Query -> Bool) -> [Query] -> [Bool]
    forall a b. (a -> b) -> [a] -> [b]
    map (Bool -> Query -> Bool
    queryIsStartDateOnly Bool
    secondary) [Query]
    ms
    queryIsStartDateOnly secondary :: Bool
    secondary (And ms :: [Query]
    ms) = [Bool] -> Bool
    forall (t :: * -> *). Foldable t => t Bool -> Bool
    and ([Bool] -> Bool) -> [Bool] -> Bool
    forall a b. (a -> b) -> a -> b
    $ (Query -> Bool) -> [Query] -> [Bool]
    forall a b. (a -> b) -> [a] -> [b]
    map (Bool -> Query -> Bool
    queryIsStartDateOnly Bool
    secondary) [Query]
    ms
    queryIsStartDateOnly False (Date (DateSpan (Just _) _)) = Bool
    True
    queryIsStartDateOnly True (Date2 (DateSpan (Just _) _)) = Bool
    True
    queryIsStartDateOnly _ _ = Bool
    False

    -- | What start date (or secondary date) does this query specify, if any ?
    -- For OR expressions, use the earliest of the dates. NOT is ignored.
    queryStartDate :: Bool -> Query -> Maybe Day
    queryStartDate :: Bool -> Query -> Maybe Day
    queryStartDate secondary :: Bool
    secondary (Or ms :: [Query]
    ms) = [Maybe Day] -> Maybe Day
    earliestMaybeDate ([Maybe Day] -> Maybe Day) -> [Maybe Day] -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ (Query -> Maybe Day) -> [Query] -> [Maybe Day]
    forall a b. (a -> b) -> [a] -> [b]
    map (Bool -> Query -> Maybe Day
    queryStartDate Bool
    secondary) [Query]
    ms
    queryStartDate secondary :: Bool
    secondary (And ms :: [Query]
    ms) = [Maybe Day] -> Maybe Day
    latestMaybeDate ([Maybe Day] -> Maybe Day) -> [Maybe Day] -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ (Query -> Maybe Day) -> [Query] -> [Maybe Day]
    forall a b. (a -> b) -> [a] -> [b]
    map (Bool -> Query -> Maybe Day
    queryStartDate Bool
    secondary) [Query]
    ms
    queryStartDate False (Date (DateSpan (Just d :: Day
    d) _)) = Day -> Maybe Day
    forall a. a -> Maybe a
    Just Day
    d
    queryStartDate True (Date2 (DateSpan (Just d :: Day
    d) _)) = Day -> Maybe Day
    forall a. a -> Maybe a
    Just Day
    d
    queryStartDate _ _ = Maybe Day
    forall a. Maybe a
    Nothing

    -- | What end date (or secondary date) does this query specify, if any ?
    -- For OR expressions, use the latest of the dates. NOT is ignored.
    queryEndDate :: Bool -> Query -> Maybe Day
    queryEndDate :: Bool -> Query -> Maybe Day
    queryEndDate secondary :: Bool
    secondary (Or ms :: [Query]
    ms) = [Maybe Day] -> Maybe Day
    latestMaybeDate' ([Maybe Day] -> Maybe Day) -> [Maybe Day] -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ (Query -> Maybe Day) -> [Query] -> [Maybe Day]
    forall a b. (a -> b) -> [a] -> [b]
    map (Bool -> Query -> Maybe Day
    queryEndDate Bool
    secondary) [Query]
    ms
    queryEndDate secondary :: Bool
    secondary (And ms :: [Query]
    ms) = [Maybe Day] -> Maybe Day
    earliestMaybeDate' ([Maybe Day] -> Maybe Day) -> [Maybe Day] -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ (Query -> Maybe Day) -> [Query] -> [Maybe Day]
    forall a b. (a -> b) -> [a] -> [b]
    map (Bool -> Query -> Maybe Day
    queryEndDate Bool
    secondary) [Query]
    ms
    queryEndDate False (Date (DateSpan _ (Just d :: Day
    d))) = Day -> Maybe Day
    forall a. a -> Maybe a
    Just Day
    d
    queryEndDate True (Date2 (DateSpan _ (Just d :: Day
    d))) = Day -> Maybe Day
    forall a. a -> Maybe a
    Just Day
    d
    queryEndDate _ _ = Maybe Day
    forall a. Maybe a
    Nothing

    queryTermDateSpan :: Query -> Maybe DateSpan
    queryTermDateSpan (Date span :: DateSpan
    span) = DateSpan -> Maybe DateSpan
    forall a. a -> Maybe a
    Just DateSpan
    span
    queryTermDateSpan _ = Maybe DateSpan
    forall a. Maybe a
    Nothing

    -- | What date span (or with a true argument, what secondary date span) does this query specify ?
    -- OR clauses specifying multiple spans return their union (the span enclosing all of them).
    -- AND clauses specifying multiple spans return their intersection.
    -- NOT clauses are ignored.
    queryDateSpan :: Bool -> Query -> DateSpan
    queryDateSpan :: Bool -> Query -> DateSpan
    queryDateSpan secondary :: Bool
    secondary (Or qs :: [Query]
    qs)  = [DateSpan] -> DateSpan
    spansUnion     ([DateSpan] -> DateSpan) -> [DateSpan] -> DateSpan
    forall a b. (a -> b) -> a -> b
    $ (Query -> DateSpan) -> [Query] -> [DateSpan]
    forall a b. (a -> b) -> [a] -> [b]
    map (Bool -> Query -> DateSpan
    queryDateSpan Bool
    secondary) [Query]
    qs
    queryDateSpan secondary :: Bool
    secondary (And qs :: [Query]
    qs) = [DateSpan] -> DateSpan
    spansIntersect ([DateSpan] -> DateSpan) -> [DateSpan] -> DateSpan
    forall a b. (a -> b) -> a -> b
    $ (Query -> DateSpan) -> [Query] -> [DateSpan]
    forall a b. (a -> b) -> [a] -> [b]
    map (Bool -> Query -> DateSpan
    queryDateSpan Bool
    secondary) [Query]
    qs
    queryDateSpan False (Date span :: DateSpan
    span)  = DateSpan
    span
    queryDateSpan True (Date2 span :: DateSpan
    span)  = DateSpan
    span
    queryDateSpan _ _                = DateSpan
    nulldatespan

    -- | What date span does this query specify, treating primary and secondary dates as equivalent ?
    -- OR clauses specifying multiple spans return their union (the span enclosing all of them).
    -- AND clauses specifying multiple spans return their intersection.
    -- NOT clauses are ignored.
    queryDateSpan' :: Query -> DateSpan
    queryDateSpan' :: Query -> DateSpan
    queryDateSpan' (Or qs :: [Query]
    qs)      = [DateSpan] -> DateSpan
    spansUnion     ([DateSpan] -> DateSpan) -> [DateSpan] -> DateSpan
    forall a b. (a -> b) -> a -> b
    $ (Query -> DateSpan) -> [Query] -> [DateSpan]
    forall a b. (a -> b) -> [a] -> [b]
    map Query -> DateSpan
    queryDateSpan' [Query]
    qs
    queryDateSpan' (And qs :: [Query]
    qs)     = [DateSpan] -> DateSpan
    spansIntersect ([DateSpan] -> DateSpan) -> [DateSpan] -> DateSpan
    forall a b. (a -> b) -> a -> b
    $ (Query -> DateSpan) -> [Query] -> [DateSpan]
    forall a b. (a -> b) -> [a] -> [b]
    map Query -> DateSpan
    queryDateSpan' [Query]
    qs
    queryDateSpan' (Date span :: DateSpan
    span)  = DateSpan
    span
    queryDateSpan' (Date2 span :: DateSpan
    span) = DateSpan
    span
    queryDateSpan' _            = DateSpan
    nulldatespan

    -- | What is the earliest of these dates, where Nothing is earliest ?
    earliestMaybeDate :: [Maybe Day] -> Maybe Day
    earliestMaybeDate :: [Maybe Day] -> Maybe Day
    earliestMaybeDate = Maybe Day -> Maybe (Maybe Day) -> Maybe Day
    forall a. a -> Maybe a -> a
    fromMaybe Maybe Day
    forall a. Maybe a
    Nothing (Maybe (Maybe Day) -> Maybe Day)
    -> ([Maybe Day] -> Maybe (Maybe Day)) -> [Maybe Day] -> Maybe Day
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Maybe Day] -> Maybe (Maybe Day)
    forall a. Ord a => [a] -> Maybe a
    minimumMay

    -- | What is the latest of these dates, where Nothing is earliest ?
    latestMaybeDate :: [Maybe Day] -> Maybe Day
    latestMaybeDate :: [Maybe Day] -> Maybe Day
    latestMaybeDate = Maybe Day -> Maybe (Maybe Day) -> Maybe Day
    forall a. a -> Maybe a -> a
    fromMaybe Maybe Day
    forall a. Maybe a
    Nothing (Maybe (Maybe Day) -> Maybe Day)
    -> ([Maybe Day] -> Maybe (Maybe Day)) -> [Maybe Day] -> Maybe Day
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Maybe Day] -> Maybe (Maybe Day)
    forall a. Ord a => [a] -> Maybe a
    maximumMay

    -- | What is the earliest of these dates, where Nothing is the latest ?
    earliestMaybeDate' :: [Maybe Day] -> Maybe Day
    earliestMaybeDate' :: [Maybe Day] -> Maybe Day
    earliestMaybeDate' = Maybe Day -> Maybe (Maybe Day) -> Maybe Day
    forall a. a -> Maybe a -> a
    fromMaybe Maybe Day
    forall a. Maybe a
    Nothing (Maybe (Maybe Day) -> Maybe Day)
    -> ([Maybe Day] -> Maybe (Maybe Day)) -> [Maybe Day] -> Maybe Day
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Maybe Day] -> Maybe (Maybe Day)
    forall a. Ord a => [a] -> Maybe a
    minimumMay ([Maybe Day] -> Maybe (Maybe Day))
    -> ([Maybe Day] -> [Maybe Day]) -> [Maybe Day] -> Maybe (Maybe Day)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Maybe Day -> Bool) -> [Maybe Day] -> [Maybe Day]
    forall a. (a -> Bool) -> [a] -> [a]
    filter Maybe Day -> Bool
    forall a. Maybe a -> Bool
    isJust

    -- | What is the latest of these dates, where Nothing is the latest ?
    latestMaybeDate' :: [Maybe Day] -> Maybe Day
    latestMaybeDate' :: [Maybe Day] -> Maybe Day
    latestMaybeDate' = Maybe Day -> Maybe (Maybe Day) -> Maybe Day
    forall a. a -> Maybe a -> a
    fromMaybe Maybe Day
    forall a. Maybe a
    Nothing (Maybe (Maybe Day) -> Maybe Day)
    -> ([Maybe Day] -> Maybe (Maybe Day)) -> [Maybe Day] -> Maybe Day
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Maybe Day -> Maybe Day -> Ordering)
    -> [Maybe Day] -> Maybe (Maybe Day)
    forall a. (a -> a -> Ordering) -> [a] -> Maybe a
    maximumByMay Maybe Day -> Maybe Day -> Ordering
    forall a. Ord a => Maybe a -> Maybe a -> Ordering
    compareNothingMax
      where
        compareNothingMax :: Maybe a -> Maybe a -> Ordering
    compareNothingMax Nothing  Nothing  = Ordering
    EQ
        compareNothingMax (Just _) Nothing  = Ordering
    LT
        compareNothingMax Nothing  (Just _) = Ordering
    GT
        compareNothingMax (Just a :: a
    a) (Just b :: a
    b) = a -> a -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare a
    a a
    b

    -- | The depth limit this query specifies, if it has one
    queryDepth :: Query -> Maybe Int
    queryDepth :: Query -> Maybe Int
    queryDepth = [Int] -> Maybe Int
    forall a. Ord a => [a] -> Maybe a
    minimumMay ([Int] -> Maybe Int) -> (Query -> [Int]) -> Query -> Maybe Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Query -> [Int]
    queryDepth'
      where
        queryDepth' :: Query -> [Int]
    queryDepth' (Depth d :: Int
    d) = [Int
    d]
        queryDepth' (Or qs :: [Query]
    qs)   = (Query -> [Int]) -> [Query] -> [Int]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap Query -> [Int]
    queryDepth' [Query]
    qs
        queryDepth' (And qs :: [Query]
    qs)  = (Query -> [Int]) -> [Query] -> [Int]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap Query -> [Int]
    queryDepth' [Query]
    qs
        queryDepth' _         = []

    -- | The account we are currently focussed on, if any, and whether subaccounts are included.
    -- Just looks at the first query option.
    inAccount :: [QueryOpt] -> Maybe (AccountName,Bool)
    inAccount :: [QueryOpt] -> Maybe (Text, Bool)
    inAccount [] = Maybe (Text, Bool)
    forall a. Maybe a
    Nothing
    inAccount (QueryOptInAcctOnly a :: Text
    a:_) = (Text, Bool) -> Maybe (Text, Bool)
    forall a. a -> Maybe a
    Just (Text
    a,Bool
    False)
    inAccount (QueryOptInAcct a :: Text
    a:_) = (Text, Bool) -> Maybe (Text, Bool)
    forall a. a -> Maybe a
    Just (Text
    a,Bool
    True)

    -- | A query for the account(s) we are currently focussed on, if any.
    -- Just looks at the first query option.
    inAccountQuery :: [QueryOpt] -> Maybe Query
    inAccountQuery :: [QueryOpt] -> Maybe Query
    inAccountQuery [] = Maybe Query
    forall a. Maybe a
    Nothing
    inAccountQuery (QueryOptInAcctOnly a :: Text
    a : _) = Query -> Maybe Query
    forall a. a -> Maybe a
    Just (Query -> Maybe Query)
    -> (Regexp -> Query) -> Regexp -> Maybe Query
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Regexp -> Query
    Acct (Regexp -> Maybe Query) -> Regexp -> Maybe Query
    forall a b. (a -> b) -> a -> b
    $ Text -> Regexp
    accountNameToAccountOnlyRegex Text
    a
    inAccountQuery (QueryOptInAcct a :: Text
    a     : _) = Query -> Maybe Query
    forall a. a -> Maybe a
    Just (Query -> Maybe Query)
    -> (Regexp -> Query) -> Regexp -> Maybe Query
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Regexp -> Query
    Acct (Regexp -> Maybe Query) -> Regexp -> Maybe Query
    forall a b. (a -> b) -> a -> b
    $ Text -> Regexp
    accountNameToAccountRegex Text
    a

    -- -- | Convert a query to its inverse.
    -- negateQuery :: Query -> Query
    -- negateQuery =  Not

    -- matching

    -- | Does the match expression match this account ?
    -- A matching in: clause is also considered a match.
    -- When matching by account name pattern, if there's a regular
    -- expression error, this function calls error.
    matchesAccount :: Query -> AccountName -> Bool
    matchesAccount :: Query -> Text -> Bool
    matchesAccount (Query
    None) _ = Bool
    False
    matchesAccount (Not m :: Query
    m) a :: Text
    a = Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ Query -> Text -> Bool
    matchesAccount Query
    m Text
    a
    matchesAccount (Or ms :: [Query]
    ms) a :: Text
    a = (Query -> Bool) -> [Query] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Query -> Text -> Bool
    `matchesAccount` Text
    a) [Query]
    ms
    matchesAccount (And ms :: [Query]
    ms) a :: Text
    a = (Query -> Bool) -> [Query] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all (Query -> Text -> Bool
    `matchesAccount` Text
    a) [Query]
    ms
    matchesAccount (Acct r :: Regexp
    r) a :: Text
    a = Regexp -> String -> Bool
    regexMatch Regexp
    r (String -> Bool) -> String -> Bool
    forall a b. (a -> b) -> a -> b
    $ Text -> String
    T.unpack Text
    a -- XXX pack
    matchesAccount (Depth d :: Int
    d) a :: Text
    a = Text -> Int
    accountNameLevel Text
    a Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Int
    d
    matchesAccount (Tag _ _) _ = Bool
    False
    matchesAccount _ _ = Bool
    True

    matchesMixedAmount :: Query -> MixedAmount -> Bool
    matchesMixedAmount :: Query -> MixedAmount -> Bool
    matchesMixedAmount q :: Query
    q (Mixed []) = Query
    q Query -> Amount -> Bool
    `matchesAmount` Amount
    nullamt
    matchesMixedAmount q :: Query
    q (Mixed as :: [Amount]
    as) = (Amount -> Bool) -> [Amount] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Query
    q Query -> Amount -> Bool
    `matchesAmount`) [Amount]
    as

    matchesCommodity :: Query -> CommoditySymbol -> Bool
    matchesCommodity :: Query -> Text -> Bool
    matchesCommodity (Sym r :: Regexp
    r) = Regexp -> String -> Bool
    regexMatch Regexp
    r (String -> Bool) -> (Text -> String) -> Text -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> String
    T.unpack
    matchesCommodity _ = Bool -> Text -> Bool
    forall a b. a -> b -> a
    const Bool
    True

    -- | Does the match expression match this (simple) amount ?
    matchesAmount :: Query -> Amount -> Bool
    matchesAmount :: Query -> Amount -> Bool
    matchesAmount (Not q :: Query
    q) a :: Amount
    a = Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ Query
    q Query -> Amount -> Bool
    `matchesAmount` Amount
    a
    matchesAmount (Query
    Any) _ = Bool
    True
    matchesAmount (Query
    None) _ = Bool
    False
    matchesAmount (Or qs :: [Query]
    qs) a :: Amount
    a = (Query -> Bool) -> [Query] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Query -> Amount -> Bool
    `matchesAmount` Amount
    a) [Query]
    qs
    matchesAmount (And qs :: [Query]
    qs) a :: Amount
    a = (Query -> Bool) -> [Query] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all (Query -> Amount -> Bool
    `matchesAmount` Amount
    a) [Query]
    qs
    matchesAmount (Amt ord :: OrdPlus
    ord n :: Quantity
    n) a :: Amount
    a = OrdPlus -> Quantity -> Amount -> Bool
    compareAmount OrdPlus
    ord Quantity
    n Amount
    a
    matchesAmount (Sym r :: Regexp
    r) a :: Amount
    a = Query -> Text -> Bool
    matchesCommodity (Regexp -> Query
    Sym Regexp
    r) (Amount -> Text
    acommodity Amount
    a)
    matchesAmount _ _ = Bool
    True

    -- | Is this simple (single-amount) mixed amount's quantity less than, greater than, equal to, or unsignedly equal to this number ?
    -- For multi-amount (multiple commodities, or just unsimplified) mixed amounts this is always true.

    -- | Is this amount's quantity less than, greater than, equal to, or unsignedly equal to this number ?
    compareAmount :: OrdPlus -> Quantity -> Amount -> Bool
    compareAmount :: OrdPlus -> Quantity -> Amount -> Bool
    compareAmount ord :: OrdPlus
    ord q :: Quantity
    q Amount{aquantity :: Amount -> Quantity
    aquantity=Quantity
    aq} = case OrdPlus
    ord of Lt      -> Quantity
    aq Quantity -> Quantity -> Bool
    forall a. Ord a => a -> a -> Bool
    <  Quantity
    q
                                                           LtEq    -> Quantity
    aq Quantity -> Quantity -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Quantity
    q
                                                           Gt      -> Quantity
    aq Quantity -> Quantity -> Bool
    forall a. Ord a => a -> a -> Bool
    >  Quantity
    q
                                                           GtEq    -> Quantity
    aq Quantity -> Quantity -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Quantity
    q
                                                           Eq      -> Quantity
    aq Quantity -> Quantity -> Bool
    forall a. Eq a => a -> a -> Bool
    == Quantity
    q
                                                           AbsLt   -> Quantity -> Quantity
    forall a. Num a => a -> a
    abs Quantity
    aq Quantity -> Quantity -> Bool
    forall a. Ord a => a -> a -> Bool
    <  Quantity -> Quantity
    forall a. Num a => a -> a
    abs Quantity
    q
                                                           AbsLtEq -> Quantity -> Quantity
    forall a. Num a => a -> a
    abs Quantity
    aq Quantity -> Quantity -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Quantity -> Quantity
    forall a. Num a => a -> a
    abs Quantity
    q
                                                           AbsGt   -> Quantity -> Quantity
    forall a. Num a => a -> a
    abs Quantity
    aq Quantity -> Quantity -> Bool
    forall a. Ord a => a -> a -> Bool
    >  Quantity -> Quantity
    forall a. Num a => a -> a
    abs Quantity
    q
                                                           AbsGtEq -> Quantity -> Quantity
    forall a. Num a => a -> a
    abs Quantity
    aq Quantity -> Quantity -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Quantity -> Quantity
    forall a. Num a => a -> a
    abs Quantity
    q
                                                           AbsEq   -> Quantity -> Quantity
    forall a. Num a => a -> a
    abs Quantity
    aq Quantity -> Quantity -> Bool
    forall a. Eq a => a -> a -> Bool
    == Quantity -> Quantity
    forall a. Num a => a -> a
    abs Quantity
    q

    -- | Does the match expression match this posting ?
    --
    -- Note that for account match we try both original and effective account
    matchesPosting :: Query -> Posting -> Bool
    matchesPosting :: Query -> Posting -> Bool
    matchesPosting (Not q :: Query
    q) p :: Posting
    p = Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ Query
    q Query -> Posting -> Bool
    `matchesPosting` Posting
    p
    matchesPosting (Query
    Any) _ = Bool
    True
    matchesPosting (Query
    None) _ = Bool
    False
    matchesPosting (Or qs :: [Query]
    qs) p :: Posting
    p = (Query -> Bool) -> [Query] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Query -> Posting -> Bool
    `matchesPosting` Posting
    p) [Query]
    qs
    matchesPosting (And qs :: [Query]
    qs) p :: Posting
    p = (Query -> Bool) -> [Query] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all (Query -> Posting -> Bool
    `matchesPosting` Posting
    p) [Query]
    qs
    matchesPosting (Code r :: Regexp
    r) p :: Posting
    p = Regexp -> String -> Bool
    regexMatch Regexp
    r (String -> Bool) -> String -> Bool
    forall a b. (a -> b) -> a -> b
    $ String -> (Transaction -> String) -> Maybe Transaction -> String
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe "" (Text -> String
    T.unpack (Text -> String) -> (Transaction -> Text) -> Transaction -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Transaction -> Text
    tcode) (Maybe Transaction -> String) -> Maybe Transaction -> String
    forall a b. (a -> b) -> a -> b
    $ Posting -> Maybe Transaction
    ptransaction Posting
    p
    matchesPosting (Desc r :: Regexp
    r) p :: Posting
    p = Regexp -> String -> Bool
    regexMatch Regexp
    r (String -> Bool) -> String -> Bool
    forall a b. (a -> b) -> a -> b
    $ String -> (Transaction -> String) -> Maybe Transaction -> String
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe "" (Text -> String
    T.unpack (Text -> String) -> (Transaction -> Text) -> Transaction -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Transaction -> Text
    tdescription) (Maybe Transaction -> String) -> Maybe Transaction -> String
    forall a b. (a -> b) -> a -> b
    $ Posting -> Maybe Transaction
    ptransaction Posting
    p
    matchesPosting (Acct r :: Regexp
    r) p :: Posting
    p = Posting -> Bool
    matches Posting
    p Bool -> Bool -> Bool
    || Posting -> Bool
    matches (Posting -> Posting
    originalPosting Posting
    p)
      where matches :: Posting -> Bool
    matches p :: Posting
    p = Regexp -> String -> Bool
    regexMatch Regexp
    r (String -> Bool) -> (Text -> String) -> Text -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> String
    T.unpack (Text -> Bool) -> Text -> Bool
    forall a b. (a -> b) -> a -> b
    $ Posting -> Text
    paccount Posting
    p -- XXX pack
    matchesPosting (Date span :: DateSpan
    span) p :: Posting
    p = DateSpan
    span DateSpan -> Day -> Bool
    `spanContainsDate` Posting -> Day
    postingDate Posting
    p
    matchesPosting (Date2 span :: DateSpan
    span) p :: Posting
    p = DateSpan
    span DateSpan -> Day -> Bool
    `spanContainsDate` Posting -> Day
    postingDate2 Posting
    p
    matchesPosting (StatusQ s :: Status
    s) p :: Posting
    p = Posting -> Status
    postingStatus Posting
    p Status -> Status -> Bool
    forall a. Eq a => a -> a -> Bool
    == Status
    s
    matchesPosting (Real v :: Bool
    v) p :: Posting
    p = Bool
    v Bool -> Bool -> Bool
    forall a. Eq a => a -> a -> Bool
    == Posting -> Bool
    isReal Posting
    p
    matchesPosting q :: Query
    q@(Depth _) Posting{paccount :: Posting -> Text
    paccount=Text
    a} = Query
    q Query -> Text -> Bool
    `matchesAccount` Text
    a
    matchesPosting q :: Query
    q@(Amt _ _) Posting{pamount :: Posting -> MixedAmount
    pamount=MixedAmount
    amt} = Query
    q Query -> MixedAmount -> Bool
    `matchesMixedAmount` MixedAmount
    amt
    -- matchesPosting q@(Amt _ _) Posting{pamount=amt} = q `matchesMixedAmount` amt
    -- matchesPosting (Empty v) Posting{pamount=a} = v == mixedAmountLooksZero a
    -- matchesPosting (Empty False) Posting{pamount=a} = True
    -- matchesPosting (Empty True) Posting{pamount=a} = mixedAmountLooksZero a
    matchesPosting (Empty _) _ = Bool
    True
    matchesPosting (Sym r :: Regexp
    r) Posting{pamount :: Posting -> MixedAmount
    pamount=Mixed as :: [Amount]
    as} = (Text -> Bool) -> [Text] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Query -> Text -> Bool
    matchesCommodity (Regexp -> Query
    Sym Regexp
    r)) ([Text] -> Bool) -> [Text] -> Bool
    forall a b. (a -> b) -> a -> b
    $ (Amount -> Text) -> [Amount] -> [Text]
    forall a b. (a -> b) -> [a] -> [b]
    map Amount -> Text
    acommodity [Amount]
    as
    matchesPosting (Tag n :: Regexp
    n v :: Maybe Regexp
    v) p :: Posting
    p = case (Regexp -> String
    reString Regexp
    n, Maybe Regexp
    v) of
      ("payee", Just v :: Regexp
    v) -> Bool -> (Transaction -> Bool) -> Maybe Transaction -> Bool
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe Bool
    False (Regexp -> String -> Bool
    regexMatch Regexp
    v (String -> Bool) -> (Transaction -> String) -> Transaction -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> String
    T.unpack (Text -> String) -> (Transaction -> Text) -> Transaction -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Transaction -> Text
    transactionPayee) (Maybe Transaction -> Bool) -> Maybe Transaction -> Bool
    forall a b. (a -> b) -> a -> b
    $ Posting -> Maybe Transaction
    ptransaction Posting
    p
      ("note", Just v :: Regexp
    v) -> Bool -> (Transaction -> Bool) -> Maybe Transaction -> Bool
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe Bool
    False (Regexp -> String -> Bool
    regexMatch Regexp
    v (String -> Bool) -> (Transaction -> String) -> Transaction -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> String
    T.unpack (Text -> String) -> (Transaction -> Text) -> Transaction -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Transaction -> Text
    transactionNote) (Maybe Transaction -> Bool) -> Maybe Transaction -> Bool
    forall a b. (a -> b) -> a -> b
    $ Posting -> Maybe Transaction
    ptransaction Posting
    p
      (_, v :: Maybe Regexp
    v) -> Regexp -> Maybe Regexp -> [(Text, Text)] -> Bool
    matchesTags Regexp
    n Maybe Regexp
    v ([(Text, Text)] -> Bool) -> [(Text, Text)] -> Bool
    forall a b. (a -> b) -> a -> b
    $ Posting -> [(Text, Text)]
    postingAllTags Posting
    p

    -- | Does the match expression match this transaction ?
    matchesTransaction :: Query -> Transaction -> Bool
    matchesTransaction :: Query -> Transaction -> Bool
    matchesTransaction (Not q :: Query
    q) t :: Transaction
    t = Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ Query
    q Query -> Transaction -> Bool
    `matchesTransaction` Transaction
    t
    matchesTransaction (Query
    Any) _ = Bool
    True
    matchesTransaction (Query
    None) _ = Bool
    False
    matchesTransaction (Or qs :: [Query]
    qs) t :: Transaction
    t = (Query -> Bool) -> [Query] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Query -> Transaction -> Bool
    `matchesTransaction` Transaction
    t) [Query]
    qs
    matchesTransaction (And qs :: [Query]
    qs) t :: Transaction
    t = (Query -> Bool) -> [Query] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all (Query -> Transaction -> Bool
    `matchesTransaction` Transaction
    t) [Query]
    qs
    matchesTransaction (Code r :: Regexp
    r) t :: Transaction
    t = Regexp -> String -> Bool
    regexMatch Regexp
    r (String -> Bool) -> String -> Bool
    forall a b. (a -> b) -> a -> b
    $ Text -> String
    T.unpack (Text -> String) -> Text -> String
    forall a b. (a -> b) -> a -> b
    $ Transaction -> Text
    tcode Transaction
    t
    matchesTransaction (Desc r :: Regexp
    r) t :: Transaction
    t = Regexp -> String -> Bool
    regexMatch Regexp
    r (String -> Bool) -> String -> Bool
    forall a b. (a -> b) -> a -> b
    $ Text -> String
    T.unpack (Text -> String) -> Text -> String
    forall a b. (a -> b) -> a -> b
    $ Transaction -> Text
    tdescription Transaction
    t
    matchesTransaction q :: Query
    q@(Acct _) t :: Transaction
    t = (Posting -> Bool) -> [Posting] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Query
    q Query -> Posting -> Bool
    `matchesPosting`) ([Posting] -> Bool) -> [Posting] -> Bool
    forall a b. (a -> b) -> a -> b
    $ Transaction -> [Posting]
    tpostings Transaction
    t
    matchesTransaction (Date span :: DateSpan
    span) t :: Transaction
    t = DateSpan -> Day -> Bool
    spanContainsDate DateSpan
    span (Day -> Bool) -> Day -> Bool
    forall a b. (a -> b) -> a -> b
    $ Transaction -> Day
    tdate Transaction
    t
    matchesTransaction (Date2 span :: DateSpan
    span) t :: Transaction
    t = DateSpan -> Day -> Bool
    spanContainsDate DateSpan
    span (Day -> Bool) -> Day -> Bool
    forall a b. (a -> b) -> a -> b
    $ Transaction -> Day
    transactionDate2 Transaction
    t
    matchesTransaction (StatusQ s :: Status
    s) t :: Transaction
    t = Transaction -> Status
    tstatus Transaction
    t Status -> Status -> Bool
    forall a. Eq a => a -> a -> Bool
    == Status
    s
    matchesTransaction (Real v :: Bool
    v) t :: Transaction
    t = Bool
    v Bool -> Bool -> Bool
    forall a. Eq a => a -> a -> Bool
    == Transaction -> Bool
    hasRealPostings Transaction
    t
    matchesTransaction q :: Query
    q@(Amt _ _) t :: Transaction
    t = (Posting -> Bool) -> [Posting] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Query
    q Query -> Posting -> Bool
    `matchesPosting`) ([Posting] -> Bool) -> [Posting] -> Bool
    forall a b. (a -> b) -> a -> b
    $ Transaction -> [Posting]
    tpostings Transaction
    t
    matchesTransaction (Empty _) _ = Bool
    True
    matchesTransaction (Depth d :: Int
    d) t :: Transaction
    t = (Posting -> Bool) -> [Posting] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Int -> Query
    Depth Int
    d Query -> Posting -> Bool
    `matchesPosting`) ([Posting] -> Bool) -> [Posting] -> Bool
    forall a b. (a -> b) -> a -> b
    $ Transaction -> [Posting]
    tpostings Transaction
    t
    matchesTransaction q :: Query
    q@(Sym _) t :: Transaction
    t = (Posting -> Bool) -> [Posting] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Query
    q Query -> Posting -> Bool
    `matchesPosting`) ([Posting] -> Bool) -> [Posting] -> Bool
    forall a b. (a -> b) -> a -> b
    $ Transaction -> [Posting]
    tpostings Transaction
    t
    matchesTransaction (Tag n :: Regexp
    n v :: Maybe Regexp
    v) t :: Transaction
    t = case (Regexp -> String
    reString Regexp
    n, Maybe Regexp
    v) of
      ("payee", Just v :: Regexp
    v) -> Regexp -> String -> Bool
    regexMatch Regexp
    v (String -> Bool) -> (Transaction -> String) -> Transaction -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> String
    T.unpack (Text -> String) -> (Transaction -> Text) -> Transaction -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Transaction -> Text
    transactionPayee (Transaction -> Bool) -> Transaction -> Bool
    forall a b. (a -> b) -> a -> b
    $ Transaction
    t
      ("note", Just v :: Regexp
    v) -> Regexp -> String -> Bool
    regexMatch Regexp
    v (String -> Bool) -> (Transaction -> String) -> Transaction -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> String
    T.unpack (Text -> String) -> (Transaction -> Text) -> Transaction -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Transaction -> Text
    transactionNote (Transaction -> Bool) -> Transaction -> Bool
    forall a b. (a -> b) -> a -> b
    $ Transaction
    t
      (_, v :: Maybe Regexp
    v) -> Regexp -> Maybe Regexp -> [(Text, Text)] -> Bool
    matchesTags Regexp
    n Maybe Regexp
    v ([(Text, Text)] -> Bool) -> [(Text, Text)] -> Bool
    forall a b. (a -> b) -> a -> b
    $ Transaction -> [(Text, Text)]
    transactionAllTags Transaction
    t

    -- | Does the query match the name and optionally the value of any of these tags ?
    matchesTags :: Regexp -> Maybe Regexp -> [Tag] -> Bool
    matchesTags :: Regexp -> Maybe Regexp -> [(Text, Text)] -> Bool
    matchesTags namepat :: Regexp
    namepat valuepat :: Maybe Regexp
    valuepat = Bool -> Bool
    not (Bool -> Bool)
    -> ([(Text, Text)] -> Bool) -> [(Text, Text)] -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [(Text, Text)] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null ([(Text, Text)] -> Bool)
    -> ([(Text, Text)] -> [(Text, Text)]) -> [(Text, Text)] -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ((Text, Text) -> Bool) -> [(Text, Text)] -> [(Text, Text)]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Regexp -> Maybe Regexp -> (Text, Text) -> Bool
    matches Regexp
    namepat Maybe Regexp
    valuepat)
      where
        matches :: Regexp -> Maybe Regexp -> (Text, Text) -> Bool
    matches npat :: Regexp
    npat vpat :: Maybe Regexp
    vpat (n :: Text
    n,v :: Text
    v) = Regexp -> String -> Bool
    regexMatch Regexp
    npat (Text -> String
    T.unpack Text
    n) Bool -> Bool -> Bool
    && (String -> Bool)
    -> (Regexp -> String -> Bool) -> Maybe Regexp -> String -> Bool
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe (Bool -> String -> Bool
    forall a b. a -> b -> a
    const Bool
    True) Regexp -> String -> Bool
    regexMatch Maybe Regexp
    vpat (Text -> String
    T.unpack Text
    v)

    -- | Does the query match this market price ?
    matchesPriceDirective :: Query -> PriceDirective -> Bool
    matchesPriceDirective :: Query -> PriceDirective -> Bool
    matchesPriceDirective (Query
    None) _      = Bool
    False
    matchesPriceDirective (Not q :: Query
    q) p :: PriceDirective
    p     = Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ Query -> PriceDirective -> Bool
    matchesPriceDirective Query
    q PriceDirective
    p
    matchesPriceDirective (Or qs :: [Query]
    qs) p :: PriceDirective
    p     = (Query -> Bool) -> [Query] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (Query -> PriceDirective -> Bool
    `matchesPriceDirective` PriceDirective
    p) [Query]
    qs
    matchesPriceDirective (And qs :: [Query]
    qs) p :: PriceDirective
    p    = (Query -> Bool) -> [Query] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all (Query -> PriceDirective -> Bool
    `matchesPriceDirective` PriceDirective
    p) [Query]
    qs
    matchesPriceDirective q :: Query
    q@(Amt _ _) p :: PriceDirective
    p = Query -> Amount -> Bool
    matchesAmount Query
    q (PriceDirective -> Amount
    pdamount PriceDirective
    p)
    matchesPriceDirective q :: Query
    q@(Sym _) p :: PriceDirective
    p   = Query -> Text -> Bool
    matchesCommodity Query
    q (PriceDirective -> Text
    pdcommodity PriceDirective
    p)
    matchesPriceDirective (Date span :: DateSpan
    span) p :: PriceDirective
    p = DateSpan -> Day -> Bool
    spanContainsDate DateSpan
    span (PriceDirective -> Day
    pddate PriceDirective
    p)
    matchesPriceDirective _ _           = Bool
    True

    -- tests

    tests_Query :: TestTree
    tests_Query = String -> [TestTree] -> TestTree
    tests "Query" [
       String -> Assertion -> TestTree
    test "simplifyQuery" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ do
         (Query -> Query
    simplifyQuery (Query -> Query) -> Query -> Query
    forall a b. (a -> b) -> a -> b
    $ [Query] -> Query
    Or [Regexp -> Query
    Acct (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "a"])      Query -> Query -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (Regexp -> Query
    Acct (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "a")
         (Query -> Query
    simplifyQuery (Query -> Query) -> Query -> Query
    forall a b. (a -> b) -> a -> b
    $ [Query] -> Query
    Or [Query
    Any,Query
    None])      Query -> Query -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (Query
    Any)
         (Query -> Query
    simplifyQuery (Query -> Query) -> Query -> Query
    forall a b. (a -> b) -> a -> b
    $ [Query] -> Query
    And [Query
    Any,Query
    None])     Query -> Query -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (Query
    None)
         (Query -> Query
    simplifyQuery (Query -> Query) -> Query -> Query
    forall a b. (a -> b) -> a -> b
    $ [Query] -> Query
    And [Query
    Any,Query
    Any])      Query -> Query -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (Query
    Any)
         (Query -> Query
    simplifyQuery (Query -> Query) -> Query -> Query
    forall a b. (a -> b) -> a -> b
    $ [Query] -> Query
    And [Regexp -> Query
    Acct (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "b",Query
    Any]) Query -> Query -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (Regexp -> Query
    Acct (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "b")
         (Query -> Query
    simplifyQuery (Query -> Query) -> Query -> Query
    forall a b. (a -> b) -> a -> b
    $ [Query] -> Query
    And [Query
    Any,[Query] -> Query
    And [DateSpan -> Query
    Date (Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    forall a. Maybe a
    Nothing Maybe Day
    forall a. Maybe a
    Nothing)]]) Query -> Query -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (Query
    Any)
         (Query -> Query
    simplifyQuery (Query -> Query) -> Query -> Query
    forall a b. (a -> b) -> a -> b
    $ [Query] -> Query
    And [DateSpan -> Query
    Date (Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    forall a. Maybe a
    Nothing (Day -> Maybe Day
    forall a. a -> Maybe a
    Just (Day -> Maybe Day) -> Day -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ Integer -> Int -> Int -> Day
    fromGregorian 2013 01 01)), DateSpan -> Query
    Date (Maybe Day -> Maybe Day -> DateSpan
    DateSpan (Day -> Maybe Day
    forall a. a -> Maybe a
    Just (Day -> Maybe Day) -> Day -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ Integer -> Int -> Int -> Day
    fromGregorian 2012 01 01) Maybe Day
    forall a. Maybe a
    Nothing)])
           Query -> Query -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (DateSpan -> Query
    Date (Maybe Day -> Maybe Day -> DateSpan
    DateSpan (Day -> Maybe Day
    forall a. a -> Maybe a
    Just (Day -> Maybe Day) -> Day -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ Integer -> Int -> Int -> Day
    fromGregorian 2012 01 01) (Day -> Maybe Day
    forall a. a -> Maybe a
    Just (Day -> Maybe Day) -> Day -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ Integer -> Int -> Int -> Day
    fromGregorian 2013 01 01)))
         (Query -> Query
    simplifyQuery (Query -> Query) -> Query -> Query
    forall a b. (a -> b) -> a -> b
    $ [Query] -> Query
    And [[Query] -> Query
    Or [],[Query] -> Query
    Or [Regexp -> Query
    Desc (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "b b"]]) Query -> Query -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (Regexp -> Query
    Desc (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "b b")

      ,String -> Assertion -> TestTree
    test "parseQuery" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ do
         (Day -> Text -> Either String (Query, [QueryOpt])
    parseQuery Day
    nulldate "acct:'expenses:autres d\233penses' desc:b") Either String (Query, [QueryOpt])
    -> Either String (Query, [QueryOpt]) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (Query, [QueryOpt]) -> Either String (Query, [QueryOpt])
    forall a b. b -> Either a b
    Right ([Query] -> Query
    And [Regexp -> Query
    Acct (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegexCI' "expenses:autres d\233penses", Regexp -> Query
    Desc (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegexCI' "b"], [])
         Day -> Text -> Either String (Query, [QueryOpt])
    parseQuery Day
    nulldate "inacct:a desc:\"b b\""                       Either String (Query, [QueryOpt])
    -> Either String (Query, [QueryOpt]) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (Query, [QueryOpt]) -> Either String (Query, [QueryOpt])
    forall a b. b -> Either a b
    Right (Regexp -> Query
    Desc (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegexCI' "b b", [Text -> QueryOpt
    QueryOptInAcct "a"])
         Day -> Text -> Either String (Query, [QueryOpt])
    parseQuery Day
    nulldate "inacct:a inacct:b"                           Either String (Query, [QueryOpt])
    -> Either String (Query, [QueryOpt]) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (Query, [QueryOpt]) -> Either String (Query, [QueryOpt])
    forall a b. b -> Either a b
    Right (Query
    Any, [Text -> QueryOpt
    QueryOptInAcct "a", Text -> QueryOpt
    QueryOptInAcct "b"])
         Day -> Text -> Either String (Query, [QueryOpt])
    parseQuery Day
    nulldate "desc:'x x'"                                  Either String (Query, [QueryOpt])
    -> Either String (Query, [QueryOpt]) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (Query, [QueryOpt]) -> Either String (Query, [QueryOpt])
    forall a b. b -> Either a b
    Right (Regexp -> Query
    Desc (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegexCI' "x x", [])
         Day -> Text -> Either String (Query, [QueryOpt])
    parseQuery Day
    nulldate "'a a' 'b"                                    Either String (Query, [QueryOpt])
    -> Either String (Query, [QueryOpt]) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (Query, [QueryOpt]) -> Either String (Query, [QueryOpt])
    forall a b. b -> Either a b
    Right ([Query] -> Query
    Or [Regexp -> Query
    Acct (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegexCI' "a a",Regexp -> Query
    Acct (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegexCI' "'b"], [])
         Day -> Text -> Either String (Query, [QueryOpt])
    parseQuery Day
    nulldate "\""                                          Either String (Query, [QueryOpt])
    -> Either String (Query, [QueryOpt]) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (Query, [QueryOpt]) -> Either String (Query, [QueryOpt])
    forall a b. b -> Either a b
    Right (Regexp -> Query
    Acct (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegexCI' "\"", [])

      ,String -> Assertion -> TestTree
    test "words''" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ do
          ([Text] -> Text -> [Text]
    words'' [] "a b")                   [Text] -> [Text] -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= ["a","b"]
          ([Text] -> Text -> [Text]
    words'' [] "'a b'")                 [Text] -> [Text] -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= ["a b"]
          ([Text] -> Text -> [Text]
    words'' [] "not:a b")               [Text] -> [Text] -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= ["not:a","b"]
          ([Text] -> Text -> [Text]
    words'' [] "not:'a b'")             [Text] -> [Text] -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= ["not:a b"]
          ([Text] -> Text -> [Text]
    words'' [] "'not:a b'")             [Text] -> [Text] -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= ["not:a b"]
          ([Text] -> Text -> [Text]
    words'' ["desc:"] "not:desc:'a b'") [Text] -> [Text] -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= ["not:desc:a b"]
          ([Text] -> Text -> [Text]
    words'' [Text]
    prefixes "\"acct:expenses:autres d\233penses\"") [Text] -> [Text] -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= ["acct:expenses:autres d\233penses"]
          ([Text] -> Text -> [Text]
    words'' [Text]
    prefixes "\"")              [Text] -> [Text] -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= ["\""]

      ,String -> Assertion -> TestTree
    test "filterQuery" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ do
         (Query -> Bool) -> Query -> Query
    filterQuery Query -> Bool
    queryIsDepth Query
    Any       Query -> Query -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Query
    Any
         (Query -> Bool) -> Query -> Query
    filterQuery Query -> Bool
    queryIsDepth (Int -> Query
    Depth 1) Query -> Query -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Int -> Query
    Depth 1
         (Query -> Bool) -> Query -> Query
    filterQuery (Bool -> Bool
    not(Bool -> Bool) -> (Query -> Bool) -> Query -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .Query -> Bool
    queryIsDepth) ([Query] -> Query
    And [[Query] -> Query
    And [Status -> Query
    StatusQ Status
    Cleared,Int -> Query
    Depth 1]]) Query -> Query -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Status -> Query
    StatusQ Status
    Cleared
         (Query -> Bool) -> Query -> Query
    filterQuery Query -> Bool
    queryIsDepth ([Query] -> Query
    And [DateSpan -> Query
    Date DateSpan
    nulldatespan, Query -> Query
    Not ([Query] -> Query
    Or [Query
    Any, Int -> Query
    Depth 1])]) Query -> Query -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Query
    Any   -- XXX unclear

      ,String -> Assertion -> TestTree
    test "parseQueryTerm" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ do
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "a"                                Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Regexp -> Query
    Acct (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegexCI' "a")
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "acct:expenses:autres d\233penses" Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Regexp -> Query
    Acct (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegexCI' "expenses:autres d\233penses")
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "not:desc:a b"                     Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Query -> Query
    Not (Query -> Query) -> Query -> Query
    forall a b. (a -> b) -> a -> b
    $ Regexp -> Query
    Desc (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegexCI' "a b")
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "status:1"                         Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Status -> Query
    StatusQ Status
    Cleared)
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "status:*"                         Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Status -> Query
    StatusQ Status
    Cleared)
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "status:!"                         Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Status -> Query
    StatusQ Status
    Pending)
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "status:0"                         Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Status -> Query
    StatusQ Status
    Unmarked)
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "status:"                          Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Status -> Query
    StatusQ Status
    Unmarked)
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "payee:x"                          Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt)
    -> Either String Query -> Either String (Either Query QueryOpt)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe String -> Either String Query
    payeeTag (String -> Maybe String
    forall a. a -> Maybe a
    Just "x")
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "note:x"                           Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt)
    -> Either String Query -> Either String (Either Query QueryOpt)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe String -> Either String Query
    noteTag (String -> Maybe String
    forall a. a -> Maybe a
    Just "x")
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "real:1"                           Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Bool -> Query
    Real Bool
    True)
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "date:2008"                        Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan (Day -> Maybe Day
    forall a. a -> Maybe a
    Just (Day -> Maybe Day) -> Day -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ Integer -> Int -> Int -> Day
    fromGregorian 2008 01 01) (Day -> Maybe Day
    forall a. a -> Maybe a
    Just (Day -> Maybe Day) -> Day -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ Integer -> Int -> Int -> Day
    fromGregorian 2009 01 01))
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "date:from 2012/5/17"              Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan (Day -> Maybe Day
    forall a. a -> Maybe a
    Just (Day -> Maybe Day) -> Day -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ Integer -> Int -> Int -> Day
    fromGregorian 2012 05 17) Maybe Day
    forall a. Maybe a
    Nothing)
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "date:20180101-201804"             Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan (Day -> Maybe Day
    forall a. a -> Maybe a
    Just (Day -> Maybe Day) -> Day -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ Integer -> Int -> Int -> Day
    fromGregorian 2018 01 01) (Day -> Maybe Day
    forall a. a -> Maybe a
    Just (Day -> Maybe Day) -> Day -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ Integer -> Int -> Int -> Day
    fromGregorian 2018 04 01))
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "inacct:a"                         Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (QueryOpt -> Either Query QueryOpt
    forall a b. b -> Either a b
    Right (QueryOpt -> Either Query QueryOpt)
    -> QueryOpt -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Text -> QueryOpt
    QueryOptInAcct "a")
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "tag:a"                            Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegexCI' "a") Maybe Regexp
    forall a. Maybe a
    Nothing)
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "tag:a=some value"                 Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegexCI' "a") (Regexp -> Maybe Regexp
    forall a. a -> Maybe a
    Just (Regexp -> Maybe Regexp) -> Regexp -> Maybe Regexp
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegexCI' "some value"))
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "amt:<0"                           Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ OrdPlus -> Quantity -> Query
    Amt OrdPlus
    Lt 0)
         Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm Day
    nulldate "amt:>10000.10"                    Either String (Either Query QueryOpt)
    -> Either String (Either Query QueryOpt) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Either Query QueryOpt -> Either String (Either Query QueryOpt)
    forall a b. b -> Either a b
    Right (Query -> Either Query QueryOpt
    forall a b. a -> Either a b
    Left (Query -> Either Query QueryOpt) -> Query -> Either Query QueryOpt
    forall a b. (a -> b) -> a -> b
    $ OrdPlus -> Quantity -> Query
    Amt OrdPlus
    AbsGt 10000.1)

      ,String -> Assertion -> TestTree
    test "parseAmountQueryTerm" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ do
         Text -> Either String (OrdPlus, Quantity)
    parseAmountQueryTerm "<0"        Either String (OrdPlus, Quantity)
    -> Either String (OrdPlus, Quantity) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    Lt,0) -- special case for convenience, since AbsLt 0 would be always false
         Text -> Either String (OrdPlus, Quantity)
    parseAmountQueryTerm ">0"        Either String (OrdPlus, Quantity)
    -> Either String (OrdPlus, Quantity) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    Gt,0) -- special case for convenience and consistency with above
         Text -> Either String (OrdPlus, Quantity)
    parseAmountQueryTerm " > - 0 "   Either String (OrdPlus, Quantity)
    -> Either String (OrdPlus, Quantity) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    Gt,0) -- accept whitespace around the argument parts
         Text -> Either String (OrdPlus, Quantity)
    parseAmountQueryTerm ">10000.10" Either String (OrdPlus, Quantity)
    -> Either String (OrdPlus, Quantity) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    AbsGt,10000.1)
         Text -> Either String (OrdPlus, Quantity)
    parseAmountQueryTerm "=0.23"     Either String (OrdPlus, Quantity)
    -> Either String (OrdPlus, Quantity) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    AbsEq,0.23)
         Text -> Either String (OrdPlus, Quantity)
    parseAmountQueryTerm "0.23"      Either String (OrdPlus, Quantity)
    -> Either String (OrdPlus, Quantity) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    AbsEq,0.23)
         Text -> Either String (OrdPlus, Quantity)
    parseAmountQueryTerm "<=+0.23"   Either String (OrdPlus, Quantity)
    -> Either String (OrdPlus, Quantity) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    LtEq,0.23)
         Text -> Either String (OrdPlus, Quantity)
    parseAmountQueryTerm "-0.23"     Either String (OrdPlus, Quantity)
    -> Either String (OrdPlus, Quantity) -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= (OrdPlus, Quantity) -> Either String (OrdPlus, Quantity)
    forall a b. b -> Either a b
    Right (OrdPlus
    Eq,(-0.23))
         Either String (OrdPlus, Quantity) -> Assertion
    forall b a. (HasCallStack, Eq b, Show b) => Either a b -> Assertion
    assertLeft (Either String (OrdPlus, Quantity) -> Assertion)
    -> Either String (OrdPlus, Quantity) -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Text -> Either String (OrdPlus, Quantity)
    parseAmountQueryTerm "-0,23"
         Either String (OrdPlus, Quantity) -> Assertion
    forall b a. (HasCallStack, Eq b, Show b) => Either a b -> Assertion
    assertLeft (Either String (OrdPlus, Quantity) -> Assertion)
    -> Either String (OrdPlus, Quantity) -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Text -> Either String (OrdPlus, Quantity)
    parseAmountQueryTerm "=.23"

      ,String -> Assertion -> TestTree
    test "queryStartDate" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ do
         let small :: Maybe Day
    small = Day -> Maybe Day
    forall a. a -> Maybe a
    Just (Day -> Maybe Day) -> Day -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ Integer -> Int -> Int -> Day
    fromGregorian 2000 01 01
             big :: Maybe Day
    big   = Day -> Maybe Day
    forall a. a -> Maybe a
    Just (Day -> Maybe Day) -> Day -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ Integer -> Int -> Int -> Day
    fromGregorian 2000 01 02
         Bool -> Query -> Maybe Day
    queryStartDate Bool
    False ([Query] -> Query
    And [DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    small Maybe Day
    forall a. Maybe a
    Nothing, DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    big Maybe Day
    forall a. Maybe a
    Nothing])     Maybe Day -> Maybe Day -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Maybe Day
    big
         Bool -> Query -> Maybe Day
    queryStartDate Bool
    False ([Query] -> Query
    And [DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    small Maybe Day
    forall a. Maybe a
    Nothing, DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    forall a. Maybe a
    Nothing Maybe Day
    forall a. Maybe a
    Nothing]) Maybe Day -> Maybe Day -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Maybe Day
    small
         Bool -> Query -> Maybe Day
    queryStartDate Bool
    False ([Query] -> Query
    Or  [DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    small Maybe Day
    forall a. Maybe a
    Nothing, DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    big Maybe Day
    forall a. Maybe a
    Nothing])     Maybe Day -> Maybe Day -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Maybe Day
    small
         Bool -> Query -> Maybe Day
    queryStartDate Bool
    False ([Query] -> Query
    Or  [DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    small Maybe Day
    forall a. Maybe a
    Nothing, DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    forall a. Maybe a
    Nothing Maybe Day
    forall a. Maybe a
    Nothing]) Maybe Day -> Maybe Day -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Maybe Day
    forall a. Maybe a
    Nothing

      ,String -> Assertion -> TestTree
    test "queryEndDate" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ do
         let small :: Maybe Day
    small = Day -> Maybe Day
    forall a. a -> Maybe a
    Just (Day -> Maybe Day) -> Day -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ Integer -> Int -> Int -> Day
    fromGregorian 2000 01 01
             big :: Maybe Day
    big   = Day -> Maybe Day
    forall a. a -> Maybe a
    Just (Day -> Maybe Day) -> Day -> Maybe Day
    forall a b. (a -> b) -> a -> b
    $ Integer -> Int -> Int -> Day
    fromGregorian 2000 01 02
         Bool -> Query -> Maybe Day
    queryEndDate Bool
    False ([Query] -> Query
    And [DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    forall a. Maybe a
    Nothing Maybe Day
    small, DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    forall a. Maybe a
    Nothing Maybe Day
    big])     Maybe Day -> Maybe Day -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Maybe Day
    small
         Bool -> Query -> Maybe Day
    queryEndDate Bool
    False ([Query] -> Query
    And [DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    forall a. Maybe a
    Nothing Maybe Day
    small, DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    forall a. Maybe a
    Nothing Maybe Day
    forall a. Maybe a
    Nothing]) Maybe Day -> Maybe Day -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Maybe Day
    small
         Bool -> Query -> Maybe Day
    queryEndDate Bool
    False ([Query] -> Query
    Or  [DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    forall a. Maybe a
    Nothing Maybe Day
    small, DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    forall a. Maybe a
    Nothing Maybe Day
    big])     Maybe Day -> Maybe Day -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Maybe Day
    big
         Bool -> Query -> Maybe Day
    queryEndDate Bool
    False ([Query] -> Query
    Or  [DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    forall a. Maybe a
    Nothing Maybe Day
    small, DateSpan -> Query
    Date (DateSpan -> Query) -> DateSpan -> Query
    forall a b. (a -> b) -> a -> b
    $ Maybe Day -> Maybe Day -> DateSpan
    DateSpan Maybe Day
    forall a. Maybe a
    Nothing Maybe Day
    forall a. Maybe a
    Nothing]) Maybe Day -> Maybe Day -> Assertion
    forall a. (Eq a, Show a, HasCallStack) => a -> a -> Assertion
    @?= Maybe Day
    forall a. Maybe a
    Nothing

      ,String -> Assertion -> TestTree
    test "matchesAccount" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ do
         HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Query
    Acct (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "b:c") Query -> Text -> Bool
    `matchesAccount` "a:bb:c:d"
         HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Query
    Acct (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "^a:b") Query -> Text -> Bool
    `matchesAccount` "c:a:b"
         HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Int -> Query
    Depth 2 Query -> Text -> Bool
    `matchesAccount` "a"
         HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Int -> Query
    Depth 2 Query -> Text -> Bool
    `matchesAccount` "a:b"
         HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ Int -> Query
    Depth 2 Query -> Text -> Bool
    `matchesAccount` "a:b:c"
         HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ DateSpan -> Query
    Date DateSpan
    nulldatespan Query -> Text -> Bool
    `matchesAccount` "a"
         HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ DateSpan -> Query
    Date2 DateSpan
    nulldatespan Query -> Text -> Bool
    `matchesAccount` "a"
         HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegex' "a") Maybe Regexp
    forall a. Maybe a
    Nothing Query -> Text -> Bool
    `matchesAccount` "a"

      ,String -> [TestTree] -> TestTree
    tests "matchesPosting" [
         String -> Assertion -> TestTree
    test "positive match on cleared posting status"  (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Status -> Query
    StatusQ Status
    Cleared)  Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{pstatus :: Status
    pstatus=Status
    Cleared}
        ,String -> Assertion -> TestTree
    test "negative match on cleared posting status"  (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ (Query -> Query
    Not (Query -> Query) -> Query -> Query
    forall a b. (a -> b) -> a -> b
    $ Status -> Query
    StatusQ Status
    Cleared)  Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{pstatus :: Status
    pstatus=Status
    Cleared}
        ,String -> Assertion -> TestTree
    test "positive match on unmarked posting status" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Status -> Query
    StatusQ Status
    Unmarked) Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{pstatus :: Status
    pstatus=Status
    Unmarked}
        ,String -> Assertion -> TestTree
    test "negative match on unmarked posting status" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ (Query -> Query
    Not (Query -> Query) -> Query -> Query
    forall a b. (a -> b) -> a -> b
    $ Status -> Query
    StatusQ Status
    Unmarked) Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{pstatus :: Status
    pstatus=Status
    Unmarked}
        ,String -> Assertion -> TestTree
    test "positive match on true posting status acquired from transaction" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Status -> Query
    StatusQ Status
    Cleared) Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{pstatus :: Status
    pstatus=Status
    Unmarked,ptransaction :: Maybe Transaction
    ptransaction=Transaction -> Maybe Transaction
    forall a. a -> Maybe a
    Just Transaction
    nulltransaction{tstatus :: Status
    tstatus=Status
    Cleared}}
        ,String -> Assertion -> TestTree
    test "real:1 on real posting" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Bool -> Query
    Real Bool
    True) Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{ptype :: PostingType
    ptype=PostingType
    RegularPosting}
        ,String -> Assertion -> TestTree
    test "real:1 on virtual posting fails" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ (Bool -> Query
    Real Bool
    True) Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{ptype :: PostingType
    ptype=PostingType
    VirtualPosting}
        ,String -> Assertion -> TestTree
    test "real:1 on balanced virtual posting fails" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ (Bool -> Query
    Real Bool
    True) Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{ptype :: PostingType
    ptype=PostingType
    BalancedVirtualPosting}
        ,String -> Assertion -> TestTree
    test "acct:" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Query
    Acct (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "'b") Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{paccount :: Text
    paccount="'b"}
        ,String -> Assertion -> TestTree
    test "tag:" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ do
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegex' "a") (Regexp -> Maybe Regexp
    forall a. a -> Maybe a
    Just (Regexp -> Maybe Regexp) -> Regexp -> Maybe Regexp
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "r$")) Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegex' "foo") Maybe Regexp
    forall a. Maybe a
    Nothing) Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{ptags :: [(Text, Text)]
    ptags=[("foo","")]}
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegex' "foo") Maybe Regexp
    forall a. Maybe a
    Nothing) Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{ptags :: [(Text, Text)]
    ptags=[("foo","baz")]}
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegex' "foo") (Regexp -> Maybe Regexp
    forall a. a -> Maybe a
    Just (Regexp -> Maybe Regexp) -> Regexp -> Maybe Regexp
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "a")) Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{ptags :: [(Text, Text)]
    ptags=[("foo","bar")]}
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegex' "foo") (Regexp -> Maybe Regexp
    forall a. a -> Maybe a
    Just (Regexp -> Maybe Regexp) -> Regexp -> Maybe Regexp
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "a$")) Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{ptags :: [(Text, Text)]
    ptags=[("foo","bar")]}
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegex' " foo ") (Regexp -> Maybe Regexp
    forall a. a -> Maybe a
    Just (Regexp -> Maybe Regexp) -> Regexp -> Maybe Regexp
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "a")) Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{ptags :: [(Text, Text)]
    ptags=[("foo","bar")]}
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegex' "foo foo") (Regexp -> Maybe Regexp
    forall a. a -> Maybe a
    Just (Regexp -> Maybe Regexp) -> Regexp -> Maybe Regexp
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' " ar ba ")) Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{ptags :: [(Text, Text)]
    ptags=[("foo foo","bar bar")]}
        ,String -> Assertion -> TestTree
    test "a tag match on a posting also sees inherited tags" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegex' "txntag") Maybe Regexp
    forall a. Maybe a
    Nothing) Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{ptransaction :: Maybe Transaction
    ptransaction=Transaction -> Maybe Transaction
    forall a. a -> Maybe a
    Just Transaction
    nulltransaction{ttags :: [(Text, Text)]
    ttags=[("txntag","")]}}
        ,String -> Assertion -> TestTree
    test "cur:" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ do
          let toSym :: Text -> Query
    toSym = (Query -> Query)
    -> (QueryOpt -> Query) -> Either Query QueryOpt -> Query
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either Query -> Query
    forall a. a -> a
    id (Query -> QueryOpt -> Query
    forall a b. a -> b -> a
    const (Query -> QueryOpt -> Query) -> Query -> QueryOpt -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Query
    forall a. String -> a
    error' "No query opts") (Either Query QueryOpt -> Query)
    -> (Text -> Either Query QueryOpt) -> Text -> Query
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (String -> Either Query QueryOpt)
    -> (Either Query QueryOpt -> Either Query QueryOpt)
    -> Either String (Either Query QueryOpt)
    -> Either Query QueryOpt
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either String -> Either Query QueryOpt
    forall a. String -> a
    error' Either Query QueryOpt -> Either Query QueryOpt
    forall a. a -> a
    id (Either String (Either Query QueryOpt) -> Either Query QueryOpt)
    -> (Text -> Either String (Either Query QueryOpt))
    -> Text
    -> Either Query QueryOpt
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Day -> Text -> Either String (Either Query QueryOpt)
    parseQueryTerm (Integer -> Int -> Int -> Day
    fromGregorian 2000 01 01) (Text -> Either String (Either Query QueryOpt))
    -> (Text -> Text) -> Text -> Either String (Either Query QueryOpt)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ("cur:"Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <>)
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ Text -> Query
    toSym "$" Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{pamount :: MixedAmount
    pamount=[Amount] -> MixedAmount
    Mixed [Quantity -> Amount
    usd 1]} -- becomes "^$$", ie testing for null symbol
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Text -> Query
    toSym "\\$") Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{pamount :: MixedAmount
    pamount=[Amount] -> MixedAmount
    Mixed [Quantity -> Amount
    usd 1]} -- have to quote $ for regexpr
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Text -> Query
    toSym "shekels") Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{pamount :: MixedAmount
    pamount=[Amount] -> MixedAmount
    Mixed [Amount
    nullamt{acommodity :: Text
    acommodity="shekels"}]}
          HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ (Text -> Query
    toSym "shek") Query -> Posting -> Bool
    `matchesPosting` Posting
    nullposting{pamount :: MixedAmount
    pamount=[Amount] -> MixedAmount
    Mixed [Amount
    nullamt{acommodity :: Text
    acommodity="shekels"}]}
      ]

      ,String -> Assertion -> TestTree
    test "matchesTransaction" (Assertion -> TestTree) -> Assertion -> TestTree
    forall a b. (a -> b) -> a -> b
    $ do
         HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Query
    Any Query -> Transaction -> Bool
    `matchesTransaction` Transaction
    nulltransaction
         HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Query
    Desc (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "x x") Query -> Transaction -> Bool
    `matchesTransaction` Transaction
    nulltransaction{tdescription :: Text
    tdescription="x"}
         HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Query
    Desc (Regexp -> Query) -> Regexp -> Query
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "x x") Query -> Transaction -> Bool
    `matchesTransaction` Transaction
    nulltransaction{tdescription :: Text
    tdescription="x x"}
         -- see posting for more tag tests
         HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegex' "foo") (Regexp -> Maybe Regexp
    forall a. a -> Maybe a
    Just (Regexp -> Maybe Regexp) -> Regexp -> Maybe Regexp
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "a")) Query -> Transaction -> Bool
    `matchesTransaction` Transaction
    nulltransaction{ttags :: [(Text, Text)]
    ttags=[("foo","bar")]}
         HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegex' "payee") (Regexp -> Maybe Regexp
    forall a. a -> Maybe a
    Just (Regexp -> Maybe Regexp) -> Regexp -> Maybe Regexp
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "payee")) Query -> Transaction -> Bool
    `matchesTransaction` Transaction
    nulltransaction{tdescription :: Text
    tdescription="payee|note"}
         HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegex' "note") (Regexp -> Maybe Regexp
    forall a. a -> Maybe a
    Just (Regexp -> Maybe Regexp) -> Regexp -> Maybe Regexp
    forall a b. (a -> b) -> a -> b
    $ String -> Regexp
    toRegex' "note")) Query -> Transaction -> Bool
    `matchesTransaction` Transaction
    nulltransaction{tdescription :: Text
    tdescription="payee|note"}
         -- a tag match on a transaction also matches posting tags
         HasCallStack => String -> Bool -> Assertion
    String -> Bool -> Assertion
    assertBool "" (Bool -> Assertion) -> Bool -> Assertion
    forall a b. (a -> b) -> a -> b
    $ (Regexp -> Maybe Regexp -> Query
    Tag (String -> Regexp
    toRegex' "postingtag") Maybe Regexp
    forall a. Maybe a
    Nothing) Query -> Transaction -> Bool
    `matchesTransaction` Transaction
    nulltransaction{tpostings :: [Posting]
    tpostings=[Posting
    nullposting{ptags :: [(Text, Text)]
    ptags=[("postingtag","")]}]}

     ]