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