use rustledger_core::{
Amount, Balance, Close, Commodity, CostSpec, Custom, Document, Event, IncompleteAmount,
MetaValue, Note, Open, Pad, Posting, Price, PriceAnnotation, Query, SYNTHESIZED_FILE_ID,
Spanned, Transaction,
};
use crate::types::{
AmountData, BalanceData, CloseData, CommodityData, CostData, CustomData, DocumentData,
EventData, MetaValueData, NoteData, OpenData, PadData, PostingData, PriceAnnotationData,
PriceData, QueryData, SourceSpan, TransactionData,
};
pub(super) fn transaction_to_data(txn: &Transaction) -> TransactionData {
TransactionData {
flag: txn.flag.to_string(),
payee: txn.payee.as_ref().map(ToString::to_string),
narration: txn.narration.to_string(),
tags: txn.tags.iter().map(ToString::to_string).collect(),
links: txn.links.iter().map(ToString::to_string).collect(),
metadata: txn
.meta
.iter()
.map(|(k, v)| (k.clone(), meta_value_to_data(v)))
.collect(),
postings: txn.postings.iter().map(spanned_posting_to_data).collect(),
}
}
pub(super) fn spanned_posting_to_data(spanned: &Spanned<Posting>) -> PostingData {
let mut data = posting_to_data(&spanned.value);
if spanned.file_id != SYNTHESIZED_FILE_ID {
data.span = Some(SourceSpan {
start: spanned.span.start as u64,
end: spanned.span.end as u64,
file_id: spanned.file_id,
});
}
data
}
pub(super) fn posting_to_data(posting: &Posting) -> PostingData {
PostingData {
account: posting.account.to_string(),
units: posting.units.as_ref().and_then(incomplete_amount_to_data),
cost: posting.cost.as_ref().map(cost_to_data),
price: posting.price.as_ref().map(price_annotation_to_data),
flag: posting.flag.map(|c| c.to_string()),
metadata: posting
.meta
.iter()
.map(|(k, v)| (k.clone(), meta_value_to_data(v)))
.collect(),
span: None,
}
}
pub(super) fn incomplete_amount_to_data(incomplete: &IncompleteAmount) -> Option<AmountData> {
match incomplete {
IncompleteAmount::Complete(amount) => Some(amount_to_data(amount)),
IncompleteAmount::CurrencyOnly(currency) => Some(AmountData {
number: String::new(), currency: currency.to_string(),
}),
IncompleteAmount::NumberOnly(number) => Some(AmountData {
number: number.to_string(),
currency: String::new(), }),
}
}
pub(super) fn amount_to_data(amount: &Amount) -> AmountData {
AmountData {
number: amount.number.to_string(),
currency: amount.currency.to_string(),
}
}
pub(super) fn cost_to_data(cost: &CostSpec) -> CostData {
use crate::types::CostNumberData;
CostData {
number: cost.number.map(|n| match n {
rustledger_core::CostNumber::PerUnit { value: d } => CostNumberData::PerUnit {
value: d.to_string(),
},
rustledger_core::CostNumber::PerUnitFromTotal(b) => CostNumberData::PerUnitFromTotal {
per_unit: b.per_unit.to_string(),
total: b.total.to_string(),
},
rustledger_core::CostNumber::Total { value: d } => CostNumberData::Total {
value: d.to_string(),
},
}),
currency: cost.currency.as_ref().map(ToString::to_string),
date: cost.date.map(|d| d.to_string()),
label: cost.label.clone(),
merge: cost.merge,
}
}
pub(super) fn price_annotation_to_data(price: &PriceAnnotation) -> PriceAnnotationData {
let is_total = matches!(price.kind, rustledger_core::PriceKind::Total);
match &price.amount {
Some(rustledger_core::IncompleteAmount::Complete(amount)) => PriceAnnotationData {
is_total,
amount: Some(amount_to_data(amount)),
number: None,
currency: None,
},
Some(inc) => PriceAnnotationData {
is_total,
amount: inc.as_amount().map(amount_to_data),
number: inc.number().map(|n| n.to_string()),
currency: inc.currency().map(String::from),
},
None => PriceAnnotationData {
is_total,
amount: None,
number: None,
currency: None,
},
}
}
pub(super) fn meta_value_to_data(value: &MetaValue) -> MetaValueData {
match value {
MetaValue::String(s) => MetaValueData::String(s.clone()),
MetaValue::Number(n) => MetaValueData::Number(n.to_string()),
MetaValue::Date(d) => MetaValueData::Date(d.to_string()),
MetaValue::Account(a) => MetaValueData::Account(a.to_string()),
MetaValue::Currency(c) => MetaValueData::Currency(c.to_string()),
MetaValue::Tag(t) => MetaValueData::Tag(t.to_string()),
MetaValue::Link(l) => MetaValueData::Link(l.to_string()),
MetaValue::Amount(a) => MetaValueData::Amount(amount_to_data(a)),
MetaValue::Bool(b) => MetaValueData::Bool(*b),
MetaValue::None => MetaValueData::String(String::new()),
}
}
pub(super) fn balance_to_data(bal: &Balance) -> BalanceData {
BalanceData {
account: bal.account.to_string(),
amount: amount_to_data(&bal.amount),
tolerance: bal.tolerance.map(|t| t.to_string()),
metadata: bal
.meta
.iter()
.map(|(k, v)| (k.clone(), meta_value_to_data(v)))
.collect(),
}
}
pub(super) fn open_to_data(open: &Open) -> OpenData {
OpenData {
account: open.account.to_string(),
currencies: open.currencies.iter().map(ToString::to_string).collect(),
booking: open.booking.clone(),
metadata: open
.meta
.iter()
.map(|(k, v)| (k.clone(), meta_value_to_data(v)))
.collect(),
}
}
pub(super) fn close_to_data(close: &Close) -> CloseData {
CloseData {
account: close.account.to_string(),
metadata: close
.meta
.iter()
.map(|(k, v)| (k.clone(), meta_value_to_data(v)))
.collect(),
}
}
pub(super) fn commodity_to_data(comm: &Commodity) -> CommodityData {
CommodityData {
currency: comm.currency.to_string(),
metadata: comm
.meta
.iter()
.map(|(k, v)| (k.clone(), meta_value_to_data(v)))
.collect(),
}
}
pub(super) fn pad_to_data(pad: &Pad) -> PadData {
PadData {
account: pad.account.to_string(),
source_account: pad.source_account.to_string(),
metadata: pad
.meta
.iter()
.map(|(k, v)| (k.clone(), meta_value_to_data(v)))
.collect(),
}
}
pub(super) fn event_to_data(event: &Event) -> EventData {
EventData {
event_type: event.event_type.clone(),
value: event.value.clone(),
metadata: event
.meta
.iter()
.map(|(k, v)| (k.clone(), meta_value_to_data(v)))
.collect(),
}
}
pub(super) fn note_to_data(note: &Note) -> NoteData {
NoteData {
account: note.account.to_string(),
comment: note.comment.clone(),
metadata: note
.meta
.iter()
.map(|(k, v)| (k.clone(), meta_value_to_data(v)))
.collect(),
}
}
pub(super) fn document_to_data(doc: &Document) -> DocumentData {
DocumentData {
account: doc.account.to_string(),
path: doc.path.clone(),
tags: doc.tags.iter().map(ToString::to_string).collect(),
links: doc.links.iter().map(ToString::to_string).collect(),
metadata: doc
.meta
.iter()
.map(|(k, v)| (k.clone(), meta_value_to_data(v)))
.collect(),
}
}
pub(super) fn price_to_data(price: &Price) -> PriceData {
PriceData {
currency: price.currency.to_string(),
amount: amount_to_data(&price.amount),
metadata: price
.meta
.iter()
.map(|(k, v)| (k.clone(), meta_value_to_data(v)))
.collect(),
}
}
pub(super) fn query_to_data(query: &Query) -> QueryData {
QueryData {
name: query.name.clone(),
query: query.query.clone(),
metadata: query
.meta
.iter()
.map(|(k, v)| (k.clone(), meta_value_to_data(v)))
.collect(),
}
}
pub(super) fn custom_to_data(custom: &Custom) -> CustomData {
CustomData {
custom_type: custom.custom_type.clone(),
values: custom.values.iter().map(meta_value_to_data).collect(),
metadata: custom
.meta
.iter()
.map(|(k, v)| (k.clone(), meta_value_to_data(v)))
.collect(),
}
}