1// Copyright 2017 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package firestore
16
17import (
18	"errors"
19	"fmt"
20	"reflect"
21	"strings"
22
23	"github.com/golang/protobuf/ptypes"
24	pb "google.golang.org/genproto/googleapis/firestore/v1"
25)
26
27func setFromProtoValue(x interface{}, vproto *pb.Value, c *Client) error {
28	v := reflect.ValueOf(x)
29	if v.Kind() != reflect.Ptr || v.IsNil() {
30		return errors.New("firestore: nil or not a pointer")
31	}
32	return setReflectFromProtoValue(v.Elem(), vproto, c)
33}
34
35// setReflectFromProtoValue sets v from a Firestore Value.
36// v must be a settable value.
37func setReflectFromProtoValue(v reflect.Value, vproto *pb.Value, c *Client) error {
38	typeErr := func() error {
39		return fmt.Errorf("firestore: cannot set type %s to %s", v.Type(), typeString(vproto))
40	}
41
42	val := vproto.ValueType
43	// A Null value sets anything nullable to nil, and has no effect
44	// on anything else.
45	if _, ok := val.(*pb.Value_NullValue); ok {
46		switch v.Kind() {
47		case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
48			v.Set(reflect.Zero(v.Type()))
49		}
50		return nil
51	}
52
53	// Handle special types first.
54	switch v.Type() {
55	case typeOfByteSlice:
56		x, ok := val.(*pb.Value_BytesValue)
57		if !ok {
58			return typeErr()
59		}
60		v.SetBytes(x.BytesValue)
61		return nil
62
63	case typeOfGoTime:
64		x, ok := val.(*pb.Value_TimestampValue)
65		if !ok {
66			return typeErr()
67		}
68		t, err := ptypes.Timestamp(x.TimestampValue)
69		if err != nil {
70			return err
71		}
72		v.Set(reflect.ValueOf(t))
73		return nil
74
75	case typeOfProtoTimestamp:
76		x, ok := val.(*pb.Value_TimestampValue)
77		if !ok {
78			return typeErr()
79		}
80		v.Set(reflect.ValueOf(x.TimestampValue))
81		return nil
82
83	case typeOfLatLng:
84		x, ok := val.(*pb.Value_GeoPointValue)
85		if !ok {
86			return typeErr()
87		}
88		v.Set(reflect.ValueOf(x.GeoPointValue))
89		return nil
90
91	case typeOfDocumentRef:
92		x, ok := val.(*pb.Value_ReferenceValue)
93		if !ok {
94			return typeErr()
95		}
96		dr, err := pathToDoc(x.ReferenceValue, c)
97		if err != nil {
98			return err
99		}
100		v.Set(reflect.ValueOf(dr))
101		return nil
102	}
103
104	switch v.Kind() {
105	case reflect.Bool:
106		x, ok := val.(*pb.Value_BooleanValue)
107		if !ok {
108			return typeErr()
109		}
110		v.SetBool(x.BooleanValue)
111
112	case reflect.String:
113		x, ok := val.(*pb.Value_StringValue)
114		if !ok {
115			return typeErr()
116		}
117		v.SetString(x.StringValue)
118
119	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
120		var i int64
121		switch x := val.(type) {
122		case *pb.Value_IntegerValue:
123			i = x.IntegerValue
124		case *pb.Value_DoubleValue:
125			f := x.DoubleValue
126			i = int64(f)
127			if float64(i) != f {
128				return fmt.Errorf("firestore: float %f does not fit into %s", f, v.Type())
129			}
130		default:
131			return typeErr()
132		}
133		if v.OverflowInt(i) {
134			return overflowErr(v, i)
135		}
136		v.SetInt(i)
137
138	case reflect.Uint8, reflect.Uint16, reflect.Uint32:
139		var u uint64
140		switch x := val.(type) {
141		case *pb.Value_IntegerValue:
142			u = uint64(x.IntegerValue)
143		case *pb.Value_DoubleValue:
144			f := x.DoubleValue
145			u = uint64(f)
146			if float64(u) != f {
147				return fmt.Errorf("firestore: float %f does not fit into %s", f, v.Type())
148			}
149		default:
150			return typeErr()
151		}
152		if v.OverflowUint(u) {
153			return overflowErr(v, u)
154		}
155		v.SetUint(u)
156
157	case reflect.Float32, reflect.Float64:
158		var f float64
159		switch x := val.(type) {
160		case *pb.Value_DoubleValue:
161			f = x.DoubleValue
162		case *pb.Value_IntegerValue:
163			f = float64(x.IntegerValue)
164			if int64(f) != x.IntegerValue {
165				return overflowErr(v, x.IntegerValue)
166			}
167		default:
168			return typeErr()
169		}
170		if v.OverflowFloat(f) {
171			return overflowErr(v, f)
172		}
173		v.SetFloat(f)
174
175	case reflect.Slice:
176		x, ok := val.(*pb.Value_ArrayValue)
177		if !ok {
178			return typeErr()
179		}
180		vals := x.ArrayValue.Values
181		vlen := v.Len()
182		xlen := len(vals)
183		// Make a slice of the right size, avoiding allocation if possible.
184		switch {
185		case vlen < xlen:
186			v.Set(reflect.MakeSlice(v.Type(), xlen, xlen))
187		case vlen > xlen:
188			v.SetLen(xlen)
189		}
190		return populateRepeated(v, vals, xlen, c)
191
192	case reflect.Array:
193		x, ok := val.(*pb.Value_ArrayValue)
194		if !ok {
195			return typeErr()
196		}
197		vals := x.ArrayValue.Values
198		xlen := len(vals)
199		vlen := v.Len()
200		minlen := vlen
201		// Set extra elements to their zero value.
202		if vlen > xlen {
203			z := reflect.Zero(v.Type().Elem())
204			for i := xlen; i < vlen; i++ {
205				v.Index(i).Set(z)
206			}
207			minlen = xlen
208		}
209		return populateRepeated(v, vals, minlen, c)
210
211	case reflect.Map:
212		x, ok := val.(*pb.Value_MapValue)
213		if !ok {
214			return typeErr()
215		}
216		return populateMap(v, x.MapValue.Fields, c)
217
218	case reflect.Ptr:
219		// If the pointer is nil, set it to a zero value.
220		if v.IsNil() {
221			v.Set(reflect.New(v.Type().Elem()))
222		}
223		return setReflectFromProtoValue(v.Elem(), vproto, c)
224
225	case reflect.Struct:
226		x, ok := val.(*pb.Value_MapValue)
227		if !ok {
228			return typeErr()
229		}
230		return populateStruct(v, x.MapValue.Fields, c)
231
232	case reflect.Interface:
233		if v.NumMethod() == 0 { // empty interface
234			// If v holds a pointer, set the pointer.
235			if !v.IsNil() && v.Elem().Kind() == reflect.Ptr {
236				return setReflectFromProtoValue(v.Elem(), vproto, c)
237			}
238			// Otherwise, create a fresh value.
239			x, err := createFromProtoValue(vproto, c)
240			if err != nil {
241				return err
242			}
243			v.Set(reflect.ValueOf(x))
244			return nil
245		}
246		// Any other kind of interface is an error.
247		fallthrough
248
249	default:
250		return fmt.Errorf("firestore: cannot set type %s", v.Type())
251	}
252	return nil
253}
254
255// populateRepeated sets the first n elements of vr, which must be a slice or
256// array, to the corresponding elements of vals.
257func populateRepeated(vr reflect.Value, vals []*pb.Value, n int, c *Client) error {
258	for i := 0; i < n; i++ {
259		if err := setReflectFromProtoValue(vr.Index(i), vals[i], c); err != nil {
260			return err
261		}
262	}
263	return nil
264}
265
266// populateMap sets the elements of vm, which must be a map, from the
267// corresponding elements of pm.
268//
269// Since a map value is not settable, this function always creates a new
270// element for each corresponding map key. Existing values of vm are
271// overwritten. This happens even if the map value is something like a pointer
272// to a struct, where we could in theory populate the existing struct value
273// instead of discarding it. This behavior matches encoding/json.
274func populateMap(vm reflect.Value, pm map[string]*pb.Value, c *Client) error {
275	t := vm.Type()
276	if t.Key().Kind() != reflect.String {
277		return errors.New("firestore: map key type is not string")
278	}
279	if vm.IsNil() {
280		vm.Set(reflect.MakeMap(t))
281	}
282	et := t.Elem()
283	for k, vproto := range pm {
284		el := reflect.New(et).Elem()
285		if err := setReflectFromProtoValue(el, vproto, c); err != nil {
286			return err
287		}
288		vm.SetMapIndex(reflect.ValueOf(k), el)
289	}
290	return nil
291}
292
293// createMapFromValueMap creates a fresh map and populates it with pm.
294func createMapFromValueMap(pm map[string]*pb.Value, c *Client) (map[string]interface{}, error) {
295	m := map[string]interface{}{}
296	for k, pv := range pm {
297		v, err := createFromProtoValue(pv, c)
298		if err != nil {
299			return nil, err
300		}
301		m[k] = v
302	}
303	return m, nil
304}
305
306// populateStruct sets the fields of vs, which must be a struct, from
307// the matching elements of pm.
308func populateStruct(vs reflect.Value, pm map[string]*pb.Value, c *Client) error {
309	fields, err := fieldCache.Fields(vs.Type())
310	if err != nil {
311		return err
312	}
313	for k, vproto := range pm {
314		f := fields.Match(k)
315		if f == nil {
316			continue
317		}
318		if err := setReflectFromProtoValue(vs.FieldByIndex(f.Index), vproto, c); err != nil {
319			return fmt.Errorf("%s.%s: %v", vs.Type(), f.Name, err)
320		}
321	}
322	return nil
323}
324
325func createFromProtoValue(vproto *pb.Value, c *Client) (interface{}, error) {
326	switch v := vproto.ValueType.(type) {
327	case *pb.Value_NullValue:
328		return nil, nil
329	case *pb.Value_BooleanValue:
330		return v.BooleanValue, nil
331	case *pb.Value_IntegerValue:
332		return v.IntegerValue, nil
333	case *pb.Value_DoubleValue:
334		return v.DoubleValue, nil
335	case *pb.Value_TimestampValue:
336		return ptypes.Timestamp(v.TimestampValue)
337	case *pb.Value_StringValue:
338		return v.StringValue, nil
339	case *pb.Value_BytesValue:
340		return v.BytesValue, nil
341	case *pb.Value_ReferenceValue:
342		return pathToDoc(v.ReferenceValue, c)
343	case *pb.Value_GeoPointValue:
344		return v.GeoPointValue, nil
345	case *pb.Value_ArrayValue:
346		vals := v.ArrayValue.Values
347		ret := make([]interface{}, len(vals))
348		for i, v := range vals {
349			r, err := createFromProtoValue(v, c)
350			if err != nil {
351				return nil, err
352			}
353			ret[i] = r
354		}
355		return ret, nil
356
357	case *pb.Value_MapValue:
358		fields := v.MapValue.Fields
359		ret := make(map[string]interface{}, len(fields))
360		for k, v := range fields {
361			r, err := createFromProtoValue(v, c)
362			if err != nil {
363				return nil, err
364			}
365			ret[k] = r
366		}
367		return ret, nil
368
369	default:
370		return nil, fmt.Errorf("firestore: unknown value type %T", v)
371	}
372}
373
374// Convert a document path to a DocumentRef.
375func pathToDoc(docPath string, c *Client) (*DocumentRef, error) {
376	projID, dbID, docIDs, err := parseDocumentPath(docPath)
377	if err != nil {
378		return nil, err
379	}
380	parentResourceName := fmt.Sprintf("projects/%s/databases/%s", projID, dbID)
381	_, doc := c.idsToRef(docIDs, parentResourceName)
382	return doc, nil
383}
384
385// A document path should be of the form "projects/P/databases/D/documents/coll1/doc1/coll2/doc2/...".
386func parseDocumentPath(path string) (projectID, databaseID string, docPath []string, err error) {
387	parts := strings.Split(path, "/")
388	if len(parts) < 6 || parts[0] != "projects" || parts[2] != "databases" || parts[4] != "documents" {
389		return "", "", nil, fmt.Errorf("firestore: malformed document path %q", path)
390	}
391	docp := parts[5:]
392	if len(docp)%2 != 0 {
393		return "", "", nil, fmt.Errorf("firestore: path %q refers to collection, not document", path)
394	}
395	return parts[1], parts[3], docp, nil
396}
397
398func typeString(vproto *pb.Value) string {
399	switch vproto.ValueType.(type) {
400	case *pb.Value_NullValue:
401		return "null"
402	case *pb.Value_BooleanValue:
403		return "bool"
404	case *pb.Value_IntegerValue:
405		return "int"
406	case *pb.Value_DoubleValue:
407		return "float"
408	case *pb.Value_TimestampValue:
409		return "timestamp"
410	case *pb.Value_StringValue:
411		return "string"
412	case *pb.Value_BytesValue:
413		return "bytes"
414	case *pb.Value_ReferenceValue:
415		return "reference"
416	case *pb.Value_GeoPointValue:
417		return "GeoPoint"
418	case *pb.Value_MapValue:
419		return "map"
420	case *pb.Value_ArrayValue:
421		return "array"
422	default:
423		return "<unknown Value type>"
424	}
425}
426
427func overflowErr(v reflect.Value, x interface{}) error {
428	return fmt.Errorf("firestore: value %v overflows type %s", x, v.Type())
429}
430