google-cloud-go icon indicating copy to clipboard operation
google-cloud-go copied to clipboard

datastore: datastore.put does not allow any non-empty value in the slice if the first value is empty with `omitempty` option

Open dmotylev opened this issue 2 years ago • 3 comments

Client

Datastore

Environment

MacOS

Go Environment

$ go version

go version go1.19.2 darwin/arm64

$ go env

GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/dmotylev/Library/Caches/go-build"
GOENV="/Users/dmotylev/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/dmotylev/go/pkg/mod"
GONOPROXY="github.com/redsift/*"
GONOSUMDB="github.com/redsift/*"
GOOS="darwin"
GOPATH="/Users/dmotylev/go"
GOPRIVATE="github.com/redsift/*"
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/opt/homebrew/Cellar/go/1.19.2/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/homebrew/Cellar/go/1.19.2/libexec/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.19.2"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/dmotylev/Workshop/redsift/smart/go.mod"
GOWORK="/Users/dmotylev/Workshop/redsift/smart/go.work"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/r4/lm381q1x3mq60xmkmxz5z1l00000gn/T/go-build743168484=/tmp/go-build -gno-record-gcc-switches -fno-common"

Code

package main

import (
	"context"
	"fmt"

	"cloud.google.com/go/datastore"
)

const (
	projectId = "SOME"
)

type T struct {
	Values []string `datastore:",noindex,omitempty" json:"values,omitempty"`
}

func test(client *datastore.Client, key string, want T) {
	k := datastore.NameKey("test", key, nil)

	fmt.Println("\nTEST", key)

	_, err := client.Put(context.TODO(), k, &want)
	if err != nil {
		fmt.Printf("datastore.Put(%s) %s\n", key, err)
		return
	}

	var got T
	err = client.Get(context.TODO(), k, &got)

	if err != nil {
		fmt.Printf("datastore.Get(%s) %s\n", key, err)
		return
	}

	fmt.Printf("want: %#v\n got: %#v\n", want, got)
}

func main() {
	client, err := datastore.NewClient(context.TODO(), projectId)
	if err != nil {
		panic(err)
	}

	test(client, "empty-strings", T{Values: []string{"", "", ""}})
	test(client, "non-empty-strings", T{Values: []string{"s0", "s1", "s2"}})
	test(client, "1st-item-is-empty-string", T{Values: []string{"", "s1", "s2"}})
	test(client, "2nd-item-is-empty-string", T{Values: []string{"s0", "", "s2"}})

	// Output:
	// TEST empty-strings
	// want: main.T{Values:[]string{"", "", ""}}
	// got: main.T{Values:[]string(nil)}
	//
	// TEST non-empty-strings
	// want: main.T{Values:[]string{"s0", "s1", "s2"}}
	// got: main.T{Values:[]string{"s0", "s1", "s2"}}
	//
	// TEST 1st-item-is-empty-string
	// datastore.Put(1st-item-is-empty-string) datastore: unexpected property "Values" in elem 1 of slice
	//
	// TEST 2nd-item-is-empty-string
	// want: main.T{Values:[]string{"s0", "", "s2"}}
	// got: main.T{Values:[]string{"s0", "s2"}}
}

Expected behavior

The datastore put method should allow the mixing of empty and non-empty values in the array in any order.

Actual behavior

It does not allow any non-empty value if the first value is empty.

Additional context

Tested with version 1.0.0 and 1.9.0

P.S.

Not saving empty slice is expected behaviour of omitempty, but removing empty values from the slice is not. Perhaps it is an another issue

dmotylev avatar Nov 03 '22 13:11 dmotylev