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