PropertyLoadSaver doesn't work on non-struct types

85 views
Skip to first unread message

Mihai B

unread,
Jul 2, 2016, 12:51:59 PM7/2/16
to google-appengine-go
Hi there, 

 I often use enum types defined as int constants.  On external/web APIs I'm using  Marshal/UnmarshalText to stringify the value. Now I need to store these enums as well but it seems PropertyLoadSaver is not working on non-structs. The documentation is a bit unclear about what types are supported[0]. Is this a bug or a known issue?  When I try to store a value of type  `TImpl` the program doesn't even panic so I Save/Load is not  called at all. This is an issue because I can't use inequality with a single operator(i.e. I need both  > and < ) and the database becomes unreadable to other clients. The enums are used as fields on multiple structs so implementing PropertyLoadSaver on each struct  is not really easy.


type TImpl struct{
F1 ImplType
}

type ImplType int

const(
      Welcome ImplType = "hello"
    GoodBye ImplType = "goodby"
)

func(i *ImplType)Save()([]datastore.Property, error){
panic(i)
if *i == 10{
return []datastore.Property{
{
Value: string("hello"),
},
}, nil
}
return nil, errors.New("expected 10, got something else")
}

func (x *ImplType) Load(ps []datastore.Property) error {
panic(x)
if len(ps) != 1{
return errors.New("Multiple properties?")
}
if s, ok := ps[0].Value.(string); ok {
if  s == "hello"{
*x = 10
}else{
*x = 1
}
return nil
}
return errors.New("invalid type ")
}

Mihai.

[0] `This type may be a struct pointer, but it does not have to be.`

Constantin Konstantinidis

unread,
Jul 2, 2016, 2:47:08 PM7/2/16
to google-appengine-go
Not sure I read correctly but the ImplType is int and not string. "Hello" cannot be converted in int, i.e. compilation immediately fails. Can you show imports to understand from where datastore comes ?

Thanks,

Constantin Konstantinidis

unread,
Jul 2, 2016, 3:36:04 PM7/2/16
to google-appengine-go
I'm reposting on the forum your reply. What function are your calling ? There is no main in your code sample.





Hi Constantin, 

You are right, the code would not compile. Just before I posted the question I’ve  edited the code to make to make more sense as example and mistakenly assigned strings instead of iota but in the real program I’m using integers. However regardless that, the issue is that Save() and Load() is not called(because the program doesn’t panic) by the datastore lib unless they are structs. 


Mihai.

package main

import (
"testing"
)

type TImpl struct {
F1 ImplType
}

type ImplType int
const(
Undefined ImplType = iota
Other
Hello = 10
)

// Implements datastore.PropertyLoadSaver
func (i *ImplType) Save() ([]datastore.Property, error) {
panic(i)
if *i == 10 {
return []datastore.Property{
{
Value: string("hello"),
},
}, nil
}
return nil, errors.New("expected 10, got something else")
}
// Implements datastore.PropertyLoadSaver
func (x *ImplType) Load(ps []datastore.Property) error {
panic(x)
if len(ps) != 1 {
return errors.New("Multiple properties?")
}
if s, ok := ps[0].Value.(string); ok {
if s == "hello" {
*x = 10
} else {
*x = 1
}
return nil
}
return errors.New("invalid type ")
}

func TestStuff(t *testing.T) {
mifv := TImpl{F1: 10}
kind := "implModel"
key := datastore.NewKey(cx, kind, "keyIf3", 0, nil)
_, err := datastore.Put(cx, key, &mifv)
if err != nil {
t.Fatal(err)
}
var rmif TImpl
_, err = datastore.NewQuery(kind).Filter("F1=", "hello").Run(cx).Next(&rmif)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(rmm, mv) {
t.Fatal(rmm)
}
}

Mihai B

unread,
Jul 2, 2016, 11:01:22 PM7/2/16
to google-appengine-go
It's a test function 'TestStuff(t *testing.T)'

Mihai B

unread,
Jul 2, 2016, 11:49:26 PM7/2/16
to google-appengine-go
I've decided to fork the package and modify the internal Save and Load() functions(i.e saveStructProperty)  to check if individual fields implement a custom interface (FieldLoadSaver).

Mihai.

[0]
type FieldLoadSaver interface{
       Save(*datastore.Property)error
       Load(*datastore.Property)error

Adam Tanner

unread,
Jul 3, 2016, 12:18:51 AM7/3/16
to Mihai B, google-appengine-go
Hey Mihai,

From a quick look at the code, I don't think the datastore package supports recursively calling the PropertyLoadSaver interface functions for individual struct fields, though I couldn't find anything in the docs that explicitly mention it's unsupported. I would recommend filing an issue at https://github.com/GoogleCloudPlatform/gcloud-golang/issues for a definitive answer.

Adam

--
You received this message because you are subscribed to the Google Groups "google-appengine-go" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-appengin...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages