Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions hledger-lib/Hledger/Data/Journal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1441,13 +1441,24 @@ pivotAccount :: Text -> Posting -> Text
pivotAccount fieldortagname p =
T.intercalate ":" [pivotComponent x p | x <- T.splitOn ":" fieldortagname]

-- | Get the value of the given field or tag for this posting.
-- | Resolve one colon-separated pivot component for a posting.
-- Within a component, multiple field or tag names can be separated by @|@;
-- the first non-empty value is returned (left-to-right fallback).
-- For example, @--pivot 'mynotes|desc'@ returns the value of the @mynotes@ tag
-- if present and non-empty, otherwise the transaction description.
pivotComponent :: Text -> Posting -> Text
pivotComponent fieldortagname p =
case filter (not . T.null) $ map (`pivotSingleField` p) $ T.splitOn "|" fieldortagname of
(v:_) -> v
[] -> ""

-- | Get the value of the given single field or tag for this posting.
-- "comm" and "cur" are accepted as synonyms meaning the commodity symbol.
-- Pivoting on an unknown field or tag, or on commodity when there are multiple commodities, returns "".
-- Pivoting on a tag when there are multiple values for that tag, returns the first value.
-- Pivoting on the "type" tag normalises type values to their short spelling.
pivotComponent :: Text -> Posting -> Text
pivotComponent fieldortagname p
pivotSingleField :: Text -> Posting -> Text
pivotSingleField fieldortagname p
| fieldortagname == "code", Just t <- ptransaction p = tcode t
| fieldortagname `elem` descnames, Just t <- ptransaction p = tdescription t
| fieldortagname == "payee", Just t <- ptransaction p = transactionPayee t
Expand Down
6 changes: 6 additions & 0 deletions hledger/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ AI usage
User-visible changes in the hledger command line tool and library.


Features

- `--pivot` now supports `|`-separated fallback within each colon-delimited component.
Eg `--pivot 'mynotes|desc'` uses the `mynotes` tag value when present and non-empty,
otherwise falls back to the transaction description. (#1640)

# 1.99.2 2026-04-28

Breaking changes
Expand Down
1 change: 1 addition & 0 deletions hledger/hledger.m4.md
Original file line number Diff line number Diff line change
Expand Up @@ -5968,6 +5968,7 @@ PIVOTEXPR can be
- any of these standard transaction or posting fields (their value is substituted): `status`, `code`, `desc`, `payee`, `note`, `acct`, `comm`/`cur`, `amt`, `cost`
- or a tag name
- or any combination of these, colon-separated.
- within each colon-separated component, multiple field or tag names can be listed with `|` as a left-to-right fallback: the first non-empty value is used. Eg `--pivot 'mynotes|desc'` uses the `mynotes` tag value when present, otherwise falls back to the transaction description.

Some special cases:

Expand Down
62 changes: 56 additions & 6 deletions hledger/test/pivot.test
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,57 @@ $ hledger -f- --pivot acct:kind:project bal ^expense -N
20 expenses:equipment:job2
25 expenses:fee:job2

# ** 12. Pivot on the commodity symbol with "comm".
# ** 12. Pipe fallback: use first non-empty value among alternatives within a component.
# When the tag is present, its value is used.
<
2024/01/01 Lunch
assets:bank 30 USD
expenses:food -30 USD ; mynotes: tasty lunch
$ hledger -f- --pivot 'mynotes|desc' print
2024-01-01 Lunch
Lunch 30 USD
tasty lunch -30 USD ; mynotes: tasty lunch

>= 0

# ** 13. Pipe fallback: when the first alternative is absent, the next is used.
# The assets posting has no mynotes tag, so it falls back to desc.
<
2024/01/01 Lunch
assets:bank 30 USD
expenses:food -30 USD ; mynotes: tasty lunch
$ hledger -f- --pivot 'mynotes|desc' bal --no-total
30 USD Lunch
-30 USD tasty lunch

# ** 14. Three-way pipe fallback: first non-empty among three alternatives.
<
2024/01/01 Meeting
assets:bank 10 USD
expenses:misc -10 USD ; project: alpha
$ hledger -f- --pivot 'mynotes|project|desc' bal --no-total
10 USD Meeting
-10 USD alpha

# ** 15. Pipe fallback combined with colon composition.
# acct:tag1|tag2 builds a two-level account name; fallback applies per component.
<
2024/01/01 Groceries
assets:bank 50 USD
expenses:food -50 USD ; category: produce
$ hledger -f- --pivot 'acct:category|desc' bal --no-total
50 USD assets:bank:Groceries
-50 USD expenses:food:produce

# ** 16. All alternatives absent: result is empty string (existing behaviour preserved).
<
2024/01/01 Test
assets 1 USD
expenses
$ hledger -f- --pivot 'notag1|notag2' bal assets --no-total
1 USD

# ** 17. Pivot on the commodity symbol with "comm".
<
2025-01-01
expenses 1 A
Expand All @@ -147,7 +197,7 @@ Balance changes in 2025:
---++----------
|| 1 A, 2 B

# ** 13. "cur" is accepted as a synonym. Postings with multiple commodities currently are lumped in the "" bucket, not pivoted fully.
# ** 18. "cur" is accepted as a synonym. Postings with multiple commodities currently are lumped in the "" bucket, not pivoted fully.
$ hledger -f- bal -Y assets --pivot=cur
Balance changes in 2025:

Expand All @@ -157,7 +207,7 @@ Balance changes in 2025:
--++------------
|| -1 A, -2 B

# ** 14. When commodities are being converted, the original commodity is shown.
# ** 19. When commodities are being converted, the original commodity is shown.
<
2025-01-01
expenses 1 A @ $10
Expand All @@ -174,7 +224,7 @@ Balance changes in 2025, converted to cost:
---++------
|| $210

# ** 15. The "" bucket looks a bit strange in this case..
# ** 20. The "" bucket looks a bit strange in this case..
$ hledger -f- bal -Y assets --pivot=comm -B
Balance changes in 2025, converted to cost:

Expand All @@ -184,7 +234,7 @@ Balance changes in 2025, converted to cost:
---++-------
|| $-210

# ** 16. Pivot on amount.
# ** 21. Pivot on amount.
$ hledger -f- bal -Y --pivot=amt
Balance changes in 2025:

Expand All @@ -196,7 +246,7 @@ Balance changes in 2025:
------++-----------------
|| $-210, 1 A, 2 B

# ** 17. Pivot on cost.
# ** 22. Pivot on cost.
$ hledger -f- bal -Y --pivot=cost
Balance changes in 2025:

Expand Down
Loading