new comm:REGEXP query matches commodity symbols. Also some minor amt: fixes.

This commit is contained in:
Simon Michael 2013-09-09 15:04:43 -07:00
parent 73230838c5
commit 957f57a07b
4 changed files with 13 additions and 3 deletions

View File

@ -953,6 +953,7 @@ A query term can be any of the following:
- `REGEX` - match account names by this regular expression - `REGEX` - match account names by this regular expression
- `acct:REGEX` - same as above - `acct:REGEX` - same as above
- `code:REGEX` - match by transaction code (eg check number) - `code:REGEX` - match by transaction code (eg check number)
- `comm:REGEX` - match by commodity symbol
- `desc:REGEX` - match transaction descriptions by regular expression - `desc:REGEX` - match transaction descriptions by regular expression
- `date:PERIODEXPR` - match dates within the specified [period](#period-expressions) - `date:PERIODEXPR` - match dates within the specified [period](#period-expressions)
- `date2:PERIODEXPR` - as above, but match secondary dates - `date2:PERIODEXPR` - as above, but match secondary dates

View File

@ -6,7 +6,8 @@ title: hledger news
## unreleased ## unreleased
- parsing: amt queries use the = operator by default, eg amt:50 finds amounts equal to 50 - queries: `comm:REGEXP` matches commodity symbols which match REGEXP
- queries: `amt` now uses the = operator by default, eg amt:50 finds amounts equal to 50
- don't break when there are non-ascii characters in CSV files - don't break when there are non-ascii characters in CSV files
- csv: add the `include` directive, useful for factoring out common rules used with multiple CSV files - csv: add the `include` directive, useful for factoring out common rules used with multiple CSV files
- balancesheet: don't bother showing equity, it won't be useful for most of us - balancesheet: don't bother showing equity, it won't be useful for most of us

View File

@ -43,7 +43,7 @@ import Text.ParserCombinators.Parsec
import Hledger.Utils import Hledger.Utils
import Hledger.Data.Types import Hledger.Data.Types
import Hledger.Data.AccountName import Hledger.Data.AccountName
import Hledger.Data.Amount (nullamt) import Hledger.Data.Amount (nullamt, usd)
import Hledger.Data.Dates import Hledger.Data.Dates
import Hledger.Data.Posting import Hledger.Data.Posting
import Hledger.Data.Transaction import Hledger.Data.Transaction
@ -57,6 +57,7 @@ data Query = Any -- ^ always match
| Or [Query] -- ^ match if any of these match | Or [Query] -- ^ match if any of these match
| And [Query] -- ^ match if all of these match | And [Query] -- ^ match if all of these match
| Code String -- ^ match if code matches this regexp | Code String -- ^ match if code matches this regexp
| Comm String -- ^ match if the commodity symbol matches this regexp
| Desc String -- ^ match if description matches this regexp | Desc String -- ^ match if description matches this regexp
| Acct String -- ^ match postings whose account matches this regexp | Acct String -- ^ match postings whose account matches this regexp
| Date DateSpan -- ^ match if primary date in this date span | Date DateSpan -- ^ match if primary date in this date span
@ -174,7 +175,9 @@ tests_words'' = [
prefixes = map (++":") [ prefixes = map (++":") [
"inacctonly" "inacctonly"
,"inacct" ,"inacct"
,"amt"
,"code" ,"code"
,"comm"
,"desc" ,"desc"
,"acct" ,"acct"
,"date" ,"date"
@ -206,6 +209,7 @@ parseQueryTerm d ('n':'o':'t':':':s) = case parseQueryTerm d s of
Left m -> Left $ Not m Left m -> Left $ Not m
Right _ -> Left Any -- not:somequeryoption will be ignored Right _ -> Left Any -- not:somequeryoption will be ignored
parseQueryTerm _ ('c':'o':'d':'e':':':s) = Left $ Code s parseQueryTerm _ ('c':'o':'d':'e':':':s) = Left $ Code s
parseQueryTerm _ ('c':'o':'m':'m':':':s) = Left $ Comm s
parseQueryTerm _ ('d':'e':'s':'c':':':s) = Left $ Desc s parseQueryTerm _ ('d':'e':'s':'c':':':s) = Left $ Desc s
parseQueryTerm _ ('a':'c':'c':'t':':':s) = Left $ Acct s parseQueryTerm _ ('a':'c':'c':'t':':':s) = Left $ Acct s
parseQueryTerm d ('d':'a':'t':'e':':':s) = parseQueryTerm d ('d':'a':'t':'e':':':s) =
@ -499,6 +503,7 @@ matchesPosting (None) _ = False
matchesPosting (Or qs) p = any (`matchesPosting` p) qs matchesPosting (Or qs) p = any (`matchesPosting` p) qs
matchesPosting (And qs) p = all (`matchesPosting` p) qs matchesPosting (And qs) p = all (`matchesPosting` p) qs
matchesPosting (Code r) p = regexMatchesCI r $ maybe "" tcode $ ptransaction p matchesPosting (Code r) p = regexMatchesCI r $ maybe "" tcode $ ptransaction p
matchesPosting (Comm r) Posting{pamount=Mixed as} = any (regexMatchesCI r) $ map acommodity as
matchesPosting (Desc r) p = regexMatchesCI r $ maybe "" tdescription $ ptransaction p matchesPosting (Desc r) p = regexMatchesCI r $ maybe "" tdescription $ ptransaction p
matchesPosting (Acct r) p = regexMatchesCI r $ paccount p matchesPosting (Acct r) p = regexMatchesCI r $ paccount p
matchesPosting (Date span) p = span `spanContainsDate` postingDate p matchesPosting (Date span) p = span `spanContainsDate` postingDate p
@ -549,6 +554,7 @@ tests_matchesPosting = [
assertBool "" $ not $ (Tag "foo foo" (Just " ar ba ")) `matchesPosting` nullposting{ptags=[("foo foo","bar bar")]} assertBool "" $ not $ (Tag "foo foo" (Just " ar ba ")) `matchesPosting` nullposting{ptags=[("foo foo","bar bar")]}
-- a tag match on a posting also sees inherited tags -- a tag match on a posting also sees inherited tags
assertBool "" $ (Tag "txntag" Nothing) `matchesPosting` nullposting{ptransaction=Just nulltransaction{ttags=[("txntag","")]}} assertBool "" $ (Tag "txntag" Nothing) `matchesPosting` nullposting{ptransaction=Just nulltransaction{ttags=[("txntag","")]}}
assertBool "" $ (Comm "$") `matchesPosting` nullposting{pamount=Mixed [usd 1]}
] ]
-- | Does the match expression match this transaction ? -- | Does the match expression match this transaction ?
@ -559,6 +565,7 @@ matchesTransaction (None) _ = False
matchesTransaction (Or qs) t = any (`matchesTransaction` t) qs matchesTransaction (Or qs) t = any (`matchesTransaction` t) qs
matchesTransaction (And qs) t = all (`matchesTransaction` t) qs matchesTransaction (And qs) t = all (`matchesTransaction` t) qs
matchesTransaction (Code r) t = regexMatchesCI r $ tcode t matchesTransaction (Code r) t = regexMatchesCI r $ tcode t
matchesTransaction q@(Comm _) t = any (q `matchesPosting`) $ tpostings t
matchesTransaction (Desc r) t = regexMatchesCI r $ tdescription t matchesTransaction (Desc r) t = regexMatchesCI r $ tdescription t
matchesTransaction q@(Acct _) t = any (q `matchesPosting`) $ tpostings t matchesTransaction q@(Acct _) t = any (q `matchesPosting`) $ tpostings t
matchesTransaction (Date span) t = spanContainsDate span $ tdate t matchesTransaction (Date span) t = spanContainsDate span $ tdate t

View File

@ -95,6 +95,7 @@ searchform VD{..} = [hamlet|
Transactions/postings may additionally be filtered by Transactions/postings may additionally be filtered by
acct:REGEXP (target account), # acct:REGEXP (target account), #
code:REGEXP (transaction code), # code:REGEXP (transaction code), #
comm:REGEXP (commodity symbol), #
desc:REGEXP (description), # desc:REGEXP (description), #
date:PERIODEXP (date), # date:PERIODEXP (date), #
date2:PERIODEXP (secondary date), # date2:PERIODEXP (secondary date), #
@ -103,7 +104,7 @@ searchform VD{..} = [hamlet|
status:*, status:!, status: (cleared status), # status:*, status:!, status: (cleared status), #
real:BOOL (real/virtual-ness), # real:BOOL (real/virtual-ness), #
empty:BOOL (is amount zero), # empty:BOOL (is amount zero), #
amt:<N, amt:=N, amt:>N (test magnitude of single-commodity amount). amt:N, amt:<N, amt:>N (test magnitude of single-commodity amount).
<br> <br>
Prepend not: to negate, enclose multi-word patterns in quotes, multiple search terms are AND'ed. Prepend not: to negate, enclose multi-word patterns in quotes, multiple search terms are AND'ed.
|] |]