Create type inside if condition - go

Requirement:
type A struct {//some code}
type B struct {//some code}
func getData(db string) interface{} {
if db == "dbA" { // problem with this if condition
type C A
} else {
type C B
}
var byteData []byte
query := //cassandra query object
iter := query.Iter()
for iter.Scan(&byteData) {
myObject := new(C)
err := proto.Unmarshal(byteData, myObject)
objects = append(objects, myObject)
}
return objects
}
Basically, I don't want to write the if condition inside the loop. But myObject is declared outside the scope of C.
Alternate way:
I have tried having the type of myObject as proto.Message, but that gives me error "invalid memory address or nil pointer dereference"
myObject := new(proto.Message)
err := proto.Unmarshal(byteData, myObject)
objects = append(objects, myObject)
Another alternate:
I am also not sure if using the same variable will work (and hence i am trying to create a new variable each time inside the loop)
PS: This does not require much Cassandra knowledge
Help appreciated. Thanks !
Edit 1:
What I'm trying to accomplish is fetch a few rows from the database. But since I have multiple tables which contain very much similar data, I want to do it in one function in a very much optimised manner. And the values I want to fetch are stored in bytes, which I am using proto to convert into Golang objects.
Edit 2:
proto.Unmarshal needs the second argument to be of type proto.Message. Hence I cant use an empty interface. (Both types A and B implement proto.Message)
Edit 3:
You can find proto at "github.com/golang/protobuf". I use it to convert objects into bytes and also back into objects.!

In Go's type system, what you want to achieve can not be done directly.
However, with help of interface{} and first-class function value, we can get it done, and rather gracefully.
To do this, instead of declaring a new type C, we declare a new constructer :
var newC func() interface{}
if true {
newC = func() interface{} {
c := new(A)
return c
}
} else {
newC = func() interface{} {
c := new(B)
return c
}
}
And then, in the loop, change myObject := new(C) to myObject := newC(). It is done.
Example: https://play.golang.org/p/dBKBYrLqi_P
Edit:
As you need the param being a proto.Message, which I guess is an interface, you can cast it into proto.Message.
So basically you can re-write you code into:
type A struct {//some code}
type B struct {//some code}
func getData(db string) interface{} {
var newC func() interface{}
if true {
newC = func() proto.Message {
c := new(A)
return c
}
} else {
newC = func() proto.Message {
c := new(B)
return c
}
}
var byteData []byte
query := //cassandra query object
iter := query.Iter()
for iter.Scan(&byteData) {
myObject := newC()
err := proto.Unmarshal(byteData, myObject)
objects = append(objects, myObject)
}
return objects
}

Related

How to write struct onto ledger state

I am trying to write chaincode for Hyperledger that has a mapping, that stores struct values mapped to strings. This is my first time writing contracts for Hyperledger and also my first time using go and it appears I am not approaching this the right way.
This is my mapping, Data struct, Init function and addVData function that shows the problem.
type Data struct{
Timestamp string
Velocity string
Location string
}
var all_data map[string]Data
func (t *DataContract) Init(stub shim.ChaincodeStubInterface) peer.Response {
all_data = make(map[string]Data)
return shim.Success(nil)
}
func (t *DataContract) addVData(stub shim.ChaincodeStubInterface, args []string) peer.Response {
params := stub.GetStringArgs()
fmt.Println("The params passed in are:", params)
if len(params) != 4 {
fmt.Println("Please resubmit in this particular order: addVData, Timestamp, Velocity, Location")
return shim.Error("Please resubmit in this particular order: addVData, Timestamp, Velocity, Location")
}
var d = Data{Timestamp:params[1], Velocity:params[2], Location:params[3]}
all_data[params[1]] = d
var err = stub.PutState(params[1],d)
return shim.Success(nil)
}
The error I am getting is actually very clear:
./data.go:79:35: cannot use d (type Data) as type []byte in argument to stub.PutState
I am wondering, since my data is not in form of a byte array, how do I go about storing it?
Also, I am not certain I have implemented the Init method and the mappings in the correct way but have had a hard time finding examples. If you could please explain and point me in the right direction it would be very appreciated, thank you.
Use json.Marshal function to convert the struct into bytes
type UserData struct {
a string
}
userdata := &UserData{a: "hello"}
// Mashelling struct to jsonByte object to put it into the ledger
userDataJSONBytes, err := json.Marshal(&userdata)
if err != nil {
return shim.Error(err.Error())
}
var err = stub.PutState(params[1],userDataJSONBytes)

Update object in memory with values from req.Body

I am creating a simple in-memory server before doing things with a database. I have this update method:
type Nearby struct {
ID int `json:"id,omitempty"`
Me int `json:"me,omitempty"`
You int `json:"you,omitempty"`
ContactTime int64 `json:"contactTime,omitempty"`
}
func (h NearbyHandler) updateById(v NearbyInjection) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
decoder := json.NewDecoder(r.Body)
var t Nearby
err := decoder.Decode(&t)
if err != nil {
panic(err)
}
mtx.Lock()
item, ok := v.Nearby[params["id"]]
mtx.Unlock()
if !ok {
panic(errors.New("No item to update"))
}
// !! Ok, how can I overwrite the properties from t onto item
if ok {
json.NewEncoder(w).Encode(item)
} else {
io.WriteString(w, "null")
}
}
}
I am looking to take the key/values from t, and write them onto the item object. t gets decoded into a struct value (I assume), and item is a struct value found in a map. Both item and t have the same type (Nearby)
In JavaScript, all I am looking to do would be:
Object.assign(item, t);
Just trying to accomplish something similar with Go.
With Golang, I can do this:
item.ContactTime = t.ContactTime
but I only want to overwrite item.ContactTime if t.ContactTime is defined.
Just overwrite the item in your map:
v.Nearby[params["id"]] = t
I'd suggest to use https://github.com/imdario/mergo function Merge. I don't think there is any reason to reinvent the wheel in this one and go's lack of generics does not help with such operations. example:
src := Foo{
A: "one",
B: 2,
}
dest := Foo{
A: "two",
}
mergo.Merge(&dest, src)
fmt.Println(dest)
// Will print
// {two 2}
I also think you should make all Nearby's properties pointers so that you can always compare them against nil to make sure they were not set.

How do I apply my custom UnmarshalJSON method to an embedded struct?

So, I have struct P. I need to unmarshal some json data into P but sometimes it comes embedded struct, Embedded. In either case, I unmarshal the json from the API and need to format the "Formatted" field. It seems in the Embedded case my unmarshaller doesn't get called.
I have the following code:
package main
import (
"encoding/json"
"fmt"
)
type P struct {
Name string `json:"name"`
Formatted string `json:"formatted"`
}
type Embedded struct {
A struct {
B struct {
*P
} `json:"b"`
} `json:"a"`
}
func (p *P) UnmarshalJSON(b []byte) error {
type Alias P
a := &struct {
*Alias
}{
Alias: (*Alias)(p),
}
if err := json.Unmarshal(b, &a); err != nil {
return err
}
a.Formatted = fmt.Sprintf("Hi, my name is %v", a.Name)
return nil
}
func simple() {
b := []byte(`{"name":"bob"}`)
p := &P{}
if err := json.Unmarshal(b, &p); err != nil {
panic(err)
}
fmt.Printf("normal: %+v\n", p)
}
func embedded() {
b := []byte(`{"a":{"b":{"name":"bob"}}}`)
e := &Embedded{}
if err := json.Unmarshal(b, &e); err != nil {
panic(err)
}
fmt.Printf("embedded: %+v\n", e.A.B.P)
}
func main() {
simple()
embedded()
}
(I realize I can get rid of the custom unmarshaller and create a method to format the name but wanted to see if this way was possible.)
I don't know enough to explain all the reasons, I will just list what works and what doesn't. Someone more knowledgeable can fill you in on the reasons behind it.
The following works when B is a *struct, not sure why.
type Embedded struct {
A struct {
B *struct {
P
} `json:"b"`
} `json:"a"`
}
The following also works. I'm guessing that using an anonymous struct had some effect in the last one since a *struct is not required here.
type embedP struct {
P
}
type Embedded struct {
A struct {
B embedP `json:"b"`
} `json:"a"`
}
The following works if *P is initialised.
type embedP struct {
*P
}
type intermediate struct {
B embedP `json:"b"`
}
type Embedded struct {
A intermediate `json:"a"`
}
e := &Embedded{A:intermediate{embedP{P:&P{}}}}
But the same thing doesn't work with anonymous structs.
type Embedded struct {
A struct {
B struct {
*P
} `json:"b"`
} `json:"a"`
}
e := &Embedded{A : struct{B struct{*P}`json:"b"`}{B: struct{*P}{&P{}}}}
Play link
Other improvements
If p := &P{} is already a pointer you don't need to pass &p in json.Unmarshal. json.Unmarshal(b, p) would suffice. Same with e := &Embedded{}.
To extent #John's answer, take a look at the source code of json decoder, especially method indirect(v reflect.Value, decodingNull bool) line 442-483.
// indirect walks down v allocating pointers as needed,
// until it gets to a non-pointer.
// if it encounters an Unmarshaler, indirect stops and returns that.
// if decodingNull is true, indirect stops at the last pointer so it can be set to nil.
The method returns, json.Unmarshaler, encoding.TextUnmarshaler and the value of v. In current implementation, inside the method, basically the following steps were executed
If argument v is not a pointer, it will return immediately without checking whether v implements json.Unmarshaler/encoding.TextUnmarshaler or not. The method assigns nil for both unmarshaller regardless B implements custom unmarshaller or not.
If argument v is a pointer, it will check whether v implements json.Unmarshaler/encoding.TextUnmarshaler or not. In this case, if v is nil, a new value will be assigned to v.
If Embedded is defined as
type Embedded struct {
A struct {
B struct {
*P
} `json:"b"`
} `json:"a"`
}
when, decoding "b":{"name":"bob"} to field B, since B is not a pointer, (1) is applicable. As the result, custom unmarshaller is returned as nil, thus never being called. The json decoder uses default unmarshaller to decode json value to B's fields.
If Embedded is defined as
type Embedded struct {
A struct {
*B struct {
P
} `json:"b"`
} `json:"a"`
}
since field B is a pointer, (2) is applicable. The decoder allocates new struct{*P} to B, detects that B implements custom unmarshaller, then call it as expected. The following declaration
type Embedded struct {
A struct {
*B struct {
*P
} `json:"b"`
} `json:"a"`
}
also works, if P is preallocated, i.e.
//...
e := Embedded{}
e.A.B = &struct{ *P }{P: &P{}}
//...
If it's not preallocated, in (2) the decoder will assign &struct{*P}{} to B, then call the custom unmarshaller with B.P == nil. As the result, json value can't be captured by B.P during unmarshall.
Note:
I'm not sure whether it is desired behavior or not, and I can't find a clear documentation related to embedded struct.

Check if a slice contains a struct with a given field value

Trying to check if a struct in some slice contains a value of a given field so i wrote this
func main() {
//test
Objs := []Obj{{1,"xxx"},{2,"yyy"},{3,"zzz"}}
res := containsStructFieldValue(Objs,"X",1)
fmt.Println(res)
}
type Obj struct {
X int
Y string
}
func containsStructFieldValue(slice []Obj ,fieldName string,fieldValueToCheck interface {}) bool{
for _,s := range slice{
r := reflect.ValueOf(s)
f := r.FieldByName(fieldName)
if f.IsValid(){
if f.Interface() == fieldValueToCheck{
return true //a field with the given value exists
}
}
}
return false
}
i need it to work for any given struct type but when i tried slice []interface as the parameter i found out that its not possible, any idea on how to make the above method work for any struct type?
You can use reflect to range over an interface{}, for instance:
func containsStructFieldValue(slice interface{} ,fieldName string,fieldValueToCheck interface {}) bool{
rangeOnMe := reflect.ValueOf(slice)
for i := 0; i < rangeOnMe.Len(); i++ {
s := rangeOnMe.Index(i)
f := s.FieldByName(fieldName)
if f.IsValid(){
if f.Interface() == fieldValueToCheck {
return true
}
}
}
}
Note that I did not check that slice is indeed a slice... If not, this code will panic. You can use reflect.Kind to check this if you want to avoid this behaviour.

in golang, general function to load http form data into a struct

In Go, http form data (e.g. from a POST or PUT request) can be accessed as a map of the form map[string][]string. I'm having a hard time converting this to structs in a generalizable way.
For example, I want to load a map like:
m := map[string][]string {
"Age": []string{"20"},
"Name": []string{"John Smith"},
}
Into a model like:
type Person struct {
Age int
Name string
}
So I'm trying to write a function with the signature LoadModel(obj interface{}, m map[string][]string) []error that will load the form data into an interface{} that I can type cast back to a Person. Using reflection so that I can use it on any struct type with any fields, not just a Person, and so that I can convert the string from the http data to an int, boolean, etc as necessary.
Using the answer to this question in golang, using reflect, how do you set the value of a struct field? I can set the value of a person using reflect, e.g.:
p := Person{25, "John"}
reflect.ValueOf(&p).Elem().Field(1).SetString("Dave")
But then I'd have to copy the load function for every type of struct I have. When I try it for an interface{} it doesn't work.
pi := (interface{})(p)
reflect.ValueOf(&pi).Elem().Field(1).SetString("Dave")
// panic: reflect: call of reflect.Value.Field on interface Value
How can I do this in the general case? Or even better, is there a more idiomatic Go way to accomplish what I'm trying to do?
You need to make switches for the general case, and load the different field types accordingly. This is basic part.
It gets harder when you have slices in the struct (then you have to load them up to the number of elements in the form field), or you have nested structs.
I have written a package that does this. Please see:
http://www.gorillatoolkit.org/pkg/schema
For fun, I tried it out. Note that I cheated a little bit (see comments), but you should get the picture. There is usually a cost to use reflection vs statically typed assignments (like nemo's answer), so be sure to weigh that in your decision (I haven't benchmarked it though).
Also, obvious disclaimer, I haven't tested all edge cases, etc, etc. Don't just copy paste this in production code :)
So here goes:
package main
import (
"fmt"
"reflect"
"strconv"
)
type Person struct {
Age int
Name string
Salary float64
}
// I cheated a little bit, made the map's value a string instead of a slice.
// Could've used just the index 0 instead, or fill an array of structs (obj).
// Either way, this shows the reflection steps.
//
// Note: no error returned from this example, I just log to stdout. Could definitely
// return an array of errors, and should catch a panic since this is possible
// with the reflect package.
func LoadModel(obj interface{}, m map[string]string) {
defer func() {
if e := recover(); e != nil {
fmt.Printf("Panic! %v\n", e)
}
}()
val := reflect.ValueOf(obj)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
// Loop over map, try to match the key to a field
for k, v := range m {
if f := val.FieldByName(k); f.IsValid() {
// Is it assignable?
if f.CanSet() {
// Assign the map's value to this field, converting to the right data type.
switch f.Type().Kind() {
// Only a few kinds, just to show the basic idea...
case reflect.Int:
if i, e := strconv.ParseInt(v, 0, 0); e == nil {
f.SetInt(i)
} else {
fmt.Printf("Could not set int value of %s: %s\n", k, e)
}
case reflect.Float64:
if fl, e := strconv.ParseFloat(v, 0); e == nil {
f.SetFloat(fl)
} else {
fmt.Printf("Could not set float64 value of %s: %s\n", k, e)
}
case reflect.String:
f.SetString(v)
default:
fmt.Printf("Unsupported format %v for field %s\n", f.Type().Kind(), k)
}
} else {
fmt.Printf("Key '%s' cannot be set\n", k)
}
} else {
// Key does not map to a field in obj
fmt.Printf("Key '%s' does not have a corresponding field in obj %+v\n", k, obj)
}
}
}
func main() {
m := map[string]string{
"Age": "36",
"Name": "Johnny",
"Salary": "1400.33",
"Ignored": "True",
}
p := new(Person)
LoadModel(p, m)
fmt.Printf("After LoadModel: Person=%+v\n", p)
}
I'd propose to use a specific interface instead of interface{} in your LoadModel
which your type has to implement in order to be loaded.
For example:
type Loadable interface{
LoadValue(name string, value []string)
}
func LoadModel(loadable Loadable, data map[string][]string) {
for key, value := range data {
loadable.LoadValue(key, value)
}
}
And your Person implements Loadable by implementing LoadModel like this:
type Person struct {
Age int
Name string
}
func (p *Person) LoadValue(name string, value []string) {
switch name {
case "Age":
p.Age, err = strconv.Atoi(value[0])
// etc.
}
}
This is the way, the encoding/binary package or the encoding/json package work, for example.

Resources