How to implement GORM Value interface - go

I am trying to implement the Value interfaces for a db model, however I only receive an empty object when the Value function is called. The models are stored in the table as Link's but when I read them I want to append an additional field by using the value interface, the function is called however I'm not sure how I can access the original entry so that I can append the name to it
I define my struct as such:
type Link struct {
Id string
Url string
}
type ReturnLink struct {
Link
Name string
}
func (l *Link) Scan(value interface{}) error {
fmt.Println("scan")
return nil
}
func (l Link) Value() (driver.Value, error) {
fmt.Println("value")
name := getName()
returnLink := ReturnLink{
Link: l,
Name: name,
}
return returnLink, nil
}
Once I have formed the query, I am able to scan the value into the struct:
var link ReturnLink
db.Model(&Link{}).Where("id = ?", id).Scan(&link)
This returns a correct link with an empty name when I don't define the Value interface, but once implemented it only returns null values for each field, is there something I'm missing?
I have also tried not implementing the scan interface but it changes nothing

Related

Binding validations does not work when request body is Array of objects

Gin's request validation feature is not working when the request body (JSON) represents an array of objects
Ex:
[
{
"field1":"aaa",
"field2":"bbb"
}
]
code:
type item struct {
Field1 string `json:"field1" binding:"required"`
Field2 string `json:"field2" binding:"required"`
}
var items []item
err := c.BindJSON(&items)
To be more clear, the validation logic in gin is expecting the root object to be a struct and hence bails out when an array type gets passed.
what is best way to validate each object in an array passed in the body?
The JSON will be parsed here and then validated here.
The comment on the default ValidateStruct method:
ValidateStruct receives any kind of type, but only performed struct or pointer to struct type.
You can work around this by defining a struct, as it is needed, that holds your data:
type itemHolder struct {
Items []item
}
Then defining a custom Unmarshaler, like this:
func (i *itemHolder) UnmarshalJSON(b []byte) error {
return json.Unmarshal(b, &i.Items)
}
Now *itemHolder implements json.Unmarshaler, which means in turn that it will be a struct that is supported by gin.
This code should work now:
var items itemHolder
err := c.BindJSON(&items)
if err != nil {
// handle...
}
// use items.Items from here on
Please note that your marshal behaviour will change; so you should definitely implement the Marshaler interface if you need to.

Creating array of struct dynamically in golang

I try to create a generic function that accepts any struct value and create a array of that struct type. Here is the code I tried. But I get the error "t is not a type". How can I implement this.
type RegAppDB struct {
nm string
data []interface{}
}
func CreateRegTable(tbl string, rec interface{}) RegAppDB {
t := reflect.TypeOf(rec)
fmt.Println(t)
return RegAppDB{"log", []t}
}
Go does not support generics, and any attempt to do something like that is not going to work out well. In your specific case, there are a couple of key problems:
You cannot use a variable as a type. Go is compile-time static typed, so anything that gets type information at runtime (i.e. reflect.TypeOf) happens too late to use the way you're trying to do it.
Equally important, your struct's field is of type []interface{}, which means the only type you can use for that field is []interface{}. []string, for example, is a different type, and cannot be assigned to that field.
I took another route. Need some beautification. But this works. So now data is an array of interface and from calling function I pass pointer to structure variables to Save function.
type RegAppDB struct {
nm string
data []interface{}
cnt int
}
// CreateRegTable creates a data structure to hold the regression result
func CreateRegTable(tbl string) *RegAppDB {
return &RegAppDB{tbl, make([]interface{}, 20), 0}
}
// Save implements saving a record Regression application DB
func (rga *RegAppDB) Save(rec interface{}) error {
rga.data[rga.cnt] = rec
rga.cnt++
return nil
}
// Show implements showing the regression table
func (rga *RegAppDB) Show() error {
fmt.Println(rga.cnt)
for i := 0; i <= rga.cnt; i++ {
fmt.Println(rga.data[i])
}
return nil
}
// Compare compares two regression table for equality
func (rga *RegAppDB) Compare(rgt *RegAppDB) bool {
return reflect.DeepEqual(rga, rgt)
}
It cannot be done for a generic type. If there are a fixed number of possible types, then you can do something like the following:
type RegAppDB struct {
nm string
data interface{}
}
func CreateRegTable(rec interface{}) RegAppDB {
switch rec.(type) {
case int:
return &RegAppDB{"log", []int{}}
case string:
return &RegAppDB{"log", []string{}}
}
return nil
}
Note: Your data in RegAppDB should be of type interface{} since []int implements interface{} but not []interface{}

Modify struct fields during instance generation

Foreign application API gives me a list of names in JSON format. I need modify all of those.
But I do not like to write some loop for it (especially after Python using with reflection and stuff)
Is there any method to write something like this in Go?
type MyIncredibleType struct {
Name ModifyName // ModifyName is not a type!
}
func ModifyName(input string) string {
return input + ".com"
}
The expected behavior of this is:
a := MyIncredibleType{Name: "Abracadabra"}
print(a.Name) // Abracadabra.com
This seems pretty straight forward to me, assuming I understand your question correctly:
// ModifyName func
func ModifyName(input string) string {
return fmt.Sprintf("%v.com", input)
}
If you wish to achieve this within the type itself, without modifying (mutating) the internal state:
type MyType sturct {
name string // unexported
}
// accessor func to return name
func (t MyType) Name() string {
return t.name
}
// accessor func to return modified name
func (t MyType) ModifiedName() string {
return fmt.Sprintf("%v.com", t.name)
}
If you want to modify the internal state:
type MyType struct {
name string
}
// mutator func (note the pointer for pass by reference)
func (t *MyType) ModifyName(input string) {
t.name = fmt.Sprintf("%v.com", input)
}
// accessor (note no pointer for pass by value)
func (t MyType) Name() string {
return t.name
}
This is is not possible in GO. That's not how struct works in Go.
type MyIncredibleType struct {
Name ModifyName `json:"name"` // ModifyName is not a type!
}
you can only define Built-in types for your fields of struct or you can define Composite Literal types.
Composite literals construct values for structs, arrays, slices, and
maps and create a new value each time they are evaluated. They consist
of the type of the literal followed by a brace-bound list of elements.
Each element may optionally be preceded by a corresponding key.
Try to create a method receiver of struct which you are using to parse json coming from the api to modify the name. That will let you achieve something similar to what you want.
package main
import (
"fmt"
)
type MyIncredibleType struct {
Name string `json:"name"` // ModifyName is not a type!
}
func(myIncredibleType *MyIncredibleType) ModifyName() string {
return myIncredibleType.Name+".com"
}
func main() {
a := MyIncredibleType{Name: "Abracadabra"}
name := a.ModifyName()
fmt.Printf("%s",name)
}
Playground Example
Or you can pass an interface which will wrap any struct value with name field and then use Type assertion to get the underlying value to modify the same and return the result:
package main
import (
"fmt"
)
type MyIncredibleType struct {
Name string `json:"name"` // ModifyName is not a type!
}
func ModifyName(input interface{}) string{
return input.(interface{}).(string)+".com"
}
func main() {
a := MyIncredibleType{Name: "Abracadabra"}
name := ModifyName(a.Name)
fmt.Printf("%s",name)
}
Working code on Go Playground
For more information also go through Golang method Declarations on how to create receivers.

How to use Go's type alias to make own models work with protobufs?

I've got some REST API with my models defined as Go structs.
type User struct {
FirstName string
LastName string
}
Then I've got my database methods for getting data.
GetUserByID(id int) (*User, error)
Now I'd like to replace my REST API with https://github.com/twitchtv/twirp .
Therefore I started defining my models inside .proto files.
message User {
string first_name = 2;
string last_name = 3;
}
Now I've got two User types. Let's call them the native and the proto type.
I've also got a service defined in my .proto file which returns a user to the frontend.
service Users {
rpc GetUser(Id) returns (User);
}
This generates an interface that I have to fill in.
func (s *Server) GetUser(context.Context, id) (*User, error) {
// i'd like to reuse my existing database methods
u, err := db.GetUserByID(id)
// handle error
// do more stuff
return u, nil
}
Unfortunately this does not work. My database returns a native User but the interface requires a proto user.
Is there an easy way to make it work? Maybe using type aliases?
Thanks a lot!
One way you can solve your problem is by doing the conversion manually.
type User struct {
FirstName string
LastName string
}
type protoUser struct {
firstName string
lastName string
}
func main() {
u := db() // Retrieve a user from a mocked db
fmt.Println("Before:")
fmt.Printf("%#v\n", *u) // What db returns (*protoUser)
fmt.Println("After:")
fmt.Printf("%#v\n", u.AsUser()) // What conversion returns (User)
}
// Mocked db that returns pointer to protoUser
func db() *protoUser {
pu := protoUser{"John", "Dough"}
return &pu
}
// Conversion method (converts protoUser into a User)
func (pu *protoUser) AsUser() User {
return User{pu.firstName, pu.lastName}
}
The key part is the AsUser method on the protoUser struct.
There we simply write our custom logic for converting a protoUser into a User type we want to be working with.
Working Example
As #Peter mentioned in the comment section.
I've seen a project which made it with a custom Convert function. It converts the Protobuf to local struct via json.Unmarshal, not sure how's the performance but it's a way to go.
Preview Code PLAYGROUND
// Convert converts the in struct to out struct via `json.Unmarshal`
func Convert(in interface{}, out interface{}) error {
j, err := json.Marshal(in)
if err != nil {
return err
}
err = json.Unmarshal(j, &out)
if err != nil {
return err
}
return nil
}
func main() {
// Converts the protobuf struct to local struct via json.Unmarshal
var localUser User
if err := convert(protoUser, &localUser); err != nil {
panic(err)
}
}
Output
Before:
main.ProtoUser{FirstName:"John", LastName:"Dough"}
After:
main.User{FirstName:"John", LastName:"Dough"}
Program exited.

Obtaining the name of a known struct field

I have a struct which represents an object in a database, something like:
type Object struct {
Id string
Field1 string
Field2 int
}
And I'd like to have a function that updates the specific field in the database whenever the field is modified, something along these lines:
func (self *Object) SetField1(value string) {
self.Field1 = value
database.Update(self.Id, "Field1", self.Field1) // pseudocode
}
Is there a way to replace the "Field1" hard-coded string such that my code is resistant to future changes in the struct field ordering and naming?
I've poked around the reflect package, and it would be nice to be able to get the StructField that represents the field I'm working with, but it seems to require either the name of the field via hard-coded string, or the field's index in the struct (which is subject to change).
not in the context that you're talking about. It's not passed in as a parameter, so you need some other way of specifying which of the struct's fields to be sent. The mental gap here is you're trying to treat that set function like it's a property when it's not; the key difference between a property, as seen in other languages, is that a property is bound to a specific field, whereas your SetField1 method is bound to the whole struct. That method might as well set two fields.
Generally if you're doing field-wise reflective stuff, and you want to do fancy dynamic stuff with fields, you want to use struct tags. e.g., like this:
type Object struct {
Id string `db:"id"`
Field1 string `db:"field1"`
Field2 int `db:"field2"`
}
you can access those tags like-a-this:
package main
import (
"reflect"
"fmt"
)
func main() {
var x struct {
MyField int `core:"required"`
}
t := reflect.TypeOf(x)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fmt.Println(field.Name, ":", field.Tag.Get("core"))
}
}
that's not really a full solution, but... the question in the way it's asked is impossible to do.
You could validate your string by adding a method something like this:
func (self *Object) verify(field string) string {
if _, ok := reflect.TypeOf(*self).FieldByName(field); ok {
return field
}
panic("Invalid field name")
}
And then use it when passing the string to the database update
func (self *Object) SetField1(value string) {
self.Field1 = value
database.Update(self.Id, self.verify("Field1"), self.Field1) // pseudocode
}
But I would think that if you're willing to use reflection, that you'd be better off just making a generic setField method that accepts the field as a string, and the value as a interface{}, checks the field and value, sets the value and updates the database.
This way everything is done using the string, so it'll either work or panic, and you don't need to remember to use the .verify() method.
Somthing like:
func (self *Object) SetField(field string, value interface{}) {
// verify field and value using reflection
// set the value using reflection
database.Update(self.Id, field, self.Field1)
}
Though I don't think this'll work on unexported fields.

Resources