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	"reflect"
21
22	proto3 "github.com/golang/protobuf/ptypes/struct"
23	sppb "google.golang.org/genproto/googleapis/spanner/v1"
24	"google.golang.org/grpc/codes"
25)
26
27// op is the mutation operation.
28type op int
29
30const (
31	// opDelete removes a row from a table.  Succeeds whether or not the
32	// key was present.
33	opDelete op = iota
34	// opInsert inserts a row into a table.  If the row already exists, the
35	// write or transaction fails.
36	opInsert
37	// opInsertOrUpdate inserts a row into a table. If the row already
38	// exists, it updates it instead.  Any column values not explicitly
39	// written are preserved.
40	opInsertOrUpdate
41	// opReplace inserts a row into a table, deleting any existing row.
42	// Unlike InsertOrUpdate, this means any values not explicitly written
43	// become NULL.
44	opReplace
45	// opUpdate updates a row in a table.  If the row does not already
46	// exist, the write or transaction fails.
47	opUpdate
48)
49
50// A Mutation describes a modification to one or more Cloud Spanner rows.  The
51// mutation represents an insert, update, delete, etc on a table.
52//
53// Many mutations can be applied in a single atomic commit. For purposes of
54// constraint checking (such as foreign key constraints), the operations can be
55// viewed as applying in the same order as the mutations are provided (so that,
56// e.g., a row and its logical "child" can be inserted in the same commit).
57//
58// The Apply function applies series of mutations. For example,
59//
60//	 m := spanner.Insert("User",
61//		 []string{"user_id", "profile"},
62//		 []interface{}{UserID, profile})
63//	 _, err := client.Apply(ctx, []*spanner.Mutation{m})
64//
65// inserts a new row into the User table. The primary key
66// for the new row is UserID (presuming that "user_id" has been declared as the
67// primary key of the "User" table).
68//
69// To apply a series of mutations as part of an atomic read-modify-write
70// operation, use ReadWriteTransaction.
71//
72// Updating a row
73//
74// Changing the values of columns in an existing row is very similar to
75// inserting a new row:
76//
77//	m := spanner.Update("User",
78//		[]string{"user_id", "profile"},
79//		[]interface{}{UserID, profile})
80//	_, err := client.Apply(ctx, []*spanner.Mutation{m})
81//
82// Deleting a row
83//
84// To delete a row, use spanner.Delete:
85//
86//	m := spanner.Delete("User", spanner.Key{UserId})
87//	_, err := client.Apply(ctx, []*spanner.Mutation{m})
88//
89// spanner.Delete accepts a KeySet, so you can also pass in a KeyRange, or use
90// the spanner.KeySets function to build any combination of Keys and KeyRanges.
91//
92// Note that deleting a row in a table may also delete rows from other tables
93// if cascading deletes are specified in those tables' schemas. Delete does
94// nothing if the named row does not exist (does not yield an error).
95//
96// Deleting a field
97//
98// To delete/clear a field within a row, use spanner.Update with the value nil:
99//
100//	m := spanner.Update("User",
101//		[]string{"user_id", "profile"},
102//		[]interface{}{UserID, nil})
103//	_, err := client.Apply(ctx, []*spanner.Mutation{m})
104//
105// The valid Go types and their corresponding Cloud Spanner types that can be
106// used in the Insert/Update/InsertOrUpdate functions are:
107//
108//     string, *string, NullString - STRING
109//     []string, []*string, []NullString - STRING ARRAY
110//     []byte - BYTES
111//     [][]byte - BYTES ARRAY
112//     int, int64, *int64, NullInt64 - INT64
113//     []int, []int64, []*int64, []NullInt64 - INT64 ARRAY
114//     bool, *bool, NullBool - BOOL
115//     []bool, []*bool, []NullBool - BOOL ARRAY
116//     float64, *float64, NullFloat64 - FLOAT64
117//     []float64, []*float64, []NullFloat64 - FLOAT64 ARRAY
118//     time.Time, *time.Time, NullTime - TIMESTAMP
119//     []time.Time, []*time.Time, []NullTime - TIMESTAMP ARRAY
120//     Date, *Date, NullDate - DATE
121//     []Date, []*Date, []NullDate - DATE ARRAY
122//
123// To compare two Mutations for testing purposes, use reflect.DeepEqual.
124type Mutation struct {
125	// op is the operation type of the mutation.
126	// See documentation for spanner.op for more details.
127	op op
128	// Table is the name of the target table to be modified.
129	table string
130	// keySet is a set of primary keys that names the rows
131	// in a delete operation.
132	keySet KeySet
133	// columns names the set of columns that are going to be
134	// modified by Insert, InsertOrUpdate, Replace or Update
135	// operations.
136	columns []string
137	// values specifies the new values for the target columns
138	// named by Columns.
139	values []interface{}
140}
141
142// mapToMutationParams converts Go map into mutation parameters.
143func mapToMutationParams(in map[string]interface{}) ([]string, []interface{}) {
144	cols := []string{}
145	vals := []interface{}{}
146	for k, v := range in {
147		cols = append(cols, k)
148		vals = append(vals, v)
149	}
150	return cols, vals
151}
152
153// errNotStruct returns error for not getting a go struct type.
154func errNotStruct(in interface{}) error {
155	return spannerErrorf(codes.InvalidArgument, "%T is not a go struct type", in)
156}
157
158// structToMutationParams converts Go struct into mutation parameters.
159// If the input is not a valid Go struct type, structToMutationParams
160// returns error.
161func structToMutationParams(in interface{}) ([]string, []interface{}, error) {
162	if in == nil {
163		return nil, nil, errNotStruct(in)
164	}
165	v := reflect.ValueOf(in)
166	t := v.Type()
167	if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct {
168		// t is a pointer to a struct.
169		if v.IsNil() {
170			// Return empty results.
171			return nil, nil, nil
172		}
173		// Get the struct value that in points to.
174		v = v.Elem()
175		t = t.Elem()
176	}
177	if t.Kind() != reflect.Struct {
178		return nil, nil, errNotStruct(in)
179	}
180	fields, err := fieldCache.Fields(t)
181	if err != nil {
182		return nil, nil, ToSpannerError(err)
183	}
184	var cols []string
185	var vals []interface{}
186	for _, f := range fields {
187		cols = append(cols, f.Name)
188		vals = append(vals, v.FieldByIndex(f.Index).Interface())
189	}
190	return cols, vals, nil
191}
192
193// Insert returns a Mutation to insert a row into a table. If the row already
194// exists, the write or transaction fails with codes.AlreadyExists.
195func Insert(table string, cols []string, vals []interface{}) *Mutation {
196	return &Mutation{
197		op:      opInsert,
198		table:   table,
199		columns: cols,
200		values:  vals,
201	}
202}
203
204// InsertMap returns a Mutation to insert a row into a table, specified by
205// a map of column name to value. If the row already exists, the write or
206// transaction fails with codes.AlreadyExists.
207func InsertMap(table string, in map[string]interface{}) *Mutation {
208	cols, vals := mapToMutationParams(in)
209	return Insert(table, cols, vals)
210}
211
212// InsertStruct returns a Mutation to insert a row into a table, specified by
213// a Go struct.  If the row already exists, the write or transaction fails with
214// codes.AlreadyExists.
215//
216// The in argument must be a struct or a pointer to a struct. Its exported
217// fields specify the column names and values. Use a field tag like "spanner:name"
218// to provide an alternative column name, or use "spanner:-" to ignore the field.
219func InsertStruct(table string, in interface{}) (*Mutation, error) {
220	cols, vals, err := structToMutationParams(in)
221	if err != nil {
222		return nil, err
223	}
224	return Insert(table, cols, vals), nil
225}
226
227// Update returns a Mutation to update a row in a table. If the row does not
228// already exist, the write or transaction fails.
229func Update(table string, cols []string, vals []interface{}) *Mutation {
230	return &Mutation{
231		op:      opUpdate,
232		table:   table,
233		columns: cols,
234		values:  vals,
235	}
236}
237
238// UpdateMap returns a Mutation to update a row in a table, specified by
239// a map of column to value. If the row does not already exist, the write or
240// transaction fails.
241func UpdateMap(table string, in map[string]interface{}) *Mutation {
242	cols, vals := mapToMutationParams(in)
243	return Update(table, cols, vals)
244}
245
246// UpdateStruct returns a Mutation to update a row in a table, specified by a Go
247// struct. If the row does not already exist, the write or transaction fails.
248func UpdateStruct(table string, in interface{}) (*Mutation, error) {
249	cols, vals, err := structToMutationParams(in)
250	if err != nil {
251		return nil, err
252	}
253	return Update(table, cols, vals), nil
254}
255
256// InsertOrUpdate returns a Mutation to insert a row into a table. If the row
257// already exists, it updates it instead. Any column values not explicitly
258// written are preserved.
259//
260// For a similar example, See Update.
261func InsertOrUpdate(table string, cols []string, vals []interface{}) *Mutation {
262	return &Mutation{
263		op:      opInsertOrUpdate,
264		table:   table,
265		columns: cols,
266		values:  vals,
267	}
268}
269
270// InsertOrUpdateMap returns a Mutation to insert a row into a table,
271// specified by a map of column to value. If the row already exists, it
272// updates it instead. Any column values not explicitly written are preserved.
273//
274// For a similar example, See UpdateMap.
275func InsertOrUpdateMap(table string, in map[string]interface{}) *Mutation {
276	cols, vals := mapToMutationParams(in)
277	return InsertOrUpdate(table, cols, vals)
278}
279
280// InsertOrUpdateStruct returns a Mutation to insert a row into a table,
281// specified by a Go struct. If the row already exists, it updates it instead.
282// Any column values not explicitly written are preserved.
283//
284// The in argument must be a struct or a pointer to a struct. Its exported
285// fields specify the column names and values. Use a field tag like
286// "spanner:name" to provide an alternative column name, or use "spanner:-" to
287// ignore the field.
288//
289// For a similar example, See UpdateStruct.
290func InsertOrUpdateStruct(table string, in interface{}) (*Mutation, error) {
291	cols, vals, err := structToMutationParams(in)
292	if err != nil {
293		return nil, err
294	}
295	return InsertOrUpdate(table, cols, vals), nil
296}
297
298// Replace returns a Mutation to insert a row into a table, deleting any
299// existing row. Unlike InsertOrUpdate, this means any values not explicitly
300// written become NULL.
301//
302// For a similar example, See Update.
303func Replace(table string, cols []string, vals []interface{}) *Mutation {
304	return &Mutation{
305		op:      opReplace,
306		table:   table,
307		columns: cols,
308		values:  vals,
309	}
310}
311
312// ReplaceMap returns a Mutation to insert a row into a table, deleting any
313// existing row. Unlike InsertOrUpdateMap, this means any values not explicitly
314// written become NULL.  The row is specified by a map of column to value.
315//
316// For a similar example, See UpdateMap.
317func ReplaceMap(table string, in map[string]interface{}) *Mutation {
318	cols, vals := mapToMutationParams(in)
319	return Replace(table, cols, vals)
320}
321
322// ReplaceStruct returns a Mutation to insert a row into a table, deleting any
323// existing row. Unlike InsertOrUpdateMap, this means any values not explicitly
324// written become NULL.  The row is specified by a Go struct.
325//
326// The in argument must be a struct or a pointer to a struct. Its exported
327// fields specify the column names and values. Use a field tag like "spanner:name"
328// to provide an alternative column name, or use "spanner:-" to ignore the field.
329//
330// For a similar example, See UpdateStruct.
331func ReplaceStruct(table string, in interface{}) (*Mutation, error) {
332	cols, vals, err := structToMutationParams(in)
333	if err != nil {
334		return nil, err
335	}
336	return Replace(table, cols, vals), nil
337}
338
339// Delete removes the rows described by the KeySet from the table. It succeeds
340// whether or not the keys were present.
341func Delete(table string, ks KeySet) *Mutation {
342	return &Mutation{
343		op:     opDelete,
344		table:  table,
345		keySet: ks,
346	}
347}
348
349// prepareWrite generates sppb.Mutation_Write from table name, column names
350// and new column values.
351func prepareWrite(table string, columns []string, vals []interface{}) (*sppb.Mutation_Write, error) {
352	v, err := encodeValueArray(vals)
353	if err != nil {
354		return nil, err
355	}
356	return &sppb.Mutation_Write{
357		Table:   table,
358		Columns: columns,
359		Values:  []*proto3.ListValue{v},
360	}, nil
361}
362
363// errInvdMutationOp returns error for unrecognized mutation operation.
364func errInvdMutationOp(m Mutation) error {
365	return spannerErrorf(codes.InvalidArgument, "Unknown op type: %d", m.op)
366}
367
368// proto converts spanner.Mutation to sppb.Mutation, in preparation to send
369// RPCs.
370func (m Mutation) proto() (*sppb.Mutation, error) {
371	var pb *sppb.Mutation
372	switch m.op {
373	case opDelete:
374		var kp *sppb.KeySet
375		if m.keySet != nil {
376			var err error
377			kp, err = m.keySet.keySetProto()
378			if err != nil {
379				return nil, err
380			}
381		}
382		pb = &sppb.Mutation{
383			Operation: &sppb.Mutation_Delete_{
384				Delete: &sppb.Mutation_Delete{
385					Table:  m.table,
386					KeySet: kp,
387				},
388			},
389		}
390	case opInsert:
391		w, err := prepareWrite(m.table, m.columns, m.values)
392		if err != nil {
393			return nil, err
394		}
395		pb = &sppb.Mutation{Operation: &sppb.Mutation_Insert{Insert: w}}
396	case opInsertOrUpdate:
397		w, err := prepareWrite(m.table, m.columns, m.values)
398		if err != nil {
399			return nil, err
400		}
401		pb = &sppb.Mutation{Operation: &sppb.Mutation_InsertOrUpdate{InsertOrUpdate: w}}
402	case opReplace:
403		w, err := prepareWrite(m.table, m.columns, m.values)
404		if err != nil {
405			return nil, err
406		}
407		pb = &sppb.Mutation{Operation: &sppb.Mutation_Replace{Replace: w}}
408	case opUpdate:
409		w, err := prepareWrite(m.table, m.columns, m.values)
410		if err != nil {
411			return nil, err
412		}
413		pb = &sppb.Mutation{Operation: &sppb.Mutation_Update{Update: w}}
414	default:
415		return nil, errInvdMutationOp(m)
416	}
417	return pb, nil
418}
419
420// mutationsProto turns a spanner.Mutation array into a sppb.Mutation array,
421// it is convenient for sending batch mutations to Cloud Spanner.
422func mutationsProto(ms []*Mutation) ([]*sppb.Mutation, error) {
423	l := make([]*sppb.Mutation, 0, len(ms))
424	for _, m := range ms {
425		pb, err := m.proto()
426		if err != nil {
427			return nil, err
428		}
429		l = append(l, pb)
430	}
431	return l, nil
432}
433