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.
 
 
 

343 lines
9.6 KiB

  1. // Copyright 2014 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 datastore
  15. import (
  16. "fmt"
  17. "reflect"
  18. "strings"
  19. "unicode"
  20. "cloud.google.com/go/internal/fields"
  21. )
  22. // Entities with more than this many indexed properties will not be saved.
  23. const maxIndexedProperties = 20000
  24. // []byte fields more than 1 megabyte long will not be loaded or saved.
  25. const maxBlobLen = 1 << 20
  26. // Property is a name/value pair plus some metadata. A datastore entity's
  27. // contents are loaded and saved as a sequence of Properties. Each property
  28. // name must be unique within an entity.
  29. type Property struct {
  30. // Name is the property name.
  31. Name string
  32. // Value is the property value. The valid types are:
  33. // - int64
  34. // - bool
  35. // - string
  36. // - float64
  37. // - *Key
  38. // - time.Time
  39. // - GeoPoint
  40. // - []byte (up to 1 megabyte in length)
  41. // - *Entity (representing a nested struct)
  42. // Value can also be:
  43. // - []interface{} where each element is one of the above types
  44. // This set is smaller than the set of valid struct field types that the
  45. // datastore can load and save. A Value's type must be explicitly on
  46. // the list above; it is not sufficient for the underlying type to be
  47. // on that list. For example, a Value of "type myInt64 int64" is
  48. // invalid. Smaller-width integers and floats are also invalid. Again,
  49. // this is more restrictive than the set of valid struct field types.
  50. //
  51. // A Value will have an opaque type when loading entities from an index,
  52. // such as via a projection query. Load entities into a struct instead
  53. // of a PropertyLoadSaver when using a projection query.
  54. //
  55. // A Value may also be the nil interface value; this is equivalent to
  56. // Python's None but not directly representable by a Go struct. Loading
  57. // a nil-valued property into a struct will set that field to the zero
  58. // value.
  59. Value interface{}
  60. // NoIndex is whether the datastore cannot index this property.
  61. // If NoIndex is set to false, []byte and string values are limited to
  62. // 1500 bytes.
  63. NoIndex bool
  64. }
  65. // An Entity is the value type for a nested struct.
  66. // This type is only used for a Property's Value.
  67. type Entity struct {
  68. Key *Key
  69. Properties []Property
  70. }
  71. // PropertyLoadSaver can be converted from and to a slice of Properties.
  72. type PropertyLoadSaver interface {
  73. Load([]Property) error
  74. Save() ([]Property, error)
  75. }
  76. // KeyLoader can store a Key.
  77. type KeyLoader interface {
  78. // PropertyLoadSaver is embedded because a KeyLoader
  79. // must also always implement PropertyLoadSaver.
  80. PropertyLoadSaver
  81. LoadKey(k *Key) error
  82. }
  83. // PropertyList converts a []Property to implement PropertyLoadSaver.
  84. type PropertyList []Property
  85. var (
  86. typeOfPropertyLoadSaver = reflect.TypeOf((*PropertyLoadSaver)(nil)).Elem()
  87. typeOfPropertyList = reflect.TypeOf(PropertyList(nil))
  88. )
  89. // Load loads all of the provided properties into l.
  90. // It does not first reset *l to an empty slice.
  91. func (l *PropertyList) Load(p []Property) error {
  92. *l = append(*l, p...)
  93. return nil
  94. }
  95. // Save saves all of l's properties as a slice of Properties.
  96. func (l *PropertyList) Save() ([]Property, error) {
  97. return *l, nil
  98. }
  99. // validPropertyName returns whether name consists of one or more valid Go
  100. // identifiers joined by ".".
  101. func validPropertyName(name string) bool {
  102. if name == "" {
  103. return false
  104. }
  105. for _, s := range strings.Split(name, ".") {
  106. if s == "" {
  107. return false
  108. }
  109. first := true
  110. for _, c := range s {
  111. if first {
  112. first = false
  113. if c != '_' && !unicode.IsLetter(c) {
  114. return false
  115. }
  116. } else {
  117. if c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
  118. return false
  119. }
  120. }
  121. }
  122. }
  123. return true
  124. }
  125. // parseTag interprets datastore struct field tags
  126. func parseTag(t reflect.StructTag) (name string, keep bool, other interface{}, err error) {
  127. s := t.Get("datastore")
  128. parts := strings.Split(s, ",")
  129. if parts[0] == "-" && len(parts) == 1 {
  130. return "", false, nil, nil
  131. }
  132. if parts[0] != "" && !validPropertyName(parts[0]) {
  133. err = fmt.Errorf("datastore: struct tag has invalid property name: %q", parts[0])
  134. return "", false, nil, err
  135. }
  136. var opts saveOpts
  137. if len(parts) > 1 {
  138. for _, p := range parts[1:] {
  139. switch p {
  140. case "flatten":
  141. opts.flatten = true
  142. case "omitempty":
  143. opts.omitEmpty = true
  144. case "noindex":
  145. opts.noIndex = true
  146. default:
  147. err = fmt.Errorf("datastore: struct tag has invalid option: %q", p)
  148. return "", false, nil, err
  149. }
  150. }
  151. other = opts
  152. }
  153. return parts[0], true, other, nil
  154. }
  155. func validateType(t reflect.Type) error {
  156. if t.Kind() != reflect.Struct {
  157. return fmt.Errorf("datastore: validate called with non-struct type %s", t)
  158. }
  159. return validateChildType(t, "", false, false, map[reflect.Type]bool{})
  160. }
  161. // validateChildType is a recursion helper func for validateType
  162. func validateChildType(t reflect.Type, fieldName string, flatten, prevSlice bool, prevTypes map[reflect.Type]bool) error {
  163. if prevTypes[t] {
  164. return nil
  165. }
  166. prevTypes[t] = true
  167. switch t.Kind() {
  168. case reflect.Slice:
  169. if flatten && prevSlice {
  170. return fmt.Errorf("datastore: flattening nested structs leads to a slice of slices: field %q", fieldName)
  171. }
  172. return validateChildType(t.Elem(), fieldName, flatten, true, prevTypes)
  173. case reflect.Struct:
  174. if t == typeOfTime || t == typeOfGeoPoint {
  175. return nil
  176. }
  177. for i := 0; i < t.NumField(); i++ {
  178. f := t.Field(i)
  179. // If a named field is unexported, ignore it. An anonymous
  180. // unexported field is processed, because it may contain
  181. // exported fields, which are visible.
  182. exported := (f.PkgPath == "")
  183. if !exported && !f.Anonymous {
  184. continue
  185. }
  186. _, keep, other, err := parseTag(f.Tag)
  187. // Handle error from parseTag now instead of later (in cache.Fields call).
  188. if err != nil {
  189. return err
  190. }
  191. if !keep {
  192. continue
  193. }
  194. if other != nil {
  195. opts := other.(saveOpts)
  196. flatten = flatten || opts.flatten
  197. }
  198. if err := validateChildType(f.Type, f.Name, flatten, prevSlice, prevTypes); err != nil {
  199. return err
  200. }
  201. }
  202. case reflect.Ptr:
  203. if t == typeOfKeyPtr {
  204. return nil
  205. }
  206. return validateChildType(t.Elem(), fieldName, flatten, prevSlice, prevTypes)
  207. }
  208. return nil
  209. }
  210. // isLeafType determines whether or not a type is a 'leaf type'
  211. // and should not be recursed into, but considered one field.
  212. func isLeafType(t reflect.Type) bool {
  213. return t == typeOfTime || t == typeOfGeoPoint
  214. }
  215. // structCache collects the structs whose fields have already been calculated.
  216. var structCache = fields.NewCache(parseTag, validateType, isLeafType)
  217. // structPLS adapts a struct to be a PropertyLoadSaver.
  218. type structPLS struct {
  219. v reflect.Value
  220. codec fields.List
  221. }
  222. // newStructPLS returns a structPLS, which implements the
  223. // PropertyLoadSaver interface, for the struct pointer p.
  224. func newStructPLS(p interface{}) (*structPLS, error) {
  225. v := reflect.ValueOf(p)
  226. if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
  227. return nil, ErrInvalidEntityType
  228. }
  229. v = v.Elem()
  230. f, err := structCache.Fields(v.Type())
  231. if err != nil {
  232. return nil, err
  233. }
  234. return &structPLS{v, f}, nil
  235. }
  236. // LoadStruct loads the properties from p to dst.
  237. // dst must be a struct pointer.
  238. //
  239. // The values of dst's unmatched struct fields are not modified,
  240. // and matching slice-typed fields are not reset before appending to
  241. // them. In particular, it is recommended to pass a pointer to a zero
  242. // valued struct on each LoadStruct call.
  243. func LoadStruct(dst interface{}, p []Property) error {
  244. x, err := newStructPLS(dst)
  245. if err != nil {
  246. return err
  247. }
  248. return x.Load(p)
  249. }
  250. // SaveStruct returns the properties from src as a slice of Properties.
  251. // src must be a struct pointer.
  252. func SaveStruct(src interface{}) ([]Property, error) {
  253. x, err := newStructPLS(src)
  254. if err != nil {
  255. return nil, err
  256. }
  257. return x.Save()
  258. }
  259. // plsForLoad tries to convert v to a PropertyLoadSaver.
  260. // If successful, plsForLoad returns a settable v as a PropertyLoadSaver.
  261. //
  262. // plsForLoad is intended to be used with nested struct fields which
  263. // may implement PropertyLoadSaver.
  264. //
  265. // v must be settable.
  266. func plsForLoad(v reflect.Value) (PropertyLoadSaver, error) {
  267. var nilPtr bool
  268. if v.Kind() == reflect.Ptr && v.IsNil() {
  269. nilPtr = true
  270. v.Set(reflect.New(v.Type().Elem()))
  271. }
  272. vpls, err := pls(v)
  273. if nilPtr && (vpls == nil || err != nil) {
  274. // unset v
  275. v.Set(reflect.Zero(v.Type()))
  276. }
  277. return vpls, err
  278. }
  279. // plsForSave tries to convert v to a PropertyLoadSaver.
  280. // If successful, plsForSave returns v as a PropertyLoadSaver.
  281. //
  282. // plsForSave is intended to be used with nested struct fields which
  283. // may implement PropertyLoadSaver.
  284. //
  285. // v must be settable.
  286. func plsForSave(v reflect.Value) (PropertyLoadSaver, error) {
  287. switch v.Kind() {
  288. case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Interface, reflect.Chan, reflect.Func:
  289. // If v is nil, return early. v contains no data to save.
  290. if v.IsNil() {
  291. return nil, nil
  292. }
  293. }
  294. return pls(v)
  295. }
  296. func pls(v reflect.Value) (PropertyLoadSaver, error) {
  297. if v.Kind() != reflect.Ptr {
  298. if _, ok := v.Interface().(PropertyLoadSaver); ok {
  299. return nil, fmt.Errorf("datastore: PropertyLoadSaver methods must be implemented on a pointer to %T.", v.Interface())
  300. }
  301. v = v.Addr()
  302. }
  303. vpls, _ := v.Interface().(PropertyLoadSaver)
  304. return vpls, nil
  305. }