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.
 
 
 

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