Reputation: 468
I'm wondering is there is a way to populate a variadic function parameter in golang with all the values of a struct (which will typically be of varying types).
The specific example I'm thinking of is the following snippet to generate a row for a mocked postgres database query using https://github.com/DATA-DOG/go-sqlmock:
rows := sqlmock.NewRows([]string{
"id",
"updated_at",
"created_at",
"meta",
"account_id",
"currency",
"nickname",
"scheme_name",
"identification",
"name",
"identification_secondary",
"servicer_scheme_name",
"servicer_identification",
"institution_id",
"client_id",
}).AddRow(
mock.Values.AccountID,
time.Now(),
time.Now(),
"{}",
"12345678",
"GBP",
"Test",
"Schema",
"12345676534263",
"New account",
"12345",
"schema",
"test id",
mock.Values.InstitutionID,
mock.Values.ClientID,
)
Given the parameters always represent a struct (fields and values), I was attempting to use a struct to populate both the fields and values rather than complete each manually. Fields is fairly simple with reflection, however the values are of multiple types with the AddRow function defined as:
AddRow func(values ...driver.Value) *Rows
Is there a way to loop over struct fields and provide typed values to achieve something like?...
account := Account{
ID: "ABCD12436364",
UpdatedAt: time.Now(),
CreatedAt: time.Now(),
Meta: "{}",
AccountID: "12345678",
Currency: "GBP",
Nickname: "Test",
SchemeName: "Scheme",
Identification: "12345676534263",
Name: "New account",
IdentificationSecondary: "12345",
ServicerSchemeName: "scheme",
ServicerIdentification: "test id",
InstitutionID: "ABCD123456",
ClientID: "ZXCVB12436",
}
rows := sqlmock.NewRows(account.GetFieldsJSON()).AddRow(account.GetValues())
Upvotes: 1
Views: 1469
Reputation: 38203
This can be done with the reflect
package which allows you to loop over a struct's fields and then construct a slice of driver.Value
s. You would then pass the resulting slice to AddRow
with the trailing ...
to "unpack" the contents.
var result []driver.Value
rv := reflect.ValueOf(account)
for i := 0; i < rv.NumField(); i++ {
fv := rv.Field(i)
dv := driver.Value(fv.Interface())
result = append(result, dv)
}
AddRow(result...)
Note that in this case the conversion driver.Value(fv.Interface())
works because driver.Value
is an empty interface and so is the type returned by fv.Interface()
.
https://play.golang.org/p/7Oy8_YrmkMa
Upvotes: 3