GetBSON method for individual elements [Go + mgo] - go

In Go, I get the json marshalling/unmarshalling. If a struct or type has a MarshalJSON method, when calling json.Marshal on another struct which has the former as a field, that structs's MarshalJSON method will be called. So from what I gather and have seen in practice...
type MyType struct has a MarshalJSON method to marshal itself a string.
type MyDocument struct has MyType as a field.
When calling json.Marshal() on MyDocument, the MyType field will be marshalled as a string due to it implementing json.Marshaller.
I'm trying to make my system database-agnostic and am implementing a service for MongoDB using the mgo driver, which means implementing bson.Getter and bson.Setter on all structs and things I want marshalled in a specific way. This is where it gets confusing.
Because Go doesn't have native fixed-point arithmetic, I'm using Shopspring's decimal package (found here) to deal with currency values. Decimal marshals to JSON perfectly but I have a named type type Currency decimal.Decimal which I just can't get to marshal down to BSON.
These are my implementations which convert the decimal to a float64 and try marshalling that in the same way I've done for json:
/*
Implements the bson.Getter interface.
*/
func (c Currency) GetBSON() (interface{}, error) {
f, _ := decimal.Decimal(c).Float64()
return f, nil
}
/*
Implements the bson.Setter interface.
*/
func (c *Currency) SetBSON(raw bson.Raw) error {
var f float64
e := raw.Unmarshal(&f)
if e == nil {
*c = Currency(decimal.NewFromFloat(f))
}
return e
}
Only problem is in the documentation for the bson package:
Marshal serializes the in value, which may be a map or a struct value.
Because it's not a struct or a map it just produces an empty document.
I'm just trying to marshal one bit of data which will only need to be marshalled as part of larger structs, but the package will only let me do it on whole documents. What should I do to get the results I need?

Related

Question regarding Golang interfaces and Composite struct [duplicate]

There are already several Q&As on this "X does not implement Y (... method has a pointer receiver)" thing, but to me, they seems to be talking about different things, and not applying to my specific case.
So, instead of making the question very specific, I'm making it broad and abstract -- Seems like there are several different cases that can make this error happen, can someone summary it up please?
I.e., how to avoid the problem, and if it occurs, what are the possibilities? Thx.
This compile-time error arises when you try to assign or pass (or convert) a concrete type to an interface type; and the type itself does not implement the interface, only a pointer to the type.
Short summary: An assignment to a variable of interface type is valid if the value being assigned implements the interface it is assigned to. It implements it if its method set is a superset of the interface. The method set of pointer types includes methods with both pointer and non-pointer receiver. The method set of non-pointer types only includes methods with non-pointer receiver.
Let's see an example:
type Stringer interface {
String() string
}
type MyType struct {
value string
}
func (m *MyType) String() string { return m.value }
The Stringer interface type has one method only: String(). Any value that is stored in an interface value Stringer must have this method. We also created a MyType, and we created a method MyType.String() with pointer receiver. This means the String() method is in the method set of the *MyType type, but not in that of MyType.
When we attempt to assign a value of MyType to a variable of type Stringer, we get the error in question:
m := MyType{value: "something"}
var s Stringer
s = m // cannot use m (type MyType) as type Stringer in assignment:
// MyType does not implement Stringer (String method has pointer receiver)
But everything is ok if we try to assign a value of type *MyType to Stringer:
s = &m
fmt.Println(s)
And we get the expected outcome (try it on the Go Playground):
something
So the requirements to get this compile-time error:
A value of non-pointer concrete type being assigned (or passed or converted)
An interface type being assigned to (or passed to, or converted to)
The concrete type has the required method of the interface, but with a pointer receiver
Possibilities to resolve the issue:
A pointer to the value must be used, whose method set will include the method with the pointer receiver
Or the receiver type must be changed to non-pointer, so the method set of the non-pointer concrete type will also contain the method (and thus satisfy the interface). This may or may not be viable, as if the method has to modify the value, a non-pointer receiver is not an option.
Structs and embedding
When using structs and embedding, often it's not "you" that implement an interface (provide a method implementation), but a type you embed in your struct. Like in this example:
type MyType2 struct {
MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: m}
var s Stringer
s = m2 // Compile-time error again
Again, compile-time error, because the method set of MyType2 does not contain the String() method of the embedded MyType, only the method set of *MyType2, so the following works (try it on the Go Playground):
var s Stringer
s = &m2
We can also make it work, if we embed *MyType and using only a non-pointer MyType2 (try it on the Go Playground):
type MyType2 struct {
*MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: &m}
var s Stringer
s = m2
Also, whatever we embed (either MyType or *MyType), if we use a pointer *MyType2, it will always work (try it on the Go Playground):
type MyType2 struct {
*MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: &m}
var s Stringer
s = &m2
Relevant section from the spec (from section Struct types):
Given a struct type S and a type named T, promoted methods are included in the method set of the struct as follows:
If S contains an anonymous field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
If S contains an anonymous field *T, the method sets of S and *S both include promoted methods with receiver T or *T.
So in other words: if we embed a non-pointer type, the method set of the non-pointer embedder only gets the methods with non-pointer receivers (from the embedded type).
If we embed a pointer type, the method set of the non-pointer embedder gets methods with both pointer and non-pointer receivers (from the embedded type).
If we use a pointer value to the embedder, regardless of whether the embedded type is pointer or not, the method set of the pointer to the embedder always gets methods with both the pointer and non-pointer receivers (from the embedded type).
Note:
There is a very similar case, namely when you have an interface value which wraps a value of MyType, and you try to type assert another interface value from it, Stringer. In this case the assertion will not hold for the reasons described above, but we get a slightly different runtime-error:
m := MyType{value: "something"}
var i interface{} = m
fmt.Println(i.(Stringer))
Runtime panic (try it on the Go Playground):
panic: interface conversion: main.MyType is not main.Stringer:
missing method String
Attempting to convert instead of type assert, we get the compile-time error we're talking about:
m := MyType{value: "something"}
fmt.Println(Stringer(m))
To keep it short and simple, let say you have a Loader interface and a WebLoader that implements this interface.
package main
import "fmt"
// Loader defines a content loader
type Loader interface {
load(src string) string
}
// WebLoader is a web content loader
type WebLoader struct{}
// load loads the content of a page
func (w *WebLoader) load(src string) string {
return fmt.Sprintf("I loaded this page %s", src)
}
func main() {
webLoader := WebLoader{}
loadContent(webLoader)
}
func loadContent(loader Loader) {
loader.load("google.com")
}
The above code will give you this compile time error
./main.go:20:13: cannot use webLoader (type WebLoader) as type Loader
in argument to loadContent:
WebLoader does not implement Loader (Load method has pointer receiver)
To fix it you only need to change webLoader := WebLoader{} to following:
webLoader := &WebLoader{}
Why this will fix the issue? Because you defined this function func (w *WebLoader) Load to accept a pointer receiver. For more explanation please read #icza and #karora answers
Another case when I have seen this kind of thing happening is if I want to create an interface where some methods will modify an internal value and others will not.
type GetterSetter interface {
GetVal() int
SetVal(x int) int
}
Something that then implements this interface could be like:
type MyTypeA struct {
a int
}
func (m MyTypeA) GetVal() int {
return a
}
func (m *MyTypeA) SetVal(newVal int) int {
int oldVal = m.a
m.a = newVal
return oldVal
}
So the implementing type will likely have some methods which are pointer receivers and some which are not and since I have quite a variety of these various things that are GetterSetters I'd like to check in my tests that they are all doing the expected.
If I were to do something like this:
myTypeInstance := MyType{ 7 }
... maybe some code doing other stuff ...
var f interface{} = myTypeInstance
_, ok := f.(GetterSetter)
if !ok {
t.Fail()
}
Then I won't get the aforementioned "X does not implement Y (Z method has pointer receiver)" error (since it is a compile-time error) but I will have a bad day chasing down exactly why my test is failing...
Instead I have to make sure I do the type check using a pointer, such as:
var f interface{} = new(&MyTypeA)
...
Or:
myTypeInstance := MyType{ 7 }
var f interface{} = &myTypeInstance
...
Then all is happy with the tests!
But wait! In my code, perhaps I have methods which accept a GetterSetter somewhere:
func SomeStuff(g GetterSetter, x int) int {
if x > 10 {
return g.GetVal() + 1
}
return g.GetVal()
}
If I call these methods from inside another type method, this will generate the error:
func (m MyTypeA) OtherThing(x int) {
SomeStuff(m, x)
}
Either of the following calls will work:
func (m *MyTypeA) OtherThing(x int) {
SomeStuff(m, x)
}
func (m MyTypeA) OtherThing(x int) {
SomeStuff(&m, x)
}
Extend from above answers (Thanks for all of your answers)
I think it would be more instinctive to show all the methods of pointer / non pointer struct.
Here is the playground code.
https://play.golang.org/p/jkYrqF4KyIf
To summarize all the example.
Pointer struct type would include all non pointer / pointer receiver methods
Non pointer struct type would only include non pointer receiver methods.
For embedded struct
non pointer outer struct + non pointer embedded struct => only non pointer receiver methods.
non pointer outer struct + pointer embedded struct / pointer outer struct + non pointer embedded struct / pointer outer struct + pointer embedded struct => all embedded methods

How to convert map[string][]byte to map[string]interface{}

I have a function that excepts parameter of type map[string]interface{} but I have variable of type map[string][]byte. my question is how can I convert map[string][]byte to map[string]interface{} in Go.
This is a common miss-expectation from go. In this case each element of the map needs to be converted to interface.
So here's a workaround with sample code:
func foo(arg map[string]interface{}){
fmt.Println(arg)
}
// msaToMsi convert map string array of byte to map string interface
func msaToMsi(msa map[string][]byte) map[string]interface{}{
msi := make(map[string]interface{}, len(msa))
for k, v := range msa {
msi[k] = v
}
return msi
}
func main() {
msa := map[string][]byte{"a": []byte("xyz")}
foo(msaToMsi(msa))
}
The solution would be similar for the following map or array conversion as well:
map[string]string to map[string]interface{}
[]string to [] interface {}
Etc..
Ok so to answer your question an interface in GO can be used where you are passing or receiving a object/struct of where you are not sure of its type.
For example:
type Human struct {
Name string
Age int
School string
DOB time.Time
}
type Animal struct {
Name string
HasTail bool
IsMamal bool
DOB time.Time
}
func DisplayData(dataType interface{}, data byte)
This Display Data function can Display any type of data, it takes data and a struct both of which the function doesn't know until we pass them in... The data could be a Human or an Animal, both having different values which can be mapped depending on which interface we pass to the function...
This means we can reuse the code to display any data as long as we tell the function the data type we want to map the data to and display (i.e. Animal or Human...)
In your case the solution would be to define the data type, the structure of the data in the byte as a struct and where you make the map instead of map[string][]byte
try changing to
map[string]YourDefinedStructure
and pass that to the function that accepts map[string]interface{}.
Hopefully this helps, the question although you supply data types is rather vague as a use case and nature of the function that accepts map[string]interface{} can affect the approach taken.
You don't really have to convert while passing your map[string][]byte to the function.
The conversion needs to happen at the point where you want to use the value from the map.

Converting time from DB to custom time fails

I need to read dates from a db, convert it to a certain timestamp and convert it to JSON.
I have the following code:
package usages
import (
"fmt"
"time"
)
type SpecialOffer struct {
PublishedDate jsonTime `gorm:"column:publishing_date" json:"published_date"`
ExpirationDate jsonTime `gorm:"column:expiration_date" json:"expiration_date"`
}
type jsonTime struct {
time.Time
}
func (tt jsonTime) MarshalJSON() ([]byte, error) {
jsonTime := fmt.Sprintf("\"%s\"", tt.Format("20060102"))
return []byte(jsonTime), nil
}
When I run it like this I get the following error:
sql: Scan error on column index 8, name "publishing_date": unsupported Scan, storing driver.Value type time.Time into type *usages.trvTime
And the data is wrong:
{"published_date":"00010101","expiration_date":"00010101"}
If I change the SpecialOffer struct to use time.Time, it return correct, but obviously the format is wrong:
{"published_date":"2020-03-12T00:00:00Z","expiration_date":"2020-06-12T00:00:00Z"}
What am I doing wrong?
You should implement the sql.Scanner and driver.Valuer interfaces.
Something like this:
func (j *jsonTime) Scan(src interface{}) error {
if t, ok := src.(time.Time); ok {
j.Time = t
}
return nil
}
func (j jsonTime) Value() (driver.Value, error) {
return j.Time, nil
}
This is necessary because the database/sql package which is used by gorm and some other go ORMs, if not all of them, provides out-of-the-box support for only a handful of types.
Most of the supported types are the language's basic builtin types like string, int, bool, etc. by extension it also supports any custom user defined type whose underlying type is one of the aforementioned basic types, then there's supports for the []byte type and the related sql.RawBytes type, and lastly the time.Time type is also supported ootb.
Any other type that you may want to write to or read from the database will need to implement the two interfaces above. The sql.Scanner's Scan method is invoked automatically after a column's value is decoded into one of the supported types (that's why you need to type assert against time.Time rather than against, say []byte). The driver.Valuer's Value method is invoked automatically before the driver encodes it into a format that's valid for the target column (that's why you can return time.Time directly rather than having the do the encoding yourself).
And keep in mind that
type jsonTime struct {
time.Time
}
or even
type jsonTime time.Time
declares a new type that is not equal to time.Time and that is why it's not picked up by the database/sql package.

how interfaces represent any type in Golang

It is said that interface{} represents any type in Go. For example, let us consider a Marshal function in encoding/json which is used to convert Go data structure into a JSON string. Its definition is
func Marshal(v interface{}) ([]byte, error)
But we are passing a struct to it as a parameter like below.
type hello struct{
Message string
}
data,err:= json.Marshal(hello{Message:'Hello world'})
How is Go handling this?
The answer is runtime reflection.
From docs:
Package reflect implements run-time reflection, allowing a program to manipulate objects with arbitrary types. The typical use is to take a value with static type interface{} and extract its dynamic type information by calling TypeOf, which returns a Type.

Golang: cast interface back to its original type

I couldn't really find an answer to this, even though I looked up the Go documentation and examples. Is it possible to cast an interface back to its original type, dynamically? I know I can do something like this:
var myint int = 5
var myinterface interface{}
myinterface = myint
recovered, _ := myinterface.(int)
fmt.Println(recovered)
But here I know the type. I would like to have a map of unknown types (interfaces) and cast them back by using reflection, like this:
// put/pop writes/read to/from a map[string]interface{}
var myint int = 5
put("key" myint)
pop("key", &myint) // this should also work for objects or any other type
Like this it would by possible to store anything within a single map. The type will be handed in by the user when calling pop() (second argument is an interface). Is it possible to achive this using reflection?
You can't assert a type from an interface without knowing what that type is at compile time, but you can set a value from an interface via reflection. Here's an example without any error checks, which panics when any parameters don't match:
var m = map[string]interface{}{}
func put(k string, v interface{}) {
m[k] = v
}
func pop(k string, o interface{}) {
reflect.ValueOf(o).Elem().Set(reflect.ValueOf(m[k]))
}
https://play.golang.org/p/ORcKhtU_3O

Resources