1/* 2Copyright 2017 Google LLC 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package spanner 18 19import ( 20 "fmt" 21 "reflect" 22 23 proto3 "github.com/golang/protobuf/ptypes/struct" 24 sppb "google.golang.org/genproto/googleapis/spanner/v1" 25 "google.golang.org/grpc/codes" 26) 27 28// A Row is a view of a row of data returned by a Cloud Spanner read. 29// It consists of a number of columns; the number depends on the columns 30// used to construct the read. 31// 32// The column values can be accessed by index. For instance, if the read specified 33// []string{"photo_id", "caption"}, then each row will contain two 34// columns: "photo_id" with index 0, and "caption" with index 1. 35// 36// Column values are decoded by using one of the Column, ColumnByName, or 37// Columns methods. The valid values passed to these methods depend on the 38// column type. For example: 39// 40// var photoID int64 41// err := row.Column(0, &photoID) // Decode column 0 as an integer. 42// 43// var caption string 44// err := row.Column(1, &caption) // Decode column 1 as a string. 45// 46// // Decode all the columns. 47// err := row.Columns(&photoID, &caption) 48// 49// Supported types and their corresponding Cloud Spanner column type(s) are: 50// 51// *string(not NULL), *NullString - STRING 52// *[]string, *[]NullString - STRING ARRAY 53// *[]byte - BYTES 54// *[][]byte - BYTES ARRAY 55// *int64(not NULL), *NullInt64 - INT64 56// *[]int64, *[]NullInt64 - INT64 ARRAY 57// *bool(not NULL), *NullBool - BOOL 58// *[]bool, *[]NullBool - BOOL ARRAY 59// *float64(not NULL), *NullFloat64 - FLOAT64 60// *[]float64, *[]NullFloat64 - FLOAT64 ARRAY 61// *time.Time(not NULL), *NullTime - TIMESTAMP 62// *[]time.Time, *[]NullTime - TIMESTAMP ARRAY 63// *Date(not NULL), *NullDate - DATE 64// *[]civil.Date, *[]NullDate - DATE ARRAY 65// *[]*some_go_struct, *[]NullRow - STRUCT ARRAY 66// *GenericColumnValue - any Cloud Spanner type 67// 68// For TIMESTAMP columns, the returned time.Time object will be in UTC. 69// 70// To fetch an array of BYTES, pass a *[][]byte. To fetch an array of (sub)rows, pass 71// a *[]spanner.NullRow or a *[]*some_go_struct where some_go_struct holds all 72// information of the subrow, see spanner.Row.ToStruct for the mapping between a 73// Cloud Spanner row and a Go struct. To fetch an array of other types, pass a 74// *[]spanner.NullXXX type of the appropriate type. Use GenericColumnValue when you 75// don't know in advance what column type to expect. 76// 77// Row decodes the row contents lazily; as a result, each call to a getter has 78// a chance of returning an error. 79// 80// A column value may be NULL if the corresponding value is not present in 81// Cloud Spanner. The spanner.NullXXX types (spanner.NullInt64 et al.) allow fetching 82// values that may be null. A NULL BYTES can be fetched into a *[]byte as nil. 83// It is an error to fetch a NULL value into any other type. 84type Row struct { 85 fields []*sppb.StructType_Field 86 vals []*proto3.Value // keep decoded for now 87} 88 89// errNamesValuesMismatch returns error for when columnNames count is not equal 90// to columnValues count. 91func errNamesValuesMismatch(columnNames []string, columnValues []interface{}) error { 92 return spannerErrorf(codes.FailedPrecondition, 93 "different number of names(%v) and values(%v)", len(columnNames), len(columnValues)) 94} 95 96// NewRow returns a Row containing the supplied data. This can be useful for 97// mocking Cloud Spanner Read and Query responses for unit testing. 98func NewRow(columnNames []string, columnValues []interface{}) (*Row, error) { 99 if len(columnValues) != len(columnNames) { 100 return nil, errNamesValuesMismatch(columnNames, columnValues) 101 } 102 r := Row{ 103 fields: make([]*sppb.StructType_Field, len(columnValues)), 104 vals: make([]*proto3.Value, len(columnValues)), 105 } 106 for i := range columnValues { 107 val, typ, err := encodeValue(columnValues[i]) 108 if err != nil { 109 return nil, err 110 } 111 r.fields[i] = &sppb.StructType_Field{ 112 Name: columnNames[i], 113 Type: typ, 114 } 115 r.vals[i] = val 116 } 117 return &r, nil 118} 119 120// Size is the number of columns in the row. 121func (r *Row) Size() int { 122 return len(r.fields) 123} 124 125// ColumnName returns the name of column i, or empty string for invalid column. 126func (r *Row) ColumnName(i int) string { 127 if i < 0 || i >= len(r.fields) { 128 return "" 129 } 130 return r.fields[i].Name 131} 132 133// ColumnIndex returns the index of the column with the given name. The 134// comparison is case-sensitive. 135func (r *Row) ColumnIndex(name string) (int, error) { 136 found := false 137 var index int 138 if len(r.vals) != len(r.fields) { 139 return 0, errFieldsMismatchVals(r) 140 } 141 for i, f := range r.fields { 142 if f == nil { 143 return 0, errNilColType(i) 144 } 145 if name == f.Name { 146 if found { 147 return 0, errDupColName(name) 148 } 149 found = true 150 index = i 151 } 152 } 153 if !found { 154 return 0, errColNotFound(name) 155 } 156 return index, nil 157} 158 159// ColumnNames returns all column names of the row. 160func (r *Row) ColumnNames() []string { 161 var n []string 162 for _, c := range r.fields { 163 n = append(n, c.Name) 164 } 165 return n 166} 167 168// errColIdxOutOfRange returns error for requested column index is out of the 169// range of the target Row's columns. 170func errColIdxOutOfRange(i int, r *Row) error { 171 return spannerErrorf(codes.OutOfRange, "column index %d out of range [0,%d)", i, len(r.vals)) 172} 173 174// errDecodeColumn returns error for not being able to decode a indexed column. 175func errDecodeColumn(i int, err error) error { 176 if err == nil { 177 return nil 178 } 179 var se *Error 180 if !errorAs(err, &se) { 181 return spannerErrorf(codes.InvalidArgument, "failed to decode column %v, error = <%v>", i, err) 182 } 183 se.decorate(fmt.Sprintf("failed to decode column %v", i)) 184 return se 185} 186 187// errFieldsMismatchVals returns error for field count isn't equal to value count in a Row. 188func errFieldsMismatchVals(r *Row) error { 189 return spannerErrorf(codes.FailedPrecondition, "row has different number of fields(%v) and values(%v)", 190 len(r.fields), len(r.vals)) 191} 192 193// errNilColType returns error for column type for column i being nil in the row. 194func errNilColType(i int) error { 195 return spannerErrorf(codes.FailedPrecondition, "column(%v)'s type is nil", i) 196} 197 198// Column fetches the value from the ith column, decoding it into ptr. 199// See the Row documentation for the list of acceptable argument types. 200// see Client.ReadWriteTransaction for an example. 201func (r *Row) Column(i int, ptr interface{}) error { 202 if len(r.vals) != len(r.fields) { 203 return errFieldsMismatchVals(r) 204 } 205 if i < 0 || i >= len(r.fields) { 206 return errColIdxOutOfRange(i, r) 207 } 208 if r.fields[i] == nil { 209 return errNilColType(i) 210 } 211 if err := decodeValue(r.vals[i], r.fields[i].Type, ptr); err != nil { 212 return errDecodeColumn(i, err) 213 } 214 return nil 215} 216 217// errDupColName returns error for duplicated column name in the same row. 218func errDupColName(n string) error { 219 return spannerErrorf(codes.FailedPrecondition, "ambiguous column name %q", n) 220} 221 222// errColNotFound returns error for not being able to find a named column. 223func errColNotFound(n string) error { 224 return spannerErrorf(codes.NotFound, "column %q not found", n) 225} 226 227// ColumnByName fetches the value from the named column, decoding it into ptr. 228// See the Row documentation for the list of acceptable argument types. 229func (r *Row) ColumnByName(name string, ptr interface{}) error { 230 index, err := r.ColumnIndex(name) 231 if err != nil { 232 return err 233 } 234 return r.Column(index, ptr) 235} 236 237// errNumOfColValue returns error for providing wrong number of values to Columns. 238func errNumOfColValue(n int, r *Row) error { 239 return spannerErrorf(codes.InvalidArgument, 240 "Columns(): number of arguments (%d) does not match row size (%d)", n, len(r.vals)) 241} 242 243// Columns fetches all the columns in the row at once. 244// 245// The value of the kth column will be decoded into the kth argument to Columns. See 246// Row for the list of acceptable argument types. The number of arguments must be 247// equal to the number of columns. Pass nil to specify that a column should be 248// ignored. 249func (r *Row) Columns(ptrs ...interface{}) error { 250 if len(ptrs) != len(r.vals) { 251 return errNumOfColValue(len(ptrs), r) 252 } 253 if len(r.vals) != len(r.fields) { 254 return errFieldsMismatchVals(r) 255 } 256 for i, p := range ptrs { 257 if p == nil { 258 continue 259 } 260 if err := r.Column(i, p); err != nil { 261 return err 262 } 263 } 264 return nil 265} 266 267// errToStructArgType returns error for p not having the correct data type(pointer to Go struct) to 268// be the argument of Row.ToStruct. 269func errToStructArgType(p interface{}) error { 270 return spannerErrorf(codes.InvalidArgument, "ToStruct(): type %T is not a valid pointer to Go struct", p) 271} 272 273// ToStruct fetches the columns in a row into the fields of a struct. 274// The rules for mapping a row's columns into a struct's exported fields 275// are: 276// 277// 1. If a field has a `spanner: "column_name"` tag, then decode column 278// 'column_name' into the field. A special case is the `spanner: "-"` 279// tag, which instructs ToStruct to ignore the field during decoding. 280// 281// 2. Otherwise, if the name of a field matches the name of a column (ignoring case), 282// decode the column into the field. 283// 284// The fields of the destination struct can be of any type that is acceptable 285// to spanner.Row.Column. 286// 287// Slice and pointer fields will be set to nil if the source column is NULL, and a 288// non-nil value if the column is not NULL. To decode NULL values of other types, use 289// one of the spanner.NullXXX types as the type of the destination field. 290// 291// If ToStruct returns an error, the contents of p are undefined. Some fields may 292// have been successfully populated, while others were not; you should not use any of 293// the fields. 294func (r *Row) ToStruct(p interface{}) error { 295 // Check if p is a pointer to a struct 296 if t := reflect.TypeOf(p); t == nil || t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct { 297 return errToStructArgType(p) 298 } 299 if len(r.vals) != len(r.fields) { 300 return errFieldsMismatchVals(r) 301 } 302 // Call decodeStruct directly to decode the row as a typed proto.ListValue. 303 return decodeStruct( 304 &sppb.StructType{Fields: r.fields}, 305 &proto3.ListValue{Values: r.vals}, 306 p, 307 ) 308} 309