Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

datastore: invalid entity type on Put

I am trying to create a wrapper around my Kinds and here is how I am doing it:

package model

import (
    "time"
)

type Kind interface {
    Name() string
}

type Message struct {
    Text      string
    CreatedOn time.Time
    UserId    string
}

func (q Message) Name() string {
    return "MESSAGE"
}

And the reason I introduced type Kind interface is:

// Stores the given model for the the kind in data store
func Store(req *http.Request, data Kind) error {
    ctx := appengine.NewContext(req)
    key := datastore.NewKey(ctx, data.Name(), "", 0, nil)
    _, err := datastore.Put(ctx, key, &data)
    return err
}

As you can see, I am using data.Name() to get the kinds name.

When I try to save the data, it complains about:

datastore: invalid entity type

I read that this could be due to not passing the reference to datastore.Put, but I am doing that. Any idea?

I must add that when I checked the type of data (using reflect.TypeOf()), it is model.Message which is correct too. So it is a concrete type.

like image 509
Max ZooZoo Avatar asked May 28 '16 00:05

Max ZooZoo


1 Answers

datastore.Put() expects the entity data as a struct pointer or any value that implements PropertyLoadSaver. This is clearly stated in its doc:

src must be a struct pointer or implement PropertyLoadSaver

What you pass to datastore.Put() is a pointer value, a pointer to an interface. It's true that the value stored in the interface is of concrete type model.Message, but they are not the same.

You can't use reflect.TypeOf().String() because in case of interface it tells you the concrete type stored in the interface (so it might be misleading).

See this code to demonstrate the difference:

var data Kind = Message{}
fmt.Println(reflect.TypeOf(&data).Kind())
fmt.Println(reflect.TypeOf(&data).Elem().Kind())

var msg Message = Message{}
fmt.Println(reflect.TypeOf(&msg).Kind())
fmt.Println(reflect.TypeOf(&msg).Elem().Kind())

Output (try it on the Go Playground):

ptr
interface
ptr
struct

All in all, &data is a pointer to an interface, and that is not allowed to be passed to datastore.Put(). You can only pass *Message, or if you want to pass an interface value (NOT a pointer to an interface), then make sure to implement PropertyLoadSaver.

like image 101
icza Avatar answered Oct 14 '22 03:10

icza