Rhymond/go-money

SQL scanner/valuer

HT808s opened this issue · 8 comments

I'd like to do the implementations of scanner and valuer for Money:

Consider this:

Money {
  Amount: 10,
  Currency: EUR,
}

I see several ways to represent it in database.

Solution A

// Scanner and Valuer implemented on `money.Money`.
type someModel struct {
  Money money.Money,     `db:"money"`
}
INSERT INTO foo (money) VALUE ('EUR 10');

A string field in database holding both the amount and the currency.

  • Not suitable for search in SQL environment
  • Conveniently aggregates the currency and the amount in the model.

Solution B

Represent two distinct fields in database, one for the amount and the other for the currency.

  • Efficient select queries can be performed on amount and/or currency.
  • Compels you to use in the model money.Amount and money.Currency.
// Scanner and Valuer implemented on `money.Amount` and `money.Currency`.
type someModel struct {
  Amount money.Amount,     `db:"amount"`
  Currency money.Currency  `db:"currency"`
}
INSERT INTO foo (amount, currency) VALUE (10, 'EUR');

I prefer solution B, what do you think @Rhymond ?

WLBF commented

Solution B +1

djui commented

I’m also in favor of option B, it has more flexibility but will require a bit more work from the user. One can always write their own scanner/valuer on a wrapper type, but the other way around is more work.

Solution B +1

I really like solution B, could you please create PR for this?

Is there an update on this? Could really use this functionality.

@Rhymond I have created a PR for this issue (#99).

I first implemented the driver.Valuer and sql.Scanner interface on the money.Amount and money.Currency types but ran into trouble when trying to use them implicitly through a money.Money object.

This led me to some research where I learned that the recommended way to implement sql.Scanner when scanning requires multiple fields is to join the parts together into some pattern (e.g. a comma-separated string) which the scanner can rely on and parse.

I have tested #99 in my own project using golang's replace reature in my go.mod file:

replace github.com/Rhymond/go-money => github.com/davidalpert/go-money v1.0.4-0.20211129052335-28ea3cdd185c

and successfully deserialized two separate columns into a single money.Money value.

any update?I'm looking forward it

@FlameMida it just got merged and released