go-money icon indicating copy to clipboard operation
go-money copied to clipboard

SQL scanner/valuer

Open HT808s opened this issue 5 years ago • 6 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 ?

HT808s avatar Mar 15 '19 09:03 HT808s

Solution B +1

WLBF avatar Mar 28 '19 09:03 WLBF

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.

djui avatar May 01 '19 18:05 djui

Solution B +1

voodoo-dn avatar Dec 12 '19 16:12 voodoo-dn

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

Rhymond avatar Jan 05 '20 14:01 Rhymond

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

jonas-jonas avatar Apr 09 '21 17:04 jonas-jonas

@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.

davidalpert avatar Nov 29 '21 05:11 davidalpert

any update?I'm looking forward it

FlameMida avatar Apr 26 '24 07:04 FlameMida

@FlameMida it just got merged and released

Rhymond avatar Apr 26 '24 10:04 Rhymond