Why embedded structs are not decoded when there is an Unmarshal implementation? - go

I have a type ServiceAccount which embeds two other types (User and Policy). However it seems the fields of the User type are totally ignored due the Unmarshaler implementation of the Policy type.
Is there any good reason for this behaviour? It looks like a bug to me because the json package can see through reflection that we have two types embedded and not only the type Policy.
I'm aware that I can "fix" the issue by implementing the Unmarshaler interface on type ServiceAccount too.
package main
import (
"encoding/json"
"fmt"
)
type ServiceAccount struct {
User
Policy
}
type User struct {
UserID string `json:"userID"`
}
type Policy struct {
Scopes string `json:"scopes,omitempty"`
}
// PolicyRaw is the Policy type as received from client.
type PolicyRaw struct {
Scopes string `json:"scopes,omitempty"`
}
func main() {
s := `{"userID":"xyz", "scopes":"some scopes"}`
srvAcc := &ServiceAccount{}
if err := json.Unmarshal([]byte(s), srvAcc); err != nil {
panic(err)
}
fmt.Printf("srvAcc %v", *srvAcc)
}
func (p *Policy) UnmarshalJSON(b []byte) error {
pr := new(PolicyRaw)
if err := json.Unmarshal(b, pr); err != nil {
return err
}
p.Scopes = pr.Scopes
return nil
}
Execute

I don't think it's a bug but just just how interfaces and embedding works. It just happens not to be what you want/expect here.
json.Unmarshal figures out to use the UnmarshalJSON method via this line:
if u, ok := v.Interface().(Unmarshaler); ok
As you know, something implements an interface if it has the right method set which *Policy and *ServiceAccount do. So it's expected that JSON decoding of the the outer type would just call the appropriate method and think it's done.
Interestingly, if you were to experiment and add a dummy method such as:
func (u *User) UnmarshalJSON([]byte) error {return errors.New("not impl")}
then although *User and *Policy would now both implement the interface,
*ServiceAccount will no longer implement that interface. The reason is clear if you try and explicitly call srvAcc.UnmarshalJSON which would then give a compiler error of "ambiguous selector srvAcc.UnmarshalJSON". Without such a call the code is legal and the method is just excluded from the method set.
So I think the solution is one of:
Just don't embed things that implement json.Unmarshaller if you want to marshal the result, e.g. use a named field instead.
Make sure you explicitly implement json.Unmarshaller for the outer type yourself when doing such embedding (e.g. add an UnmarshalJSON method to *ServiceAccount).
Make sure at least two embedded things implement json.Unmarshaller and then they'll work individually¹ but the "outer" type will get the default behaviour.
The last option seems like a hack to me. (And btw could be done on purpose with something like:
type ServiceAccount struct {
User
Policy
dummyMarshaller
}
type dummyMarshaller struct{}
func (dummyMarshaller) MarshalJSON([]byte) error {panic("ouch")}
but that looks really hacky to me).
See also:
https://golang.org/ref/spec#Struct_types
https://golang.org/doc/effective_go.html#embedding
¹ Further testing shows that decoding such anonymous (i.e. embedded fields), that their UnmarshalJSON methods do not get called.

Related

How can I separate generated code package and user code but have them accessible from one place in code

I am newer to golang, so I have some courses that I bought from udemy to help break me into the language. One of them I found very helpful for a general understanding as I took on a project in the language.
In the class that I took, all of the sql related functions were in the sqlc folder with the structure less broken out:
sqlc
generatedcode
store
One of those files is a querier that is generated by sqlc that contains an interface with all of the methods that were generated. Here is the general idea of what it currently looks like: https://github.com/techschool/simplebank/tree/master/db/sqlc
package db
import (
"context"
"github.com/google/uuid"
)
type Querier interface {
AddAccountBalance(ctx context.Context, arg AddAccountBalanceParams) (Account, error)
CreateAccount(ctx context.Context, arg CreateAccountParams) (Account, error)
...
}
var _ Querier = (*Queries)(nil)
Would it be possible to wrap both what sqlc generates AND any queries that a developer creates (dynamic queries) into a single querier? I'm also trying to have it so that the sqlc generated code is in its own folder. The structure I am aiming for is:
sql
sqlc
generatedcode
store - (wraps it all together)
dynamicsqlfiles
This should clear up what a I mean by store: https://github.com/techschool/simplebank/blob/master/db/sqlc/store.go
package db
import (
"context"
"database/sql"
"fmt"
)
// Store defines all functions to execute db queries and transactions
type Store interface {
Querier
TransferTx(ctx context.Context, arg TransferTxParams) (TransferTxResult, error)
}
// SQLStore provides all functions to execute SQL queries and transactions
type SQLStore struct {
db *sql.DB
*Queries
}
// NewStore creates a new store
func NewStore(db *sql.DB) Store {
return &SQLStore{
db: db,
Queries: New(db),
}
}
I'm trying to run everything through that store (both generated and my functions), so I can make a call similar to the CreateUser function in this file (server.store.): https://github.com/techschool/simplebank/blob/master/api/user.go
arg := db.CreateUserParams{
Username: req.Username,
HashedPassword: hashedPassword,
FullName: req.FullName,
Email: req.Email,
}
user, err := server.store.CreateUser(ctx, arg)
if err != nil {
if pqErr, ok := err.(*pq.Error); ok {
switch pqErr.Code.Name() {
case "unique_violation":
ctx.JSON(http.StatusForbidden, errorResponse(err))
return
}
}
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
I've tried creating something that houses another querier interface that embeds the generated one, then creating my own db.go that uses the generated DBTX interface but has its own Queries struct, and New function. It always gives me an error that the Queries struct I created aren't implementing the functions I made, despite having it implemented in one of the custom methods I made.
I deleted that branch, and have been clicking through the simplebank project linked above to see if I can find another way this could be done, or if I missed something. If it can't be done, that's okay. I'm just using this as a good opportunity to learn a little more about the language, and keep some code separated if possible.
UPDATE:
There were only a few pieces I had to change, but I modified the store.go to look more like:
// sdb is imported, but points to the generated Querier
// Store provides all functions to execute db queries and transactions
type Store interface {
sdb.Querier
DynamicQuerier
}
// SQLStore provides all functions to execute SQL queries and transactions
type SQLStore struct {
db *sql.DB
*sdb.Queries
*dynamicQueries
}
// NewStore creates a new Store
func NewStore(db *sql.DB) Store {
return &SQLStore{
db: db,
Queries: sdb.New(db),
dynamicQueries: New(db),
}
}
Then just created a new Querier and struct for the methods I would be creating. Gave them their own New function, and tied it together in the above. Before, I was trying to figure out a way to reuse as much of the generated code as possible, which I think was the issue.
Why I wanted the Interface:
I wanted a structure that separated the files I would be working in more from the files that I would never touch (generated). This is the new structure:
I like how the generated code put everything in the Querier interface, then checked that anything implementing it satisfied all of the function requirements. So I wanted to replicate that for the dynamic portion which I would be creating on my own.
It might be complicating it a bit more than it would 'NEED' to be, but it also provides an additional set of error checking that is nice to have. And in this case, even while maybe not necessary, it ended up being doable.
Would it be possible to wrap both what sqlc generates AND any queries that a developer creates (dynamic queries) into a single querier?
If I'm understanding your question correctly I think that you are looking for something like the below (playground):
package main
import (
"context"
"database/sql"
)
// Sample SQL C Code
type DBTX interface {
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
}
type Queries struct {
db DBTX
}
func (q *Queries) DeleteAccount(ctx context.Context, id int64) error {
// _, err := q.db.ExecContext(ctx, deleteAccount, id)
// return err
return nil // Pretend that this always works
}
type Querier interface {
DeleteAccount(ctx context.Context, id int64) error
}
//
// Your custom "dynamic" queries
//
type myDynamicQueries struct {
db DBTX
}
func (m *myDynamicQueries) GetDynamicResult(ctx context.Context) error {
// _, err := q.db.ExecContext(ctx, deleteAccount, id)
// return err
return nil // Pretend that this always works
}
type myDynamicQuerier interface {
GetDynamicResult(ctx context.Context) error
}
// Combine things
type allDatabase struct {
*Queries // Note: You could embed this directly into myDynamicQueries instead of having a seperate struct if that is your preference
*myDynamicQueries
}
type DatabaseFunctions interface {
Querier
myDynamicQuerier
}
func main() {
// Basic example
var db DatabaseFunctions
db = getDatabase()
db.DeleteAccount(context.Background(), 0)
db.GetDynamicResult(context.Background())
}
// getDatabase - Perform whatever is needed to connect to database...
func getDatabase() allDatabase {
sqlc := &Queries{db: nil} // In reality you would use New() to do this!
myDyn := &myDynamicQueries{db: nil} // Again it's often cleaner to use a function
return allDatabase{Queries: sqlc, myDynamicQueries: myDyn}
}
The above is all in one file for simplicity but could easily pull from multiple packages e.g.
type allDatabase struct {
*generatedcode.Queries
*store.myDynamicQueries
}
If this does not answer your question then please show one of your failed attempts (so we can see where you are going wrong).
One general comment - do you really need the interface? A common recommendation is "Accept interfaces, return structs". While this may not always apply I suspect you may be introducing interfaces where they are not really necessary and this may add unnecessary complexity.
I thought that the Store, which was housing both Queriers, was tying it all together. Can you explain a little with the example above (in the question post) why it's not necessary? How does SQLStore get access to all of the Querier interface functions?
The struct SQLStore is what is "tying it all together". As per the Go spec:
Given a struct type S and a named type T, promoted methods are included in the method set of the struct as follows:
If S contains an embedded 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 embedded field *T, the method sets of S and *S both include promoted methods with receiver T or *T.
So an object of type SQLStore:
type SQLStore struct {
db *sql.DB
*sdb.Queries
*dynamicQueries
}
var foo SQLStore // Assume that we are actually providing values for all fields
Will implement all of the methods of sdb.Queries and, also, those in dynamicQueries (you can also access the sql.DB members via foo.db.XXX). This means that you can call foo.AddAccountBalance() and foo.MyGenericQuery() (assuming that is in dynamicQueries!) etc.
The spec says "In its most basic form an interface specifies a (possibly empty) list of methods". So you can think of an interface as a list of functions that must be implemented by whatever implementation (e.g. struct) you assign to the interface (the interface itself does not implement anything directly).
This example might help you understand.
Hopefully that helps a little (as I'm not sure which aspect you don't understand I'm not really sure what to focus on).

How do I improve the testability of go library methods

I'm writing some code that uses a library called Vault. In this library we have a Client. My code makes use of this Client but I want to be able to easily test the code that uses it. I use only a couple methods from the library so I ended up creating an interface:
type VaultClient interface {
Logical() *api.Logical
SetToken(v string)
NewLifetimeWatcher(i *api.LifetimeWatcherInput) (*api.LifetimeWatcher, error)
}
Now if my code is pointed at this interface everything is easily testable.. Except let's look at the Logical() method. It returns a struct here. My issue is that this Logical struct also has methods on it that allow you to Read, Write, ex:
func (c *Logical) Read(path string) (*Secret, error) {
return c.ReadWithData(path, nil)
}
and these are being used in my project as well to do something like:
{{ VaultClient defined above }}.Logical().Write("something", something)
Here is the issue. The Logical returned from the call to .Logical() has a .Write and .Read method that I can't reach to mock. I don't want all the logic within those methods to run in my tests.
Ideally I'd like to be able to do something similar to what I did above and create an interface for Logical as well. I'm relatively new to Golang, but I'm struggling with the best approach here. From what I can tell that's not possible. Embedding doesn't work like inheritance so it seems like I have to return a Logical. That leaves my code unable to be tested as simply as I would like because all the logic within a Logical's methods can't be mocked.
I'm sort of at a loss here. I have scoured Google for an answer to this but nobody ever talks about this scenario. They only go as far as I went with the initial interface for the client.
Is this a common scenario? Other libraries I've used don't return structs like Logical. Instead they typically just return a bland struct that holds data and has no methods.
package usecasevaultclient
// usecase.go
type VaultClient interface {
Logical() *api.Logical
SetToken(v string)
NewLifetimeWatcher(i *api.LifetimeWatcherInput) (*api.LifetimeWatcher, error)
}
type vaultClient struct {
repo RepoVaultClient
}
// create new injection
func NewVaultClient(repo RepoVaultClient) VaultClient {
return &vaultClient{repo}
}
func(u *vaultClient) Logical() *api.Logical {
// do your logic and call the repo of
u.repo.ReadData()
u.repo.WriteData()
}
func(u *vaultClient) SetToken(v string) {}
func(u *vaultClient) NewLifetimeWatcher(i *api.LifetimeWatcherInput) (*api.LifetimeWatcher, error)
// interfaces.go
type RepoVaultClient interface {
ReadData() error
WriteData() error
}
// repo_vaultclient_mock.go
import "github.com/stretchr/testify/mock"
type MockRepoVaultClient struct {
mock.Mock
}
func (m *MockRepoVaultClient) ReadData() error {
args := m.Called()
return args.Error(0)
}
func (m *MockRepoVaultClient) WriteData() error {
args := m.Called()
return args.Error(0)
}
// vaultClient_test.go
func TestLogicalShouldBeSuccess(t *testing.T) {
mockRepoVaultClient = &MockRepoVaultClient{}
useCase := NewVaultClient(mockRepoVaultClient)
mockRepoVaultClient.On("ReadData").Return(nil)
mockRepoVaultClient.On("WriteData").Return(nil)
// your logics gonna make this response as actual what u implemented
response := useCase.Logical()
assert.Equal(t, expected, response)
}
if you want to test the interface of Logical you need to mock the ReadData and WriteData , with testify/mock so u can defined the respond of return of those methods and you can compare it after you called the new injection of your interface

How can we mock cassandra session using golang?

Q : Is there any way to mock casssandra session using go without actually connecting to any keyspace/schema/DB. Can we mock cassandra for unit testing?
In general the best thing to do is to use interfaces instead of the real cassandra library implementation.
You've not included an example so I've created on below:
type Service struct {
session *gocql.Session
}
func (s *Service) Tweets() {
var id gocql.UUID
var text string
q := `SELECT id, text FROM tweet WHERE timeline = ? LIMIT 1`
if err := s.session.Query(q, "me").Consistency(gocql.One).Scan(&id, &text); err != nil {
log.Fatal(err)
}
fmt.Println("Tweet:", id, text)
}
In this example we use the s.session field from the *Service method receiver.
Instead of using the session directly, we can create interfaces that allow us to later create mocks.
// SessionInterface allows gomock mock of gocql.Session
type SessionInterface interface {
Query(string, ...interface{}) QueryInterface
}
// QueryInterface allows gomock mock of gocql.Query
type QueryInterface interface {
Bind(...interface{}) QueryInterface
Exec() error
Iter() IterInterface
Scan(...interface{}) error
}
Now our updated code might look like:
type Service struct {
session SessionInterface
}
This means that we can implement the SessionInterface with a mock implementation and control the return values for testing.
Full code example of interfaces here
This question is a bit old, but I also found the gockle library, which contains an interface for the mock-worth driver components. This library is referenced by the gocql library in the README.

How pass different structures to function?

I have several different structures.
Here show two:
type AdsResponse struct {
Body struct {
Docs []struct {
ID int `json:"ID"`
// others
} `json:"docs"`
} `json:"response"`
Header `json:"responseHeader"`
}
type OtherResponse struct {
Body struct {
Docs []struct {
ID int `json:"ID"`
// others
} `json:"docs"`
} `json:"response"`
Header `json:"responseHeader"`
}
but i don't know how i can do for this method accepts and return both.
func Get(url string, response Response) (Response, bool) {
res, err := goreq.Request{
Uri: url,
}.Do()
// several validations
res.Body.FromJsonTo(&response)
return response, true
}
And use like this:
var struct1 AdsResponse
var struct2 OtherResponse
Get("someURL", struct1)
Get("someURL", struct2)
There are any form?
Your code example is somewhat confusing since both structs appear to be identical. I'll assume that they differ somewhere in "others".
First, I generally recommend creating a wrapper around these kinds of JSON deserializations. Working directly on the JSON structure is fragile. Most of your program should not be aware of the fact that the data comes down in JSON. So for instance, you can wrap this in an Ads struct that contains an AdsResponse, or just copies the pieces it cares about out of it. Doing that will also make some of the below slightly easier to implement and less fragile.
The most common solution is probably to create an interface:
type Response interface {
ID() int
}
You make both Ads and Others conform to Response. Then you can return Response. If necessary, you can type-switch later to figure out which one you have and unload other data.
switch response := response.(type) {
case Ads:
...
case Other:
...
}
I don't quite get why you have the reponse as a parameter and as a return. I think you dont need to return it. You should pass a pointer to the reponse and fill it with the data. Also, I'd return an Error instead of a boolean, but that is another topic.
Anyway, the solution is to use interface{} (empty interface).
You are lucky because the function you are using (FromJsonTo) accepts an empty interface as a parameter, so you can safely change your parameter type to interface{} and just pass it to FromJsonTo. Like this:
func Get(url string, response interface{}) bool {
res, err := goreq.Request{
Uri: url,
}.Do()
// several validations
res.Body.FromJsonTo(response)
return true
}
Warning: I did not compile the code.
Then you would call this function with the url and a pointer to one of the reponse structs like this:
var struct1 AdsResponse
var struct2 OtherResponse
Get("someURL", &struct1)
Get("someURL", &struct2)
The way to achieve this is through Go's interfaces.
Two options:
empty interface
Get(url string, response interface{}) (Response, bool)
This option allows any value to be given to this function.
custom interface
Creating a custom interface will allow you to narrow down the types that can be provided as arguments to your function.
In this case you'll have to create an interface that all your Response structs will need to abide by. Any struct really that abides by that interface will be able to be used as an argument of your function.
Something like this:
type MyResponse interface {
SomeFunction()
}
Then your function signature could look like
Get(url string, response MyResponse) (MyResponse, bool)
As long as AdsResponse and OtherResponse abide by the MyResponse interface, they will be allowed to be used as arguments to the function.
Follow the solution working at Go Playground
Go has no polymorphic or any other OO like behaviour, so, when you try to pass a AdsResponse or OtherResponse struct as an Response (or any interface{}), these values becomes an Response (or other param type specified), and is not possible to Go to infer the real type that originate these interface{} and correctly decode your json to these struct types as expected.
This kind of thing should works perfectly in OO languages, like Java, C# etc. There is no hierarchy generalization/specialization on structs/interfaces in Go.
You would need to do a type assertion in your Rest executor, or a switch case, but it seems that you need a generic REST executor, like a generic lib some thing like that. Would not reasonable create a switch case for each struct in your program. Maybe you have dozens or hundreds of structs soon.
I think that a reasonable solution is the rest client pass a lambda function to do the last step for your, that is just create a correct struct destination type and call json decode.
As i say above, the return type of executeRest() in my example will became an interface{}, but the rest client can securely do the type assertion of returned value after executeRest() call.

calling function from map[string]interface{} by giving key

I want to be able to pass function name to gin.Engine route handler. I have the following code;
// status service
type StatusService struct {
App *gin.Engine
}
func (s *StatusService) Ping(ctx *gin.Context) {
ctx.JSON(200, gin.H{
"message": "pong",
})
}
app := gin.Default()
// define services
statusService := &services.StatusService{
App: app,
}
ss := make(map[string]interface{})
ss["auth"] = statusService
app.GET("/ping", ss["auth"].Ping)
The compiler gives the following error;
./app.go:60: ss["auth"].Ping undefined (type interface {} has no field or method Ping)
Any ideas about how to fix that?
interface{} works for just about any type, the problem is that you've failed to assert which type the thing is. In this case you would need something like... ss["auth"].(*StatusService).Ping(myCtxInstance). This answer has a more thorough example which I'll refrain from duplicating; Go map of functions
Couple other things; if your real use case is as simple as your example just stop what you're doing and add func(ctx *gin.Context) as a second argument. Also, depending on the nature of the functions you want to use (like if they all have the same args and return types) then you might want to use a second arg for the delegates, map[string]func(argumentType) would be more appropriate.
The design you currently have pushes all errors to runtime which obviously is less desirable than the compile time safety you'd get from either of the options I touched on above.

Resources