|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608 |
- /*
- Copyright 2017 Google LLC
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
- package spanner
-
- import (
- "encoding/base64"
- "fmt"
- "math"
- "reflect"
- "strconv"
- "time"
-
- "cloud.google.com/go/civil"
- "cloud.google.com/go/internal/fields"
- proto "github.com/golang/protobuf/proto"
- proto3 "github.com/golang/protobuf/ptypes/struct"
- sppb "google.golang.org/genproto/googleapis/spanner/v1"
- "google.golang.org/grpc/codes"
- )
-
- const commitTimestampPlaceholderString = "spanner.commit_timestamp()"
-
- var (
- // CommitTimestamp is a special value used to tell Cloud Spanner
- // to insert the commit timestamp of the transaction into a column.
- // It can be used in a Mutation, or directly used in
- // InsertStruct or InsertMap. See ExampleCommitTimestamp.
- // This is just a placeholder and the actual value stored in this
- // variable has no meaning.
- CommitTimestamp time.Time = commitTimestamp
- commitTimestamp = time.Unix(0, 0).In(time.FixedZone("CommitTimestamp placeholder", 0xDB))
- )
-
- // NullInt64 represents a Cloud Spanner INT64 that may be NULL.
- type NullInt64 struct {
- Int64 int64
- Valid bool // Valid is true if Int64 is not NULL.
- }
-
- // String implements Stringer.String for NullInt64
- func (n NullInt64) String() string {
- if !n.Valid {
- return fmt.Sprintf("%v", "<null>")
- }
- return fmt.Sprintf("%v", n.Int64)
- }
-
- // NullString represents a Cloud Spanner STRING that may be NULL.
- type NullString struct {
- StringVal string
- Valid bool // Valid is true if StringVal is not NULL.
- }
-
- // String implements Stringer.String for NullString
- func (n NullString) String() string {
- if !n.Valid {
- return fmt.Sprintf("%v", "<null>")
- }
- return fmt.Sprintf("%q", n.StringVal)
- }
-
- // NullFloat64 represents a Cloud Spanner FLOAT64 that may be NULL.
- type NullFloat64 struct {
- Float64 float64
- Valid bool // Valid is true if Float64 is not NULL.
- }
-
- // Cloud Spanner STRUCT (aka STRUCT) values (https://cloud.google.com/spanner/docs/data-types#struct-type)
- // can be represented by a Go struct value.
- // The spanner.StructType of such values is built from the field types and field tag information
- // of the Go struct. If a field in the struct type definition has a "spanner:<field_name>" tag,
- // then the value of the "spanner" key in the tag is used as the name for that field in the
- // built spanner.StructType, otherwise the field name in the struct definition is used. To specify a
- // field with an empty field name in a Cloud Spanner STRUCT type, use the `spanner:""` tag
- // annotation against the corresponding field in the Go struct's type definition.
- //
- // A STRUCT value can contain STRUCT-typed and Array-of-STRUCT typed fields and these can be
- // specified using named struct-typed and []struct-typed fields inside a Go struct. However,
- // embedded struct fields are not allowed. Unexported struct fields are ignored.
- //
- // NULL STRUCT values in Cloud Spanner are typed. A nil pointer to a Go struct value can be used to
- // specify a NULL STRUCT value of the corresponding spanner.StructType. Nil and empty slices of a
- // Go STRUCT type can be used to specify NULL and empty array values respectively of the
- // corresponding spanner.StructType. A slice of pointers to a Go struct type can be used to specify
- // an array of NULL-able STRUCT values.
-
- // String implements Stringer.String for NullFloat64
- func (n NullFloat64) String() string {
- if !n.Valid {
- return fmt.Sprintf("%v", "<null>")
- }
- return fmt.Sprintf("%v", n.Float64)
- }
-
- // NullBool represents a Cloud Spanner BOOL that may be NULL.
- type NullBool struct {
- Bool bool
- Valid bool // Valid is true if Bool is not NULL.
- }
-
- // String implements Stringer.String for NullBool
- func (n NullBool) String() string {
- if !n.Valid {
- return fmt.Sprintf("%v", "<null>")
- }
- return fmt.Sprintf("%v", n.Bool)
- }
-
- // NullTime represents a Cloud Spanner TIMESTAMP that may be null.
- type NullTime struct {
- Time time.Time
- Valid bool // Valid is true if Time is not NULL.
- }
-
- // String implements Stringer.String for NullTime
- func (n NullTime) String() string {
- if !n.Valid {
- return fmt.Sprintf("%s", "<null>")
- }
- return fmt.Sprintf("%q", n.Time.Format(time.RFC3339Nano))
- }
-
- // NullDate represents a Cloud Spanner DATE that may be null.
- type NullDate struct {
- Date civil.Date
- Valid bool // Valid is true if Date is not NULL.
- }
-
- // String implements Stringer.String for NullDate
- func (n NullDate) String() string {
- if !n.Valid {
- return fmt.Sprintf("%s", "<null>")
- }
- return fmt.Sprintf("%q", n.Date)
- }
-
- // NullRow represents a Cloud Spanner STRUCT that may be NULL.
- // See also the document for Row.
- // Note that NullRow is not a valid Cloud Spanner column Type.
- type NullRow struct {
- Row Row
- Valid bool // Valid is true if Row is not NULL.
- }
-
- // GenericColumnValue represents the generic encoded value and type of the
- // column. See google.spanner.v1.ResultSet proto for details. This can be
- // useful for proxying query results when the result types are not known in
- // advance.
- //
- // If you populate a GenericColumnValue from a row using Row.Column or related
- // methods, do not modify the contents of Type and Value.
- type GenericColumnValue struct {
- Type *sppb.Type
- Value *proto3.Value
- }
-
- // Decode decodes a GenericColumnValue. The ptr argument should be a pointer
- // to a Go value that can accept v.
- func (v GenericColumnValue) Decode(ptr interface{}) error {
- return decodeValue(v.Value, v.Type, ptr)
- }
-
- // NewGenericColumnValue creates a GenericColumnValue from Go value that is
- // valid for Cloud Spanner.
- func newGenericColumnValue(v interface{}) (*GenericColumnValue, error) {
- value, typ, err := encodeValue(v)
- if err != nil {
- return nil, err
- }
- return &GenericColumnValue{Value: value, Type: typ}, nil
- }
-
- // errTypeMismatch returns error for destination not having a compatible type
- // with source Cloud Spanner type.
- func errTypeMismatch(srcCode, elCode sppb.TypeCode, dst interface{}) error {
- s := srcCode.String()
- if srcCode == sppb.TypeCode_ARRAY {
- s = fmt.Sprintf("%v[%v]", srcCode, elCode)
- }
- return spannerErrorf(codes.InvalidArgument, "type %T cannot be used for decoding %s", dst, s)
- }
-
- // errNilSpannerType returns error for nil Cloud Spanner type in decoding.
- func errNilSpannerType() error {
- return spannerErrorf(codes.FailedPrecondition, "unexpected nil Cloud Spanner data type in decoding")
- }
-
- // errNilSrc returns error for decoding from nil proto value.
- func errNilSrc() error {
- return spannerErrorf(codes.FailedPrecondition, "unexpected nil Cloud Spanner value in decoding")
- }
-
- // errNilDst returns error for decoding into nil interface{}.
- func errNilDst(dst interface{}) error {
- return spannerErrorf(codes.InvalidArgument, "cannot decode into nil type %T", dst)
- }
-
- // errNilArrElemType returns error for input Cloud Spanner data type being a array but without a
- // non-nil array element type.
- func errNilArrElemType(t *sppb.Type) error {
- return spannerErrorf(codes.FailedPrecondition, "array type %v is with nil array element type", t)
- }
-
- func errUnsupportedEmbeddedStructFields(fname string) error {
- return spannerErrorf(codes.InvalidArgument, "Embedded field: %s. Embedded and anonymous fields are not allowed "+
- "when converting Go structs to Cloud Spanner STRUCT values. To create a STRUCT value with an "+
- "unnamed field, use a `spanner:\"\"` field tag.", fname)
- }
-
- // errDstNotForNull returns error for decoding a SQL NULL value into a destination which doesn't
- // support NULL values.
- func errDstNotForNull(dst interface{}) error {
- return spannerErrorf(codes.InvalidArgument, "destination %T cannot support NULL SQL values", dst)
- }
-
- // errBadEncoding returns error for decoding wrongly encoded types.
- func errBadEncoding(v *proto3.Value, err error) error {
- return spannerErrorf(codes.FailedPrecondition, "%v wasn't correctly encoded: <%v>", v, err)
- }
-
- func parseNullTime(v *proto3.Value, p *NullTime, code sppb.TypeCode, isNull bool) error {
- if p == nil {
- return errNilDst(p)
- }
- if code != sppb.TypeCode_TIMESTAMP {
- return errTypeMismatch(code, sppb.TypeCode_TYPE_CODE_UNSPECIFIED, p)
- }
- if isNull {
- *p = NullTime{}
- return nil
- }
- x, err := getStringValue(v)
- if err != nil {
- return err
- }
- y, err := time.Parse(time.RFC3339Nano, x)
- if err != nil {
- return errBadEncoding(v, err)
- }
- p.Valid = true
- p.Time = y
- return nil
- }
-
- // decodeValue decodes a protobuf Value into a pointer to a Go value, as
- // specified by sppb.Type.
- func decodeValue(v *proto3.Value, t *sppb.Type, ptr interface{}) error {
- if v == nil {
- return errNilSrc()
- }
- if t == nil {
- return errNilSpannerType()
- }
- code := t.Code
- acode := sppb.TypeCode_TYPE_CODE_UNSPECIFIED
- if code == sppb.TypeCode_ARRAY {
- if t.ArrayElementType == nil {
- return errNilArrElemType(t)
- }
- acode = t.ArrayElementType.Code
- }
- _, isNull := v.Kind.(*proto3.Value_NullValue)
-
- // Do the decoding based on the type of ptr.
- switch p := ptr.(type) {
- case nil:
- return errNilDst(nil)
- case *string:
- if p == nil {
- return errNilDst(p)
- }
- if code != sppb.TypeCode_STRING {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- return errDstNotForNull(ptr)
- }
- x, err := getStringValue(v)
- if err != nil {
- return err
- }
- *p = x
- case *NullString:
- if p == nil {
- return errNilDst(p)
- }
- if code != sppb.TypeCode_STRING {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = NullString{}
- break
- }
- x, err := getStringValue(v)
- if err != nil {
- return err
- }
- p.Valid = true
- p.StringVal = x
- case *[]NullString:
- if p == nil {
- return errNilDst(p)
- }
- if acode != sppb.TypeCode_STRING {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = nil
- break
- }
- x, err := getListValue(v)
- if err != nil {
- return err
- }
- y, err := decodeNullStringArray(x)
- if err != nil {
- return err
- }
- *p = y
- case *[]string:
- if p == nil {
- return errNilDst(p)
- }
- if acode != sppb.TypeCode_STRING {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = nil
- break
- }
- x, err := getListValue(v)
- if err != nil {
- return err
- }
- y, err := decodeStringArray(x)
- if err != nil {
- return err
- }
- *p = y
- case *[]byte:
- if p == nil {
- return errNilDst(p)
- }
- if code != sppb.TypeCode_BYTES {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = nil
- break
- }
- x, err := getStringValue(v)
- if err != nil {
- return err
- }
- y, err := base64.StdEncoding.DecodeString(x)
- if err != nil {
- return errBadEncoding(v, err)
- }
- *p = y
- case *[][]byte:
- if p == nil {
- return errNilDst(p)
- }
- if acode != sppb.TypeCode_BYTES {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = nil
- break
- }
- x, err := getListValue(v)
- if err != nil {
- return err
- }
- y, err := decodeByteArray(x)
- if err != nil {
- return err
- }
- *p = y
- case *int64:
- if p == nil {
- return errNilDst(p)
- }
- if code != sppb.TypeCode_INT64 {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- return errDstNotForNull(ptr)
- }
- x, err := getStringValue(v)
- if err != nil {
- return err
- }
- y, err := strconv.ParseInt(x, 10, 64)
- if err != nil {
- return errBadEncoding(v, err)
- }
- *p = y
- case *NullInt64:
- if p == nil {
- return errNilDst(p)
- }
- if code != sppb.TypeCode_INT64 {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = NullInt64{}
- break
- }
- x, err := getStringValue(v)
- if err != nil {
- return err
- }
- y, err := strconv.ParseInt(x, 10, 64)
- if err != nil {
- return errBadEncoding(v, err)
- }
- p.Valid = true
- p.Int64 = y
- case *[]NullInt64:
- if p == nil {
- return errNilDst(p)
- }
- if acode != sppb.TypeCode_INT64 {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = nil
- break
- }
- x, err := getListValue(v)
- if err != nil {
- return err
- }
- y, err := decodeNullInt64Array(x)
- if err != nil {
- return err
- }
- *p = y
- case *[]int64:
- if p == nil {
- return errNilDst(p)
- }
- if acode != sppb.TypeCode_INT64 {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = nil
- break
- }
- x, err := getListValue(v)
- if err != nil {
- return err
- }
- y, err := decodeInt64Array(x)
- if err != nil {
- return err
- }
- *p = y
- case *bool:
- if p == nil {
- return errNilDst(p)
- }
- if code != sppb.TypeCode_BOOL {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- return errDstNotForNull(ptr)
- }
- x, err := getBoolValue(v)
- if err != nil {
- return err
- }
- *p = x
- case *NullBool:
- if p == nil {
- return errNilDst(p)
- }
- if code != sppb.TypeCode_BOOL {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = NullBool{}
- break
- }
- x, err := getBoolValue(v)
- if err != nil {
- return err
- }
- p.Valid = true
- p.Bool = x
- case *[]NullBool:
- if p == nil {
- return errNilDst(p)
- }
- if acode != sppb.TypeCode_BOOL {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = nil
- break
- }
- x, err := getListValue(v)
- if err != nil {
- return err
- }
- y, err := decodeNullBoolArray(x)
- if err != nil {
- return err
- }
- *p = y
- case *[]bool:
- if p == nil {
- return errNilDst(p)
- }
- if acode != sppb.TypeCode_BOOL {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = nil
- break
- }
- x, err := getListValue(v)
- if err != nil {
- return err
- }
- y, err := decodeBoolArray(x)
- if err != nil {
- return err
- }
- *p = y
- case *float64:
- if p == nil {
- return errNilDst(p)
- }
- if code != sppb.TypeCode_FLOAT64 {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- return errDstNotForNull(ptr)
- }
- x, err := getFloat64Value(v)
- if err != nil {
- return err
- }
- *p = x
- case *NullFloat64:
- if p == nil {
- return errNilDst(p)
- }
- if code != sppb.TypeCode_FLOAT64 {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = NullFloat64{}
- break
- }
- x, err := getFloat64Value(v)
- if err != nil {
- return err
- }
- p.Valid = true
- p.Float64 = x
- case *[]NullFloat64:
- if p == nil {
- return errNilDst(p)
- }
- if acode != sppb.TypeCode_FLOAT64 {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = nil
- break
- }
- x, err := getListValue(v)
- if err != nil {
- return err
- }
- y, err := decodeNullFloat64Array(x)
- if err != nil {
- return err
- }
- *p = y
- case *[]float64:
- if p == nil {
- return errNilDst(p)
- }
- if acode != sppb.TypeCode_FLOAT64 {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = nil
- break
- }
- x, err := getListValue(v)
- if err != nil {
- return err
- }
- y, err := decodeFloat64Array(x)
- if err != nil {
- return err
- }
- *p = y
- case *time.Time:
- var nt NullTime
- if isNull {
- return errDstNotForNull(ptr)
- }
- err := parseNullTime(v, &nt, code, isNull)
- if err != nil {
- return nil
- }
- *p = nt.Time
- case *NullTime:
- err := parseNullTime(v, p, code, isNull)
- if err != nil {
- return err
- }
- case *[]NullTime:
- if p == nil {
- return errNilDst(p)
- }
- if acode != sppb.TypeCode_TIMESTAMP {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = nil
- break
- }
- x, err := getListValue(v)
- if err != nil {
- return err
- }
- y, err := decodeNullTimeArray(x)
- if err != nil {
- return err
- }
- *p = y
- case *[]time.Time:
- if p == nil {
- return errNilDst(p)
- }
- if acode != sppb.TypeCode_TIMESTAMP {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = nil
- break
- }
- x, err := getListValue(v)
- if err != nil {
- return err
- }
- y, err := decodeTimeArray(x)
- if err != nil {
- return err
- }
- *p = y
- case *civil.Date:
- if p == nil {
- return errNilDst(p)
- }
- if code != sppb.TypeCode_DATE {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- return errDstNotForNull(ptr)
- }
- x, err := getStringValue(v)
- if err != nil {
- return err
- }
- y, err := civil.ParseDate(x)
- if err != nil {
- return errBadEncoding(v, err)
- }
- *p = y
- case *NullDate:
- if p == nil {
- return errNilDst(p)
- }
- if code != sppb.TypeCode_DATE {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = NullDate{}
- break
- }
- x, err := getStringValue(v)
- if err != nil {
- return err
- }
- y, err := civil.ParseDate(x)
- if err != nil {
- return errBadEncoding(v, err)
- }
- p.Valid = true
- p.Date = y
- case *[]NullDate:
- if p == nil {
- return errNilDst(p)
- }
- if acode != sppb.TypeCode_DATE {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = nil
- break
- }
- x, err := getListValue(v)
- if err != nil {
- return err
- }
- y, err := decodeNullDateArray(x)
- if err != nil {
- return err
- }
- *p = y
- case *[]civil.Date:
- if p == nil {
- return errNilDst(p)
- }
- if acode != sppb.TypeCode_DATE {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = nil
- break
- }
- x, err := getListValue(v)
- if err != nil {
- return err
- }
- y, err := decodeDateArray(x)
- if err != nil {
- return err
- }
- *p = y
- case *[]NullRow:
- if p == nil {
- return errNilDst(p)
- }
- if acode != sppb.TypeCode_STRUCT {
- return errTypeMismatch(code, acode, ptr)
- }
- if isNull {
- *p = nil
- break
- }
- x, err := getListValue(v)
- if err != nil {
- return err
- }
- y, err := decodeRowArray(t.ArrayElementType.StructType, x)
- if err != nil {
- return err
- }
- *p = y
- case *GenericColumnValue:
- *p = GenericColumnValue{Type: t, Value: v}
- default:
- // Check if the proto encoding is for an array of structs.
- if !(code == sppb.TypeCode_ARRAY && acode == sppb.TypeCode_STRUCT) {
- return errTypeMismatch(code, acode, ptr)
- }
- vp := reflect.ValueOf(p)
- if !vp.IsValid() {
- return errNilDst(p)
- }
- if !isPtrStructPtrSlice(vp.Type()) {
- // The container is not a pointer to a struct pointer slice.
- return errTypeMismatch(code, acode, ptr)
- }
- // Only use reflection for nil detection on slow path.
- // Also, IsNil panics on many types, so check it after the type check.
- if vp.IsNil() {
- return errNilDst(p)
- }
- if isNull {
- // The proto Value is encoding NULL, set the pointer to struct
- // slice to nil as well.
- vp.Elem().Set(reflect.Zero(vp.Elem().Type()))
- break
- }
- x, err := getListValue(v)
- if err != nil {
- return err
- }
- if err = decodeStructArray(t.ArrayElementType.StructType, x, p); err != nil {
- return err
- }
- }
- return nil
- }
-
- // errSrvVal returns an error for getting a wrong source protobuf value in decoding.
- func errSrcVal(v *proto3.Value, want string) error {
- return spannerErrorf(codes.FailedPrecondition, "cannot use %v(Kind: %T) as %s Value",
- v, v.GetKind(), want)
- }
-
- // getStringValue returns the string value encoded in proto3.Value v whose
- // kind is proto3.Value_StringValue.
- func getStringValue(v *proto3.Value) (string, error) {
- if x, ok := v.GetKind().(*proto3.Value_StringValue); ok && x != nil {
- return x.StringValue, nil
- }
- return "", errSrcVal(v, "String")
- }
-
- // getBoolValue returns the bool value encoded in proto3.Value v whose
- // kind is proto3.Value_BoolValue.
- func getBoolValue(v *proto3.Value) (bool, error) {
- if x, ok := v.GetKind().(*proto3.Value_BoolValue); ok && x != nil {
- return x.BoolValue, nil
- }
- return false, errSrcVal(v, "Bool")
- }
-
- // getListValue returns the proto3.ListValue contained in proto3.Value v whose
- // kind is proto3.Value_ListValue.
- func getListValue(v *proto3.Value) (*proto3.ListValue, error) {
- if x, ok := v.GetKind().(*proto3.Value_ListValue); ok && x != nil {
- return x.ListValue, nil
- }
- return nil, errSrcVal(v, "List")
- }
-
- // errUnexpectedNumStr returns error for decoder getting a unexpected string for
- // representing special float values.
- func errUnexpectedNumStr(s string) error {
- return spannerErrorf(codes.FailedPrecondition, "unexpected string value %q for number", s)
- }
-
- // getFloat64Value returns the float64 value encoded in proto3.Value v whose
- // kind is proto3.Value_NumberValue / proto3.Value_StringValue.
- // Cloud Spanner uses string to encode NaN, Infinity and -Infinity.
- func getFloat64Value(v *proto3.Value) (float64, error) {
- switch x := v.GetKind().(type) {
- case *proto3.Value_NumberValue:
- if x == nil {
- break
- }
- return x.NumberValue, nil
- case *proto3.Value_StringValue:
- if x == nil {
- break
- }
- switch x.StringValue {
- case "NaN":
- return math.NaN(), nil
- case "Infinity":
- return math.Inf(1), nil
- case "-Infinity":
- return math.Inf(-1), nil
- default:
- return 0, errUnexpectedNumStr(x.StringValue)
- }
- }
- return 0, errSrcVal(v, "Number")
- }
-
- // errNilListValue returns error for unexpected nil ListValue in decoding Cloud Spanner ARRAYs.
- func errNilListValue(sqlType string) error {
- return spannerErrorf(codes.FailedPrecondition, "unexpected nil ListValue in decoding %v array", sqlType)
- }
-
- // errDecodeArrayElement returns error for failure in decoding single array element.
- func errDecodeArrayElement(i int, v proto.Message, sqlType string, err error) error {
- se, ok := toSpannerError(err).(*Error)
- if !ok {
- return spannerErrorf(codes.Unknown,
- "cannot decode %v(array element %v) as %v, error = <%v>", v, i, sqlType, err)
- }
- se.decorate(fmt.Sprintf("cannot decode %v(array element %v) as %v", v, i, sqlType))
- return se
- }
-
- // decodeNullStringArray decodes proto3.ListValue pb into a NullString slice.
- func decodeNullStringArray(pb *proto3.ListValue) ([]NullString, error) {
- if pb == nil {
- return nil, errNilListValue("STRING")
- }
- a := make([]NullString, len(pb.Values))
- for i, v := range pb.Values {
- if err := decodeValue(v, stringType(), &a[i]); err != nil {
- return nil, errDecodeArrayElement(i, v, "STRING", err)
- }
- }
- return a, nil
- }
-
- // decodeStringArray decodes proto3.ListValue pb into a string slice.
- func decodeStringArray(pb *proto3.ListValue) ([]string, error) {
- if pb == nil {
- return nil, errNilListValue("STRING")
- }
- a := make([]string, len(pb.Values))
- st := stringType()
- for i, v := range pb.Values {
- if err := decodeValue(v, st, &a[i]); err != nil {
- return nil, errDecodeArrayElement(i, v, "STRING", err)
- }
- }
- return a, nil
- }
-
- // decodeNullInt64Array decodes proto3.ListValue pb into a NullInt64 slice.
- func decodeNullInt64Array(pb *proto3.ListValue) ([]NullInt64, error) {
- if pb == nil {
- return nil, errNilListValue("INT64")
- }
- a := make([]NullInt64, len(pb.Values))
- for i, v := range pb.Values {
- if err := decodeValue(v, intType(), &a[i]); err != nil {
- return nil, errDecodeArrayElement(i, v, "INT64", err)
- }
- }
- return a, nil
- }
-
- // decodeInt64Array decodes proto3.ListValue pb into a int64 slice.
- func decodeInt64Array(pb *proto3.ListValue) ([]int64, error) {
- if pb == nil {
- return nil, errNilListValue("INT64")
- }
- a := make([]int64, len(pb.Values))
- for i, v := range pb.Values {
- if err := decodeValue(v, intType(), &a[i]); err != nil {
- return nil, errDecodeArrayElement(i, v, "INT64", err)
- }
- }
- return a, nil
- }
-
- // decodeNullBoolArray decodes proto3.ListValue pb into a NullBool slice.
- func decodeNullBoolArray(pb *proto3.ListValue) ([]NullBool, error) {
- if pb == nil {
- return nil, errNilListValue("BOOL")
- }
- a := make([]NullBool, len(pb.Values))
- for i, v := range pb.Values {
- if err := decodeValue(v, boolType(), &a[i]); err != nil {
- return nil, errDecodeArrayElement(i, v, "BOOL", err)
- }
- }
- return a, nil
- }
-
- // decodeBoolArray decodes proto3.ListValue pb into a bool slice.
- func decodeBoolArray(pb *proto3.ListValue) ([]bool, error) {
- if pb == nil {
- return nil, errNilListValue("BOOL")
- }
- a := make([]bool, len(pb.Values))
- for i, v := range pb.Values {
- if err := decodeValue(v, boolType(), &a[i]); err != nil {
- return nil, errDecodeArrayElement(i, v, "BOOL", err)
- }
- }
- return a, nil
- }
-
- // decodeNullFloat64Array decodes proto3.ListValue pb into a NullFloat64 slice.
- func decodeNullFloat64Array(pb *proto3.ListValue) ([]NullFloat64, error) {
- if pb == nil {
- return nil, errNilListValue("FLOAT64")
- }
- a := make([]NullFloat64, len(pb.Values))
- for i, v := range pb.Values {
- if err := decodeValue(v, floatType(), &a[i]); err != nil {
- return nil, errDecodeArrayElement(i, v, "FLOAT64", err)
- }
- }
- return a, nil
- }
-
- // decodeFloat64Array decodes proto3.ListValue pb into a float64 slice.
- func decodeFloat64Array(pb *proto3.ListValue) ([]float64, error) {
- if pb == nil {
- return nil, errNilListValue("FLOAT64")
- }
- a := make([]float64, len(pb.Values))
- for i, v := range pb.Values {
- if err := decodeValue(v, floatType(), &a[i]); err != nil {
- return nil, errDecodeArrayElement(i, v, "FLOAT64", err)
- }
- }
- return a, nil
- }
-
- // decodeByteArray decodes proto3.ListValue pb into a slice of byte slice.
- func decodeByteArray(pb *proto3.ListValue) ([][]byte, error) {
- if pb == nil {
- return nil, errNilListValue("BYTES")
- }
- a := make([][]byte, len(pb.Values))
- for i, v := range pb.Values {
- if err := decodeValue(v, bytesType(), &a[i]); err != nil {
- return nil, errDecodeArrayElement(i, v, "BYTES", err)
- }
- }
- return a, nil
- }
-
- // decodeNullTimeArray decodes proto3.ListValue pb into a NullTime slice.
- func decodeNullTimeArray(pb *proto3.ListValue) ([]NullTime, error) {
- if pb == nil {
- return nil, errNilListValue("TIMESTAMP")
- }
- a := make([]NullTime, len(pb.Values))
- for i, v := range pb.Values {
- if err := decodeValue(v, timeType(), &a[i]); err != nil {
- return nil, errDecodeArrayElement(i, v, "TIMESTAMP", err)
- }
- }
- return a, nil
- }
-
- // decodeTimeArray decodes proto3.ListValue pb into a time.Time slice.
- func decodeTimeArray(pb *proto3.ListValue) ([]time.Time, error) {
- if pb == nil {
- return nil, errNilListValue("TIMESTAMP")
- }
- a := make([]time.Time, len(pb.Values))
- for i, v := range pb.Values {
- if err := decodeValue(v, timeType(), &a[i]); err != nil {
- return nil, errDecodeArrayElement(i, v, "TIMESTAMP", err)
- }
- }
- return a, nil
- }
-
- // decodeNullDateArray decodes proto3.ListValue pb into a NullDate slice.
- func decodeNullDateArray(pb *proto3.ListValue) ([]NullDate, error) {
- if pb == nil {
- return nil, errNilListValue("DATE")
- }
- a := make([]NullDate, len(pb.Values))
- for i, v := range pb.Values {
- if err := decodeValue(v, dateType(), &a[i]); err != nil {
- return nil, errDecodeArrayElement(i, v, "DATE", err)
- }
- }
- return a, nil
- }
-
- // decodeDateArray decodes proto3.ListValue pb into a civil.Date slice.
- func decodeDateArray(pb *proto3.ListValue) ([]civil.Date, error) {
- if pb == nil {
- return nil, errNilListValue("DATE")
- }
- a := make([]civil.Date, len(pb.Values))
- for i, v := range pb.Values {
- if err := decodeValue(v, dateType(), &a[i]); err != nil {
- return nil, errDecodeArrayElement(i, v, "DATE", err)
- }
- }
- return a, nil
- }
-
- func errNotStructElement(i int, v *proto3.Value) error {
- return errDecodeArrayElement(i, v, "STRUCT",
- spannerErrorf(codes.FailedPrecondition, "%v(type: %T) doesn't encode Cloud Spanner STRUCT", v, v))
- }
-
- // decodeRowArray decodes proto3.ListValue pb into a NullRow slice according to
- // the structural information given in sppb.StructType ty.
- func decodeRowArray(ty *sppb.StructType, pb *proto3.ListValue) ([]NullRow, error) {
- if pb == nil {
- return nil, errNilListValue("STRUCT")
- }
- a := make([]NullRow, len(pb.Values))
- for i := range pb.Values {
- switch v := pb.Values[i].GetKind().(type) {
- case *proto3.Value_ListValue:
- a[i] = NullRow{
- Row: Row{
- fields: ty.Fields,
- vals: v.ListValue.Values,
- },
- Valid: true,
- }
- // Null elements not currently supported by the server, see
- // https://cloud.google.com/spanner/docs/query-syntax#using-structs-with-select
- case *proto3.Value_NullValue:
- // no-op, a[i] is NullRow{} already
- default:
- return nil, errNotStructElement(i, pb.Values[i])
- }
- }
- return a, nil
- }
-
- // errNilSpannerStructType returns error for unexpected nil Cloud Spanner STRUCT schema type in decoding.
- func errNilSpannerStructType() error {
- return spannerErrorf(codes.FailedPrecondition, "unexpected nil StructType in decoding Cloud Spanner STRUCT")
- }
-
- // errUnnamedField returns error for decoding a Cloud Spanner STRUCT with unnamed field into a Go struct.
- func errUnnamedField(ty *sppb.StructType, i int) error {
- return spannerErrorf(codes.InvalidArgument, "unnamed field %v in Cloud Spanner STRUCT %+v", i, ty)
- }
-
- // errNoOrDupGoField returns error for decoding a Cloud Spanner
- // STRUCT into a Go struct which is either missing a field, or has duplicate fields.
- func errNoOrDupGoField(s interface{}, f string) error {
- return spannerErrorf(codes.InvalidArgument, "Go struct %+v(type %T) has no or duplicate fields for Cloud Spanner STRUCT field %v", s, s, f)
- }
-
- // errDupColNames returns error for duplicated Cloud Spanner STRUCT field names found in decoding a Cloud Spanner STRUCT into a Go struct.
- func errDupSpannerField(f string, ty *sppb.StructType) error {
- return spannerErrorf(codes.InvalidArgument, "duplicated field name %q in Cloud Spanner STRUCT %+v", f, ty)
- }
-
- // errDecodeStructField returns error for failure in decoding a single field of a Cloud Spanner STRUCT.
- func errDecodeStructField(ty *sppb.StructType, f string, err error) error {
- se, ok := toSpannerError(err).(*Error)
- if !ok {
- return spannerErrorf(codes.Unknown,
- "cannot decode field %v of Cloud Spanner STRUCT %+v, error = <%v>", f, ty, err)
- }
- se.decorate(fmt.Sprintf("cannot decode field %v of Cloud Spanner STRUCT %+v", f, ty))
- return se
- }
-
- // decodeStruct decodes proto3.ListValue pb into struct referenced by pointer ptr, according to
- // the structural information given in sppb.StructType ty.
- func decodeStruct(ty *sppb.StructType, pb *proto3.ListValue, ptr interface{}) error {
- if reflect.ValueOf(ptr).IsNil() {
- return errNilDst(ptr)
- }
- if ty == nil {
- return errNilSpannerStructType()
- }
- // t holds the structural information of ptr.
- t := reflect.TypeOf(ptr).Elem()
- // v is the actual value that ptr points to.
- v := reflect.ValueOf(ptr).Elem()
-
- fields, err := fieldCache.Fields(t)
- if err != nil {
- return toSpannerError(err)
- }
- seen := map[string]bool{}
- for i, f := range ty.Fields {
- if f.Name == "" {
- return errUnnamedField(ty, i)
- }
- sf := fields.Match(f.Name)
- if sf == nil {
- return errNoOrDupGoField(ptr, f.Name)
- }
- if seen[f.Name] {
- // We don't allow duplicated field name.
- return errDupSpannerField(f.Name, ty)
- }
- // Try to decode a single field.
- if err := decodeValue(pb.Values[i], f.Type, v.FieldByIndex(sf.Index).Addr().Interface()); err != nil {
- return errDecodeStructField(ty, f.Name, err)
- }
- // Mark field f.Name as processed.
- seen[f.Name] = true
- }
- return nil
- }
-
- // isPtrStructPtrSlice returns true if ptr is a pointer to a slice of struct pointers.
- func isPtrStructPtrSlice(t reflect.Type) bool {
- if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Slice {
- // t is not a pointer to a slice.
- return false
- }
- if t = t.Elem(); t.Elem().Kind() != reflect.Ptr || t.Elem().Elem().Kind() != reflect.Struct {
- // the slice that t points to is not a slice of struct pointers.
- return false
- }
- return true
- }
-
- // decodeStructArray decodes proto3.ListValue pb into struct slice referenced by pointer ptr, according to the
- // structural information given in a sppb.StructType.
- func decodeStructArray(ty *sppb.StructType, pb *proto3.ListValue, ptr interface{}) error {
- if pb == nil {
- return errNilListValue("STRUCT")
- }
- // Type of the struct pointers stored in the slice that ptr points to.
- ts := reflect.TypeOf(ptr).Elem().Elem()
- // The slice that ptr points to, might be nil at this point.
- v := reflect.ValueOf(ptr).Elem()
- // Allocate empty slice.
- v.Set(reflect.MakeSlice(v.Type(), 0, len(pb.Values)))
- // Decode every struct in pb.Values.
- for i, pv := range pb.Values {
- // Check if pv is a NULL value.
- if _, isNull := pv.Kind.(*proto3.Value_NullValue); isNull {
- // Append a nil pointer to the slice.
- v.Set(reflect.Append(v, reflect.New(ts).Elem()))
- continue
- }
- // Allocate empty struct.
- s := reflect.New(ts.Elem())
- // Get proto3.ListValue l from proto3.Value pv.
- l, err := getListValue(pv)
- if err != nil {
- return errDecodeArrayElement(i, pv, "STRUCT", err)
- }
- // Decode proto3.ListValue l into struct referenced by s.Interface().
- if err = decodeStruct(ty, l, s.Interface()); err != nil {
- return errDecodeArrayElement(i, pv, "STRUCT", err)
- }
- // Append the decoded struct back into the slice.
- v.Set(reflect.Append(v, s))
- }
- return nil
- }
-
- // errEncoderUnsupportedType returns error for not being able to encode a value of
- // certain type.
- func errEncoderUnsupportedType(v interface{}) error {
- return spannerErrorf(codes.InvalidArgument, "client doesn't support type %T", v)
- }
-
- // encodeValue encodes a Go native type into a proto3.Value.
- func encodeValue(v interface{}) (*proto3.Value, *sppb.Type, error) {
- pb := &proto3.Value{
- Kind: &proto3.Value_NullValue{NullValue: proto3.NullValue_NULL_VALUE},
- }
- var pt *sppb.Type
- var err error
- switch v := v.(type) {
- case nil:
- case string:
- pb.Kind = stringKind(v)
- pt = stringType()
- case NullString:
- if v.Valid {
- return encodeValue(v.StringVal)
- }
- pt = stringType()
- case []string:
- if v != nil {
- pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] })
- if err != nil {
- return nil, nil, err
- }
- }
- pt = listType(stringType())
- case []NullString:
- if v != nil {
- pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] })
- if err != nil {
- return nil, nil, err
- }
- }
- pt = listType(stringType())
- case []byte:
- if v != nil {
- pb.Kind = stringKind(base64.StdEncoding.EncodeToString(v))
- }
- pt = bytesType()
- case [][]byte:
- if v != nil {
- pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] })
- if err != nil {
- return nil, nil, err
- }
- }
- pt = listType(bytesType())
- case int:
- pb.Kind = stringKind(strconv.FormatInt(int64(v), 10))
- pt = intType()
- case []int:
- if v != nil {
- pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] })
- if err != nil {
- return nil, nil, err
- }
- }
- pt = listType(intType())
- case int64:
- pb.Kind = stringKind(strconv.FormatInt(v, 10))
- pt = intType()
- case []int64:
- if v != nil {
- pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] })
- if err != nil {
- return nil, nil, err
- }
- }
- pt = listType(intType())
- case NullInt64:
- if v.Valid {
- return encodeValue(v.Int64)
- }
- pt = intType()
- case []NullInt64:
- if v != nil {
- pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] })
- if err != nil {
- return nil, nil, err
- }
- }
- pt = listType(intType())
- case bool:
- pb.Kind = &proto3.Value_BoolValue{BoolValue: v}
- pt = boolType()
- case []bool:
- if v != nil {
- pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] })
- if err != nil {
- return nil, nil, err
- }
- }
- pt = listType(boolType())
- case NullBool:
- if v.Valid {
- return encodeValue(v.Bool)
- }
- pt = boolType()
- case []NullBool:
- if v != nil {
- pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] })
- if err != nil {
- return nil, nil, err
- }
- }
- pt = listType(boolType())
- case float64:
- pb.Kind = &proto3.Value_NumberValue{NumberValue: v}
- pt = floatType()
- case []float64:
- if v != nil {
- pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] })
- if err != nil {
- return nil, nil, err
- }
- }
- pt = listType(floatType())
- case NullFloat64:
- if v.Valid {
- return encodeValue(v.Float64)
- }
- pt = floatType()
- case []NullFloat64:
- if v != nil {
- pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] })
- if err != nil {
- return nil, nil, err
- }
- }
- pt = listType(floatType())
- case time.Time:
- if v == commitTimestamp {
- pb.Kind = stringKind(commitTimestampPlaceholderString)
- } else {
- pb.Kind = stringKind(v.UTC().Format(time.RFC3339Nano))
- }
- pt = timeType()
- case []time.Time:
- if v != nil {
- pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] })
- if err != nil {
- return nil, nil, err
- }
- }
- pt = listType(timeType())
- case NullTime:
- if v.Valid {
- return encodeValue(v.Time)
- }
- pt = timeType()
- case []NullTime:
- if v != nil {
- pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] })
- if err != nil {
- return nil, nil, err
- }
- }
- pt = listType(timeType())
- case civil.Date:
- pb.Kind = stringKind(v.String())
- pt = dateType()
- case []civil.Date:
- if v != nil {
- pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] })
- if err != nil {
- return nil, nil, err
- }
- }
- pt = listType(dateType())
- case NullDate:
- if v.Valid {
- return encodeValue(v.Date)
- }
- pt = dateType()
- case []NullDate:
- if v != nil {
- pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] })
- if err != nil {
- return nil, nil, err
- }
- }
- pt = listType(dateType())
- case GenericColumnValue:
- // Deep clone to ensure subsequent changes to v before
- // transmission don't affect our encoded value.
- pb = proto.Clone(v.Value).(*proto3.Value)
- pt = proto.Clone(v.Type).(*sppb.Type)
- case []GenericColumnValue:
- return nil, nil, errEncoderUnsupportedType(v)
- default:
- if !isStructOrArrayOfStructValue(v) {
- return nil, nil, errEncoderUnsupportedType(v)
- }
- typ := reflect.TypeOf(v)
-
- // Value is a Go struct value/ptr.
- if (typ.Kind() == reflect.Struct) ||
- (typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct) {
- return encodeStruct(v)
- }
-
- // Value is a slice of Go struct values/ptrs.
- if typ.Kind() == reflect.Slice {
- return encodeStructArray(v)
- }
- }
- return pb, pt, nil
- }
-
- // Encodes a Go struct value/ptr in v to the spanner Value and Type protos. v itself must
- // be non-nil.
- func encodeStruct(v interface{}) (*proto3.Value, *sppb.Type, error) {
- typ := reflect.TypeOf(v)
- val := reflect.ValueOf(v)
-
- // Pointer to struct.
- if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct {
- typ = typ.Elem()
- if val.IsNil() {
- // nil pointer to struct, representing a NULL STRUCT value. Use a dummy value to
- // get the type.
- _, st, err := encodeStruct(reflect.Zero(typ).Interface())
- if err != nil {
- return nil, nil, err
- }
- return nullProto(), st, nil
- }
- val = val.Elem()
- }
-
- if typ.Kind() != reflect.Struct {
- return nil, nil, errEncoderUnsupportedType(v)
- }
-
- stf := make([]*sppb.StructType_Field, 0, typ.NumField())
- stv := make([]*proto3.Value, 0, typ.NumField())
-
- for i := 0; i < typ.NumField(); i++ {
- // If the field has a 'spanner' tag, use the value of that tag as the field name.
- // This is used to build STRUCT types with unnamed/duplicate fields.
- sf := typ.Field(i)
- fval := val.Field(i)
-
- // Embedded fields are not allowed.
- if sf.Anonymous {
- return nil, nil, errUnsupportedEmbeddedStructFields(sf.Name)
- }
-
- // Unexported fields are ignored.
- if !fval.CanInterface() {
- continue
- }
-
- fname, ok := structTagLookup(sf.Tag, "spanner")
- if !ok {
- fname = sf.Name
- }
-
- eval, etype, err := encodeValue(fval.Interface())
- if err != nil {
- return nil, nil, err
- }
-
- stf = append(stf, mkField(fname, etype))
- stv = append(stv, eval)
- }
-
- return listProto(stv...), structType(stf...), nil
- }
-
- // Encodes a slice of Go struct values/ptrs in v to the spanner Value and Type protos. v itself
- // must be non-nil.
- func encodeStructArray(v interface{}) (*proto3.Value, *sppb.Type, error) {
- etyp := reflect.TypeOf(v).Elem()
- sliceval := reflect.ValueOf(v)
-
- // Slice of pointers to structs.
- if etyp.Kind() == reflect.Ptr {
- etyp = etyp.Elem()
- }
-
- // Use a dummy struct value to get the element type
- _, elemTyp, err := encodeStruct(reflect.Zero(etyp).Interface())
- if err != nil {
- return nil, nil, err
- }
-
- // nil slice represents a NULL array-of-struct.
- if sliceval.IsNil() {
- return nullProto(), listType(elemTyp), nil
- }
-
- values := make([]*proto3.Value, 0, sliceval.Len())
-
- for i := 0; i < sliceval.Len(); i++ {
- ev, _, err := encodeStruct(sliceval.Index(i).Interface())
- if err != nil {
- return nil, nil, err
- }
- values = append(values, ev)
- }
- return listProto(values...), listType(elemTyp), nil
- }
-
- func isStructOrArrayOfStructValue(v interface{}) bool {
- typ := reflect.TypeOf(v)
- if typ.Kind() == reflect.Slice {
- typ = typ.Elem()
- }
- if typ.Kind() == reflect.Ptr {
- typ = typ.Elem()
- }
- return typ.Kind() == reflect.Struct
- }
-
- func isSupportedMutationType(v interface{}) bool {
- switch v.(type) {
- case string, NullString, []string, []NullString,
- []byte, [][]byte,
- int, []int, int64, []int64, NullInt64, []NullInt64,
- bool, []bool, NullBool, []NullBool,
- float64, []float64, NullFloat64, []NullFloat64,
- time.Time, []time.Time, NullTime, []NullTime,
- civil.Date, []civil.Date, NullDate, []NullDate,
- GenericColumnValue:
- return true
- default:
- return false
- }
- }
-
- // encodeValueArray encodes a Value array into a proto3.ListValue.
- func encodeValueArray(vs []interface{}) (*proto3.ListValue, error) {
- lv := &proto3.ListValue{}
- lv.Values = make([]*proto3.Value, 0, len(vs))
- for _, v := range vs {
- if !isSupportedMutationType(v) {
- return nil, errEncoderUnsupportedType(v)
- }
- pb, _, err := encodeValue(v)
- if err != nil {
- return nil, err
- }
- lv.Values = append(lv.Values, pb)
- }
- return lv, nil
- }
-
- // encodeArray assumes that all values of the array element type encode without error.
- func encodeArray(len int, at func(int) interface{}) (*proto3.Value, error) {
- vs := make([]*proto3.Value, len)
- var err error
- for i := 0; i < len; i++ {
- vs[i], _, err = encodeValue(at(i))
- if err != nil {
- return nil, err
- }
- }
- return listProto(vs...), nil
- }
-
- func spannerTagParser(t reflect.StructTag) (name string, keep bool, other interface{}, err error) {
- if s := t.Get("spanner"); s != "" {
- if s == "-" {
- return "", false, nil, nil
- }
- return s, true, nil, nil
- }
- return "", true, nil, nil
- }
-
- var fieldCache = fields.NewCache(spannerTagParser, nil, nil)
|