googleapis / google-cloud-go

Google Cloud Client Libraries for Go.
https://cloud.google.com/go/docs/reference
Apache License 2.0
3.68k stars 1.26k forks source link

datastore: PropertyLoadSaver doesn't store __key__ of embedded entity #10351

Open Philio opened 2 months ago

Philio commented 2 months ago

Client

Datastore

Environment

Linux

Go Environment

$ go version

go version go1.22.3 linux/amd64

$ go env

GO111MODULE='on'
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/phil/.cache/go-build'
GOENV='/home/phil/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/phil/go/pkg/mod'
GONOPROXY='github.com/boxes-ltd'
GONOSUMDB='github.com/boxes-ltd'
GOOS='linux'
GOPATH='/home/phil/go'
GOPRIVATE='github.com/boxes-ltd'
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/snap/go/10603'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/snap/go/10603/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.22.3'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/home/phil/GolandProjects/boxes-common/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build4098846308=/tmp/go-build -gno-record-gcc-switches'

Code

I have a struct with 2 slices, they are interface types so although they save correctly they require a PropertyLoadSaver implementation to reconstruct them on load

type BoxSpec struct {
    Key  *datastore.Key `datastore:"__key__"`
    Content  []SortableContent
    Criteria []SortableCriteria
    Order    int
}

func (s *BoxSpec) LoadKey(k *datastore.Key) error {
    s.Key = k
    return nil
}

func (s *BoxSpec) Load(ps []datastore.Property) error {
    // TODO: Load properties into struct
    return nil
}

func (s *BoxSpec) Save() ([]datastore.Property, error) {
    return datastore.SaveStruct(s)
}

Expected behavior

The key is returned by datastore.SaveStruct(s) (see debug screenshot below) so I would have expected it to be saved

Actual behavior

BoxSpec is embedded in another entity, if I save without the PropertyLoadSaver implementation the key gets saved:

{
  "values": [
    {
      "entityValue": {
        "key": {
          "partitionId": {
            "projectId": "*******"
          },
          "path": [
            {
              "kind": "Boxes_BoxSpec",
              "name": "018ffd4d-1543-760c-9437-fbc05141f3ab"
            }
          ]
        },
        "properties": {
          "Order": {
            "integerValue": "0"
          },
...

After adding PropertyLoadSaver implementation the key is returned by datastore.SaveStruct(s) but doesn't get saved in the database:

{
  "values": [
    {
      "entityValue": {
        "properties": {
          "Order": {
            "integerValue": "0"
          },
...

Screenshots

Screenshot from 2024-06-09 15-49-44

Additional context

N/A

Philio commented 2 months ago

Currently the solution I have is to save/load the key as an additional property:

func (s *BoxSpec) Load(ps []datastore.Property) error {
    for _, p := range ps {
        switch p.Name {
        case "Key":
            s.Key = p.Value.(*datastore.Key)
        }
    }
    return nil
}

func (s *BoxSpec) Save() ([]datastore.Property, error) {
    ps, err := datastore.SaveStruct(s)
    if err != nil {
        return ps, err
    }
    ps = append(ps, datastore.Property{
        Name:  "Key",
        Value: s.Key,
    })
    return ps, nil
}