1// Copyright 2011 Google Inc. All rights reserved. 2// Use of this source code is governed by the Apache 2.0 3// license that can be found in the LICENSE file. 4 5/* 6Package datastore provides a client for App Engine's datastore service. 7 8 9Basic Operations 10 11Entities are the unit of storage and are associated with a key. A key 12consists of an optional parent key, a string application ID, a string kind 13(also known as an entity type), and either a StringID or an IntID. A 14StringID is also known as an entity name or key name. 15 16It is valid to create a key with a zero StringID and a zero IntID; this is 17called an incomplete key, and does not refer to any saved entity. Putting an 18entity into the datastore under an incomplete key will cause a unique key 19to be generated for that entity, with a non-zero IntID. 20 21An entity's contents are a mapping from case-sensitive field names to values. 22Valid value types are: 23 - signed integers (int, int8, int16, int32 and int64), 24 - bool, 25 - string, 26 - float32 and float64, 27 - []byte (up to 1 megabyte in length), 28 - any type whose underlying type is one of the above predeclared types, 29 - ByteString, 30 - *Key, 31 - time.Time (stored with microsecond precision), 32 - appengine.BlobKey, 33 - appengine.GeoPoint, 34 - structs whose fields are all valid value types, 35 - slices of any of the above. 36 37Slices of structs are valid, as are structs that contain slices. However, if 38one struct contains another, then at most one of those can be repeated. This 39disqualifies recursively defined struct types: any struct T that (directly or 40indirectly) contains a []T. 41 42The Get and Put functions load and save an entity's contents. An entity's 43contents are typically represented by a struct pointer. 44 45Example code: 46 47 type Entity struct { 48 Value string 49 } 50 51 func handle(w http.ResponseWriter, r *http.Request) { 52 ctx := appengine.NewContext(r) 53 54 k := datastore.NewKey(ctx, "Entity", "stringID", 0, nil) 55 e := new(Entity) 56 if err := datastore.Get(ctx, k, e); err != nil { 57 http.Error(w, err.Error(), 500) 58 return 59 } 60 61 old := e.Value 62 e.Value = r.URL.Path 63 64 if _, err := datastore.Put(ctx, k, e); err != nil { 65 http.Error(w, err.Error(), 500) 66 return 67 } 68 69 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 70 fmt.Fprintf(w, "old=%q\nnew=%q\n", old, e.Value) 71 } 72 73GetMulti, PutMulti and DeleteMulti are batch versions of the Get, Put and 74Delete functions. They take a []*Key instead of a *Key, and may return an 75appengine.MultiError when encountering partial failure. 76 77 78Properties 79 80An entity's contents can be represented by a variety of types. These are 81typically struct pointers, but can also be any type that implements the 82PropertyLoadSaver interface. If using a struct pointer, you do not have to 83explicitly implement the PropertyLoadSaver interface; the datastore will 84automatically convert via reflection. If a struct pointer does implement that 85interface then those methods will be used in preference to the default 86behavior for struct pointers. Struct pointers are more strongly typed and are 87easier to use; PropertyLoadSavers are more flexible. 88 89The actual types passed do not have to match between Get and Put calls or even 90across different calls to datastore. It is valid to put a *PropertyList and 91get that same entity as a *myStruct, or put a *myStruct0 and get a *myStruct1. 92Conceptually, any entity is saved as a sequence of properties, and is loaded 93into the destination value on a property-by-property basis. When loading into 94a struct pointer, an entity that cannot be completely represented (such as a 95missing field) will result in an ErrFieldMismatch error but it is up to the 96caller whether this error is fatal, recoverable or ignorable. 97 98By default, for struct pointers, all properties are potentially indexed, and 99the property name is the same as the field name (and hence must start with an 100upper case letter). 101 102Fields may have a `datastore:"name,options"` tag. The tag name is the 103property name, which must be one or more valid Go identifiers joined by ".", 104but may start with a lower case letter. An empty tag name means to just use the 105field name. A "-" tag name means that the datastore will ignore that field. 106 107The only valid options are "omitempty" and "noindex". 108 109If the options include "omitempty" and the value of the field is empty, then the field will be omitted on Save. 110The empty values are false, 0, any nil interface value, and any array, slice, map, or string of length zero. 111Struct field values will never be empty. 112 113If options include "noindex" then the field will not be indexed. All fields are indexed 114by default. Strings or byte slices longer than 1500 bytes cannot be indexed; 115fields used to store long strings and byte slices must be tagged with "noindex" 116or they will cause Put operations to fail. 117 118To use multiple options together, separate them by a comma. 119The order does not matter. 120 121If the options is "" then the comma may be omitted. 122 123Example code: 124 125 // A and B are renamed to a and b. 126 // A, C and J are not indexed. 127 // D's tag is equivalent to having no tag at all (E). 128 // I is ignored entirely by the datastore. 129 // J has tag information for both the datastore and json packages. 130 type TaggedStruct struct { 131 A int `datastore:"a,noindex"` 132 B int `datastore:"b"` 133 C int `datastore:",noindex"` 134 D int `datastore:""` 135 E int 136 I int `datastore:"-"` 137 J int `datastore:",noindex" json:"j"` 138 } 139 140 141Structured Properties 142 143If the struct pointed to contains other structs, then the nested or embedded 144structs are flattened. For example, given these definitions: 145 146 type Inner1 struct { 147 W int32 148 X string 149 } 150 151 type Inner2 struct { 152 Y float64 153 } 154 155 type Inner3 struct { 156 Z bool 157 } 158 159 type Outer struct { 160 A int16 161 I []Inner1 162 J Inner2 163 Inner3 164 } 165 166then an Outer's properties would be equivalent to those of: 167 168 type OuterEquivalent struct { 169 A int16 170 IDotW []int32 `datastore:"I.W"` 171 IDotX []string `datastore:"I.X"` 172 JDotY float64 `datastore:"J.Y"` 173 Z bool 174 } 175 176If Outer's embedded Inner3 field was tagged as `datastore:"Foo"` then the 177equivalent field would instead be: FooDotZ bool `datastore:"Foo.Z"`. 178 179If an outer struct is tagged "noindex" then all of its implicit flattened 180fields are effectively "noindex". 181 182 183The PropertyLoadSaver Interface 184 185An entity's contents can also be represented by any type that implements the 186PropertyLoadSaver interface. This type may be a struct pointer, but it does 187not have to be. The datastore package will call Load when getting the entity's 188contents, and Save when putting the entity's contents. 189Possible uses include deriving non-stored fields, verifying fields, or indexing 190a field only if its value is positive. 191 192Example code: 193 194 type CustomPropsExample struct { 195 I, J int 196 // Sum is not stored, but should always be equal to I + J. 197 Sum int `datastore:"-"` 198 } 199 200 func (x *CustomPropsExample) Load(ps []datastore.Property) error { 201 // Load I and J as usual. 202 if err := datastore.LoadStruct(x, ps); err != nil { 203 return err 204 } 205 // Derive the Sum field. 206 x.Sum = x.I + x.J 207 return nil 208 } 209 210 func (x *CustomPropsExample) Save() ([]datastore.Property, error) { 211 // Validate the Sum field. 212 if x.Sum != x.I + x.J { 213 return nil, errors.New("CustomPropsExample has inconsistent sum") 214 } 215 // Save I and J as usual. The code below is equivalent to calling 216 // "return datastore.SaveStruct(x)", but is done manually for 217 // demonstration purposes. 218 return []datastore.Property{ 219 { 220 Name: "I", 221 Value: int64(x.I), 222 }, 223 { 224 Name: "J", 225 Value: int64(x.J), 226 }, 227 }, nil 228 } 229 230The *PropertyList type implements PropertyLoadSaver, and can therefore hold an 231arbitrary entity's contents. 232 233 234Queries 235 236Queries retrieve entities based on their properties or key's ancestry. Running 237a query yields an iterator of results: either keys or (key, entity) pairs. 238Queries are re-usable and it is safe to call Query.Run from concurrent 239goroutines. Iterators are not safe for concurrent use. 240 241Queries are immutable, and are either created by calling NewQuery, or derived 242from an existing query by calling a method like Filter or Order that returns a 243new query value. A query is typically constructed by calling NewQuery followed 244by a chain of zero or more such methods. These methods are: 245 - Ancestor and Filter constrain the entities returned by running a query. 246 - Order affects the order in which they are returned. 247 - Project constrains the fields returned. 248 - Distinct de-duplicates projected entities. 249 - KeysOnly makes the iterator return only keys, not (key, entity) pairs. 250 - Start, End, Offset and Limit define which sub-sequence of matching entities 251 to return. Start and End take cursors, Offset and Limit take integers. Start 252 and Offset affect the first result, End and Limit affect the last result. 253 If both Start and Offset are set, then the offset is relative to Start. 254 If both End and Limit are set, then the earliest constraint wins. Limit is 255 relative to Start+Offset, not relative to End. As a special case, a 256 negative limit means unlimited. 257 258Example code: 259 260 type Widget struct { 261 Description string 262 Price int 263 } 264 265 func handle(w http.ResponseWriter, r *http.Request) { 266 ctx := appengine.NewContext(r) 267 q := datastore.NewQuery("Widget"). 268 Filter("Price <", 1000). 269 Order("-Price") 270 b := new(bytes.Buffer) 271 for t := q.Run(ctx); ; { 272 var x Widget 273 key, err := t.Next(&x) 274 if err == datastore.Done { 275 break 276 } 277 if err != nil { 278 serveError(ctx, w, err) 279 return 280 } 281 fmt.Fprintf(b, "Key=%v\nWidget=%#v\n\n", key, x) 282 } 283 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 284 io.Copy(w, b) 285 } 286 287 288Transactions 289 290RunInTransaction runs a function in a transaction. 291 292Example code: 293 294 type Counter struct { 295 Count int 296 } 297 298 func inc(ctx context.Context, key *datastore.Key) (int, error) { 299 var x Counter 300 if err := datastore.Get(ctx, key, &x); err != nil && err != datastore.ErrNoSuchEntity { 301 return 0, err 302 } 303 x.Count++ 304 if _, err := datastore.Put(ctx, key, &x); err != nil { 305 return 0, err 306 } 307 return x.Count, nil 308 } 309 310 func handle(w http.ResponseWriter, r *http.Request) { 311 ctx := appengine.NewContext(r) 312 var count int 313 err := datastore.RunInTransaction(ctx, func(ctx context.Context) error { 314 var err1 error 315 count, err1 = inc(ctx, datastore.NewKey(ctx, "Counter", "singleton", 0, nil)) 316 return err1 317 }, nil) 318 if err != nil { 319 serveError(ctx, w, err) 320 return 321 } 322 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 323 fmt.Fprintf(w, "Count=%d", count) 324 } 325 326 327Metadata 328 329The datastore package provides access to some of App Engine's datastore 330metadata. This metadata includes information about the entity groups, 331namespaces, entity kinds, and properties in the datastore, as well as the 332property representations for each property. 333 334Example code: 335 336 func handle(w http.ResponseWriter, r *http.Request) { 337 // Print all the kinds in the datastore, with all the indexed 338 // properties (and their representations) for each. 339 ctx := appengine.NewContext(r) 340 341 kinds, err := datastore.Kinds(ctx) 342 if err != nil { 343 serveError(ctx, w, err) 344 return 345 } 346 347 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 348 for _, kind := range kinds { 349 fmt.Fprintf(w, "%s:\n", kind) 350 props, err := datastore.KindProperties(ctx, kind) 351 if err != nil { 352 fmt.Fprintln(w, "\t(unable to retrieve properties)") 353 continue 354 } 355 for p, rep := range props { 356 fmt.Fprintf(w, "\t-%s (%s)\n", p, strings.Join(rep, ", ")) 357 } 358 } 359 } 360*/ 361package datastore 362