You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

430 lines
11 KiB

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