In Google App Engine for Go, how can a property have values ​​of more than one type?

Google App Engine for the Go datastore docs says, "A property can have more than one type of value . " There is no example or additional explanation. (Version: appengine 1.9.19.)

How does a property have more than one type if you have to declare that property with a specific type in the backing structure?

+3


source to share


1 answer


You do not need to declare a specific type for the property in the backing structure.

By injecting PropertyLoadSaver

, you can dynamically do whatever you want with the properties of the object during load or before saving. See this answer which shows how to represent an object as a generic type map[string]interface{}

in Go, so it can have dynamic properties.

Back to your question:

A property can have more than one type of value.

It's right. But if you want to make this work, you will also have to use your own load / save mechanism through the interface PropertyLoadSaver

.

Define a fallback first struct

, where a property that will have multiple values ​​of different types could be []interface{}

:

type MyMy struct {
    Objects []interface{}
}

      



Then we have to implement PropertyLoadSaver

. On load, we'll just add all the values ​​to the slice Objects

, which will have a name "Objects"

.

On saving, we will iterate over the slice items Objects

and send all of its values ​​with the same property name. This ensures they are stored under the same property, and we must also specify the field Multiple

as a true

(multivalued property):

func (m *MyMy) Load(ch <-chan datastore.Property) error {
    for p := range ch { // Read until channel is closed
        if p.Name == "Objects" {
            m.Objects = append(m.Objects, p.Value)
        }
    }
    return nil
}

func (m *MyMy) Save(ch chan<- datastore.Property) error {
    defer close(ch)
    for _, v := range m.Objects {
        switch v2 := v.(type) {
        case int64: // Here v2 is of type int64
            ch <- datastore.Property{Name: "Objects", Value: v2, Multiple: true}
        case string:  // Here v2 is of type string
            ch <- datastore.Property{Name: "Objects", Value: v2, Multiple: true}
        case float64: // Here v2 is of type float64
            ch <- datastore.Property{Name: "Objects", Value: v2, Multiple: true}
        }
    }
    return nil
}

      

Please note that setting the value of type interface{}

to as Property.Value

will result in an error, so I used a type switch so I will set specific types. In my example, I only supported 3 types ( int64

, string

and float64

), but you can simply add more types by adding new branches case

.

And using it:

And finally, using our custom type MyMy

to save a new object with the Objects property, which will have multiple values ​​and different types:

m := MyMy{[]interface{}{int64(1234), "strval", 32.2}}
key, err := datastore.Put(c, datastore.NewIncompleteKey(c, "MyMy", nil), &m)

      

+3


source







All Articles