I'm trying to get getObj() function will be more general and could
work with any type, not only User like in my code.
I was thinking in return a interface instead a defined struct, but I can't fit this
idea to my code, please could someone give me a hand with this?
Thanks in advance
type User struct {
FirstName string `bson:"first_name"`
LastName string `bson:"last_name"`
}
type Mbase struct {
coll *mgo.Collection
sess *mgo.Session
}
func (b *Mbase) getObj(attr string, val string) (res *User, err error) {
err = b.coll.Find(bson.M{attr: val}).One(&res)
if err != nil {
return
}
err = nil
return
}
You can do something like:
func (b *Mbase) GetObj(attr string, val string, result interface{}) error {
return b.coll.Find(bson.M{attr: val}).One(result)
}
Doesn't feel like the helper is doing much good, though. Find+One
itself is already generic. I'd also consider using bson.D{{attr, val}}
instead of bson.M if that's all you need.
Also, please consider asking questions in a single forum at a time.
Related
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)
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.
Sorry if this question is a bit basic.
I am trying to use Golang interfaces to make the implementation of CRUD more dynamic.
I have implemented an interface as follows
type Datastore interface {
AllQuery() ([]interface{}, error)
ReadQuery() ([]interface{}, error)
UpdateQuery() ([]interface{}, error)
CreateQuery() ([]interface{}, error)
DestroyQuery() ([]interface{}, error)//Im not sure if the return value implementation is correct
}
That can be used with a multitude of models category Category,tag Tag.etc
It implements the methods indicative of the structs which represent the models in the app.
Here is the simplified handler/controller
func UpdateHandler(c handler.context) error {
p := new(models.Post)
return Update(p,c)
}
This is the function implementing the interface
func Update(data Datastore,c handler.context) error{
if err := c.Bind(data); err != nil {
log.Error(err)
}
d, err := data.UpdateQuery()
//stuff(err checking .etc)
return c.JSON(fasthttp.StatusOK, d)///the returned value is used here
}
This is the method I am using to query the database
func (post Post) UpdateQuery() ([]interface{}, error){
//run query using the
return //I dont know how to structure the return statement
}
How do I structure the interface above and the methods it implements so that I can return the result of the query back to the implementing function.
Please let me know if I need to add anything to the question or improve it I will try to do so promptly.
Thanks!
I think you should store the return value to a variable. Also make sure that this return value (result) is slice of interface.
If it's not then convert it by
v := reflect.ValueOf(s)
intf := make([]interface{}, v.Len())
In your case your UpdateQuery function might look like
func (post Post) UpdateQuery() (interface{}, bool) {
result,err := []Struct{}
return result, err
}
Demo :
https://play.golang.org/p/HOU56KibUd
Due to error handling in Go, I often end up with multiple values functions. So far, the way I have managed this has been very messy and I am looking for best practices to write cleaner code.
Let's say I have the following function:
type Item struct {
Value int
Name string
}
func Get(value int) (Item, error) {
// some code
return item, nil
}
How can I assign a new variable to item.Value elegantly. Before introducing the error handling, my function just returned item and I could simply do this:
val := Get(1).Value
Now I do this:
item, _ := Get(1)
val := item.Value
Isn't there a way to access directly the first returned variable?
In case of a multi-value return function you can't refer to fields or methods of a specific value of the result when calling the function.
And if one of them is an error, it's there for a reason (which is the function might fail) and you should not bypass it because if you do, your subsequent code might also fail miserably (e.g. resulting in runtime panic).
However there might be situations where you know the code will not fail in any circumstances. In these cases you can provide a helper function (or method) which will discard the error (or raise a runtime panic if it still occurs).
This can be the case if you provide the input values for a function from code, and you know they work.
Great examples of this are the template and regexp packages: if you provide a valid template or regexp at compile time, you can be sure they can always be parsed without errors at runtime. For this reason the template package provides the Must(t *Template, err error) *Template function and the regexp package provides the MustCompile(str string) *Regexp function: they don't return errors because their intended use is where the input is guaranteed to be valid.
Examples:
// "text" is a valid template, parsing it will not fail
var t = template.Must(template.New("name").Parse("text"))
// `^[a-z]+\[[0-9]+\]$` is a valid regexp, always compiles
var validID = regexp.MustCompile(`^[a-z]+\[[0-9]+\]$`)
Back to your case
IF you can be certain Get() will not produce error for certain input values, you can create a helper Must() function which would not return the error but raise a runtime panic if it still occurs:
func Must(i Item, err error) Item {
if err != nil {
panic(err)
}
return i
}
But you should not use this in all cases, just when you're sure it succeeds. Usage:
val := Must(Get(1)).Value
Go 1.18 generics update: Go 1.18 adds generics support, it is now possible to write a generic Must() function:
func Must[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}
This is available in github.com/icza/gog, as gog.Must() (disclosure: I'm the author).
Alternative / Simplification
You can even simplify it further if you incorporate the Get() call into your helper function, let's call it MustGet:
func MustGet(value int) Item {
i, err := Get(value)
if err != nil {
panic(err)
}
return i
}
Usage:
val := MustGet(1).Value
See some interesting / related questions:
How to pass multiple return values to a variadic function?
Return map like 'ok' in Golang on normal functions
Yes, there is.
Surprising, huh? You can get a specific value from a multiple return using a simple mute function:
package main
import "fmt"
import "strings"
func µ(a ...interface{}) []interface{} {
return a
}
type A struct {
B string
C func()(string)
}
func main() {
a := A {
B:strings.TrimSpace(µ(E())[1].(string)),
C:µ(G())[0].(func()(string)),
}
fmt.Printf ("%s says %s\n", a.B, a.C())
}
func E() (bool, string) {
return false, "F"
}
func G() (func()(string), bool) {
return func() string { return "Hello" }, true
}
https://play.golang.org/p/IwqmoKwVm-
Notice how you select the value number just like you would from a slice/array and then the type to get the actual value.
You can read more about the science behind that from this article. Credits to the author.
No, but that is a good thing since you should always handle your errors.
There are techniques that you can employ to defer error handling, see Errors are values by Rob Pike.
ew := &errWriter{w: fd}
ew.write(p0[a:b])
ew.write(p1[c:d])
ew.write(p2[e:f])
// and so on
if ew.err != nil {
return ew.err
}
In this example from the blog post he illustrates how you could create an errWriter type that defers error handling till you are done calling write.
No, you cannot directly access the first value.
I suppose a hack for this would be to return an array of values instead of "item" and "err", and then just do
item, _ := Get(1)[0]
but I would not recommend this.
How about this way?
package main
import (
"fmt"
"errors"
)
type Item struct {
Value int
Name string
}
var items []Item = []Item{{Value:0, Name:"zero"},
{Value:1, Name:"one"},
{Value:2, Name:"two"}}
func main() {
var err error
v := Get(3, &err).Value
if err != nil {
fmt.Println(err)
return
}
fmt.Println(v)
}
func Get(value int, err *error) Item {
if value > (len(items) - 1) {
*err = errors.New("error")
return Item{}
} else {
return items[value]
}
}
Here's a generic helper function with assumption checking:
func assumeNoError(value interface{}, err error) interface{} {
if err != nil {
panic("error encountered when none assumed:" + err.Error())
}
return value
}
Since this returns as an interface{}, you'll generally need to cast it back to your function's return type.
For example, the OP's example called Get(1), which returns (Item, error).
item := assumeNoError(Get(1)).(Item)
The trick that makes this possible: Multi-values returned from one function call can be passed in as multi-variable arguments to another function.
As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order.
This answer borrows heavily from existing answers, but none had provided a simple, generic solution of this form.
I have the following piece of code:
func GetUUIDValidator(text string) bool {
r, _ := regexp.Compile("/[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/")
return r.Match([]byte(text))
}
But when I pass fbd3036f-0f1c-4e98-b71c-d4cd61213f90 as a value, I got false, while indeed it is an UUID v4.
What am I doing wrong?
Regex is expensive. The following approach is ~18x times faster than the regex version.
Use something like https://godoc.org/github.com/google/uuid#Parse instead.
import "github.com/google/uuid"
func IsValidUUID(u string) bool {
_, err := uuid.Parse(u)
return err == nil
}
Try with...
func IsValidUUID(uuid string) bool {
r := regexp.MustCompile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$")
return r.MatchString(uuid)
}
Live example: https://play.golang.org/p/a4Z-Jn4EvG
Note: as others have said, validating UUIDs with regular expressions can be slow. Consider other options too if you need better performance.
You can utilize satori/go.uuid package to accomplish this:
import "github.com/satori/go.uuid"
func IsValidUUID(u string) bool {
_, err := uuid.FromString(u)
return err == nil
}
This package is widely used for UUID operations: https://github.com/satori/go.uuid
In case you would be validating it as attribute of a struct, there is an awesome golang library straight from the Go called validator https://godoc.org/gopkg.in/go-playground/validator.v9 which you can use to validate all kinds of fields nested structures by provided built-in validators as well as complete custom validation methods. All you need to do is just add proper tags to the fields
import "gopkg.in/go-playground/validator.v9"
type myObject struct {
UID string `validate:"required,uuid4"`
}
func validate(obj *myObject) {
validate := validator.New()
err := validate.Struct(obj)
}
It provides structured field errors and other relevant data from it.