github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/google.golang.org/appengine/datastore/doc.go (about) 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 /* 6 Package datastore provides a client for App Engine's datastore service. 7 8 9 Basic Operations 10 11 Entities are the unit of storage and are associated with a key. A key 12 consists 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 14 StringID is also known as an entity name or key name. 15 16 It is valid to create a key with a zero StringID and a zero IntID; this is 17 called an incomplete key, and does not refer to any saved entity. Putting an 18 entity into the datastore under an incomplete key will cause a unique key 19 to be generated for that entity, with a non-zero IntID. 20 21 An entity's contents are a mapping from case-sensitive field names to values. 22 Valid 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 37 Slices of structs are valid, as are structs that contain slices. However, if 38 one struct contains another, then at most one of those can be repeated. This 39 disqualifies recursively defined struct types: any struct T that (directly or 40 indirectly) contains a []T. 41 42 The Get and Put functions load and save an entity's contents. An entity's 43 contents are typically represented by a struct pointer. 44 45 Example 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 73 GetMulti, PutMulti and DeleteMulti are batch versions of the Get, Put and 74 Delete functions. They take a []*Key instead of a *Key, and may return an 75 appengine.MultiError when encountering partial failure. 76 77 78 Properties 79 80 An entity's contents can be represented by a variety of types. These are 81 typically struct pointers, but can also be any type that implements the 82 PropertyLoadSaver interface. If using a struct pointer, you do not have to 83 explicitly implement the PropertyLoadSaver interface; the datastore will 84 automatically convert via reflection. If a struct pointer does implement that 85 interface then those methods will be used in preference to the default 86 behavior for struct pointers. Struct pointers are more strongly typed and are 87 easier to use; PropertyLoadSavers are more flexible. 88 89 The actual types passed do not have to match between Get and Put calls or even 90 across different App Engine requests. It is valid to put a *PropertyList and 91 get that same entity as a *myStruct, or put a *myStruct0 and get a *myStruct1. 92 Conceptually, any entity is saved as a sequence of properties, and is loaded 93 into the destination value on a property-by-property basis. When loading into 94 a struct pointer, an entity that cannot be completely represented (such as a 95 missing field) will result in an ErrFieldMismatch error but it is up to the 96 caller whether this error is fatal, recoverable or ignorable. 97 98 By default, for struct pointers, all properties are potentially indexed, and 99 the property name is the same as the field name (and hence must start with an 100 upper case letter). Fields may have a `datastore:"name,options"` tag. The tag 101 name is the property name, which must be one or more valid Go identifiers 102 joined by ".", but may start with a lower case letter. An empty tag name means 103 to just use the field name. A "-" tag name means that the datastore will 104 ignore that field. If options is "noindex" then the field will not be indexed. 105 If the options is "" then the comma may be omitted. There are no other 106 recognized options. 107 108 Fields (except for []byte) are indexed by default. Strings longer than 1500 109 bytes cannot be indexed; fields used to store long strings should be 110 tagged with "noindex". Similarly, ByteStrings longer than 1500 bytes cannot be 111 indexed. 112 113 Example code: 114 115 // A and B are renamed to a and b. 116 // A, C and J are not indexed. 117 // D's tag is equivalent to having no tag at all (E). 118 // I is ignored entirely by the datastore. 119 // J has tag information for both the datastore and json packages. 120 type TaggedStruct struct { 121 A int `datastore:"a,noindex"` 122 B int `datastore:"b"` 123 C int `datastore:",noindex"` 124 D int `datastore:""` 125 E int 126 I int `datastore:"-"` 127 J int `datastore:",noindex" json:"j"` 128 } 129 130 131 Structured Properties 132 133 If the struct pointed to contains other structs, then the nested or embedded 134 structs are flattened. For example, given these definitions: 135 136 type Inner1 struct { 137 W int32 138 X string 139 } 140 141 type Inner2 struct { 142 Y float64 143 } 144 145 type Inner3 struct { 146 Z bool 147 } 148 149 type Outer struct { 150 A int16 151 I []Inner1 152 J Inner2 153 Inner3 154 } 155 156 then an Outer's properties would be equivalent to those of: 157 158 type OuterEquivalent struct { 159 A int16 160 IDotW []int32 `datastore:"I.W"` 161 IDotX []string `datastore:"I.X"` 162 JDotY float64 `datastore:"J.Y"` 163 Z bool 164 } 165 166 If Outer's embedded Inner3 field was tagged as `datastore:"Foo"` then the 167 equivalent field would instead be: FooDotZ bool `datastore:"Foo.Z"`. 168 169 If an outer struct is tagged "noindex" then all of its implicit flattened 170 fields are effectively "noindex". 171 172 173 The PropertyLoadSaver Interface 174 175 An entity's contents can also be represented by any type that implements the 176 PropertyLoadSaver interface. This type may be a struct pointer, but it does 177 not have to be. The datastore package will call Load when getting the entity's 178 contents, and Save when putting the entity's contents. 179 Possible uses include deriving non-stored fields, verifying fields, or indexing 180 a field only if its value is positive. 181 182 Example code: 183 184 type CustomPropsExample struct { 185 I, J int 186 // Sum is not stored, but should always be equal to I + J. 187 Sum int `datastore:"-"` 188 } 189 190 func (x *CustomPropsExample) Load(ps []datastore.Property) error { 191 // Load I and J as usual. 192 if err := datastore.LoadStruct(x, ps); err != nil { 193 return err 194 } 195 // Derive the Sum field. 196 x.Sum = x.I + x.J 197 return nil 198 } 199 200 func (x *CustomPropsExample) Save() ([]datastore.Property, error) { 201 // Validate the Sum field. 202 if x.Sum != x.I + x.J { 203 return errors.New("CustomPropsExample has inconsistent sum") 204 } 205 // Save I and J as usual. The code below is equivalent to calling 206 // "return datastore.SaveStruct(x)", but is done manually for 207 // demonstration purposes. 208 return []datastore.Property{ 209 { 210 Name: "I", 211 Value: int64(x.I), 212 }, 213 { 214 Name: "J", 215 Value: int64(x.J), 216 }, 217 } 218 } 219 220 The *PropertyList type implements PropertyLoadSaver, and can therefore hold an 221 arbitrary entity's contents. 222 223 224 Queries 225 226 Queries retrieve entities based on their properties or key's ancestry. Running 227 a query yields an iterator of results: either keys or (key, entity) pairs. 228 Queries are re-usable and it is safe to call Query.Run from concurrent 229 goroutines. Iterators are not safe for concurrent use. 230 231 Queries are immutable, and are either created by calling NewQuery, or derived 232 from an existing query by calling a method like Filter or Order that returns a 233 new query value. A query is typically constructed by calling NewQuery followed 234 by a chain of zero or more such methods. These methods are: 235 - Ancestor and Filter constrain the entities returned by running a query. 236 - Order affects the order in which they are returned. 237 - Project constrains the fields returned. 238 - Distinct de-duplicates projected entities. 239 - KeysOnly makes the iterator return only keys, not (key, entity) pairs. 240 - Start, End, Offset and Limit define which sub-sequence of matching entities 241 to return. Start and End take cursors, Offset and Limit take integers. Start 242 and Offset affect the first result, End and Limit affect the last result. 243 If both Start and Offset are set, then the offset is relative to Start. 244 If both End and Limit are set, then the earliest constraint wins. Limit is 245 relative to Start+Offset, not relative to End. As a special case, a 246 negative limit means unlimited. 247 248 Example code: 249 250 type Widget struct { 251 Description string 252 Price int 253 } 254 255 func handle(w http.ResponseWriter, r *http.Request) { 256 ctx := appengine.NewContext(r) 257 q := datastore.NewQuery("Widget"). 258 Filter("Price <", 1000). 259 Order("-Price") 260 b := new(bytes.Buffer) 261 for t := q.Run(ctx); ; { 262 var x Widget 263 key, err := t.Next(&x) 264 if err == datastore.Done { 265 break 266 } 267 if err != nil { 268 serveError(ctx, w, err) 269 return 270 } 271 fmt.Fprintf(b, "Key=%v\nWidget=%#v\n\n", key, x) 272 } 273 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 274 io.Copy(w, b) 275 } 276 277 278 Transactions 279 280 RunInTransaction runs a function in a transaction. 281 282 Example code: 283 284 type Counter struct { 285 Count int 286 } 287 288 func inc(ctx context.Context, key *datastore.Key) (int, error) { 289 var x Counter 290 if err := datastore.Get(ctx, key, &x); err != nil && err != datastore.ErrNoSuchEntity { 291 return 0, err 292 } 293 x.Count++ 294 if _, err := datastore.Put(ctx, key, &x); err != nil { 295 return 0, err 296 } 297 return x.Count, nil 298 } 299 300 func handle(w http.ResponseWriter, r *http.Request) { 301 ctx := appengine.NewContext(r) 302 var count int 303 err := datastore.RunInTransaction(ctx, func(ctx context.Context) error { 304 var err1 error 305 count, err1 = inc(ctx, datastore.NewKey(ctx, "Counter", "singleton", 0, nil)) 306 return err1 307 }, nil) 308 if err != nil { 309 serveError(ctx, w, err) 310 return 311 } 312 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 313 fmt.Fprintf(w, "Count=%d", count) 314 } 315 */ 316 package datastore