| // Copyright 2014 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package datastore_test |
| |
| import ( |
| "context" |
| "fmt" |
| "log" |
| "time" |
| |
| "cloud.google.com/go/datastore" |
| "google.golang.org/api/iterator" |
| ) |
| |
| func ExampleNewClient() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| _ = client // TODO: Use client. |
| } |
| |
| func ExampleClient_Get() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| |
| type Article struct { |
| Title string |
| Description string |
| Body string `datastore:",noindex"` |
| Author *datastore.Key |
| PublishedAt time.Time |
| } |
| key := datastore.NameKey("Article", "articled1", nil) |
| article := &Article{} |
| if err := client.Get(ctx, key, article); err != nil { |
| // TODO: Handle error. |
| } |
| } |
| |
| func ExampleClient_Put() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| |
| type Article struct { |
| Title string |
| Description string |
| Body string `datastore:",noindex"` |
| Author *datastore.Key |
| PublishedAt time.Time |
| } |
| newKey := datastore.IncompleteKey("Article", nil) |
| _, err = client.Put(ctx, newKey, &Article{ |
| Title: "The title of the article", |
| Description: "The description of the article...", |
| Body: "...", |
| Author: datastore.NameKey("Author", "jbd", nil), |
| PublishedAt: time.Now(), |
| }) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| } |
| |
| func ExampleClient_Put_flatten() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| log.Fatal(err) |
| } |
| |
| type Animal struct { |
| Name string |
| Type string |
| Breed string |
| } |
| |
| type Human struct { |
| Name string |
| Height int |
| Pet Animal `datastore:",flatten"` |
| } |
| |
| newKey := datastore.IncompleteKey("Human", nil) |
| _, err = client.Put(ctx, newKey, &Human{ |
| Name: "Susan", |
| Height: 67, |
| Pet: Animal{ |
| Name: "Fluffy", |
| Type: "Cat", |
| Breed: "Sphynx", |
| }, |
| }) |
| if err != nil { |
| log.Fatal(err) |
| } |
| } |
| |
| func ExampleClient_Delete() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| |
| key := datastore.NameKey("Article", "articled1", nil) |
| if err := client.Delete(ctx, key); err != nil { |
| // TODO: Handle error. |
| } |
| } |
| |
| func ExampleClient_DeleteMulti() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| var keys []*datastore.Key |
| for i := 1; i <= 10; i++ { |
| keys = append(keys, datastore.IDKey("Article", int64(i), nil)) |
| } |
| if err := client.DeleteMulti(ctx, keys); err != nil { |
| // TODO: Handle error. |
| } |
| } |
| |
| type Post struct { |
| Title string |
| PublishedAt time.Time |
| Comments int |
| } |
| |
| func ExampleClient_GetMulti() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| |
| keys := []*datastore.Key{ |
| datastore.NameKey("Post", "post1", nil), |
| datastore.NameKey("Post", "post2", nil), |
| datastore.NameKey("Post", "post3", nil), |
| } |
| posts := make([]Post, 3) |
| if err := client.GetMulti(ctx, keys, posts); err != nil { |
| // TODO: Handle error. |
| } |
| } |
| |
| func ExampleMultiError() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| |
| keys := []*datastore.Key{ |
| datastore.NameKey("bad-key", "bad-key", nil), |
| } |
| posts := make([]Post, 1) |
| if err := client.GetMulti(ctx, keys, posts); err != nil { |
| if merr, ok := err.(datastore.MultiError); ok { |
| for _, err := range merr { |
| // TODO: Handle error. |
| _ = err |
| } |
| } else { |
| // TODO: Handle error. |
| } |
| } |
| } |
| |
| func ExampleClient_PutMulti_slice() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| |
| keys := []*datastore.Key{ |
| datastore.NameKey("Post", "post1", nil), |
| datastore.NameKey("Post", "post2", nil), |
| } |
| |
| // PutMulti with a Post slice. |
| posts := []*Post{ |
| {Title: "Post 1", PublishedAt: time.Now()}, |
| {Title: "Post 2", PublishedAt: time.Now()}, |
| } |
| if _, err := client.PutMulti(ctx, keys, posts); err != nil { |
| // TODO: Handle error. |
| } |
| } |
| |
| func ExampleClient_PutMulti_interfaceSlice() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| |
| keys := []*datastore.Key{ |
| datastore.NameKey("Post", "post1", nil), |
| datastore.NameKey("Post", "post2", nil), |
| } |
| |
| // PutMulti with an empty interface slice. |
| posts := []interface{}{ |
| &Post{Title: "Post 1", PublishedAt: time.Now()}, |
| &Post{Title: "Post 2", PublishedAt: time.Now()}, |
| } |
| if _, err := client.PutMulti(ctx, keys, posts); err != nil { |
| // TODO: Handle error. |
| } |
| } |
| |
| func ExampleNewQuery() { |
| // Query for Post entities. |
| q := datastore.NewQuery("Post") |
| _ = q // TODO: Use the query with Client.Run. |
| } |
| |
| func ExampleNewQuery_options() { |
| // Query to order the posts by the number of comments they have received. |
| q := datastore.NewQuery("Post").Order("-Comments") |
| // Start listing from an offset and limit the results. |
| q = q.Offset(20).Limit(10) |
| _ = q // TODO: Use the query. |
| } |
| |
| func ExampleClient_Count() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| // Count the number of the post entities. |
| q := datastore.NewQuery("Post") |
| n, err := client.Count(ctx, q) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| fmt.Printf("There are %d posts.", n) |
| } |
| |
| func ExampleClient_Run() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| // List the posts published since yesterday. |
| yesterday := time.Now().Add(-24 * time.Hour) |
| q := datastore.NewQuery("Post").Filter("PublishedAt >", yesterday) |
| it := client.Run(ctx, q) |
| _ = it // TODO: iterate using Next. |
| } |
| |
| func ExampleClient_NewTransaction() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| const retries = 3 |
| |
| // Increment a counter. |
| // See https://cloud.google.com/appengine/articles/sharding_counters for |
| // a more scalable solution. |
| type Counter struct { |
| Count int |
| } |
| |
| key := datastore.NameKey("counter", "CounterA", nil) |
| var tx *datastore.Transaction |
| for i := 0; i < retries; i++ { |
| tx, err = client.NewTransaction(ctx) |
| if err != nil { |
| break |
| } |
| |
| var c Counter |
| if err = tx.Get(key, &c); err != nil && err != datastore.ErrNoSuchEntity { |
| break |
| } |
| c.Count++ |
| if _, err = tx.Put(key, &c); err != nil { |
| break |
| } |
| |
| // Attempt to commit the transaction. If there's a conflict, try again. |
| if _, err = tx.Commit(); err != datastore.ErrConcurrentTransaction { |
| break |
| } |
| } |
| if err != nil { |
| // TODO: Handle error. |
| } |
| } |
| |
| func ExampleClient_RunInTransaction() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| |
| // Increment a counter. |
| // See https://cloud.google.com/appengine/articles/sharding_counters for |
| // a more scalable solution. |
| type Counter struct { |
| Count int |
| } |
| |
| var count int |
| key := datastore.NameKey("Counter", "singleton", nil) |
| _, err = client.RunInTransaction(ctx, func(tx *datastore.Transaction) error { |
| var x Counter |
| if err := tx.Get(key, &x); err != nil && err != datastore.ErrNoSuchEntity { |
| return err |
| } |
| x.Count++ |
| if _, err := tx.Put(key, &x); err != nil { |
| return err |
| } |
| count = x.Count |
| return nil |
| }) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| // The value of count is only valid once the transaction is successful |
| // (RunInTransaction has returned nil). |
| fmt.Printf("Count=%d\n", count) |
| } |
| |
| func ExampleClient_AllocateIDs() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| var keys []*datastore.Key |
| for i := 0; i < 10; i++ { |
| keys = append(keys, datastore.IncompleteKey("Article", nil)) |
| } |
| keys, err = client.AllocateIDs(ctx, keys) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| _ = keys // TODO: Use keys. |
| } |
| |
| func ExampleKey_Encode() { |
| key := datastore.IDKey("Article", 1, nil) |
| encoded := key.Encode() |
| fmt.Println(encoded) |
| // Output: EgsKB0FydGljbGUQAQ |
| } |
| |
| func ExampleDecodeKey() { |
| const encoded = "EgsKB0FydGljbGUQAQ" |
| key, err := datastore.DecodeKey(encoded) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| fmt.Println(key) |
| // Output: /Article,1 |
| } |
| |
| func ExampleIDKey() { |
| // Key with numeric ID. |
| k := datastore.IDKey("Article", 1, nil) |
| _ = k // TODO: Use key. |
| } |
| |
| func ExampleNameKey() { |
| // Key with string ID. |
| k := datastore.NameKey("Article", "article8", nil) |
| _ = k // TODO: Use key. |
| } |
| |
| func ExampleIncompleteKey() { |
| k := datastore.IncompleteKey("Article", nil) |
| _ = k // TODO: Use incomplete key. |
| } |
| |
| func ExampleClient_GetAll() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| var posts []*Post |
| keys, err := client.GetAll(ctx, datastore.NewQuery("Post"), &posts) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| for i, key := range keys { |
| fmt.Println(key) |
| fmt.Println(posts[i]) |
| } |
| } |
| |
| func ExampleClient_Mutate() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| |
| key1 := datastore.NameKey("Post", "post1", nil) |
| key2 := datastore.NameKey("Post", "post2", nil) |
| key3 := datastore.NameKey("Post", "post3", nil) |
| key4 := datastore.NameKey("Post", "post4", nil) |
| |
| _, err = client.Mutate(ctx, |
| datastore.NewInsert(key1, Post{Title: "Post 1"}), |
| datastore.NewUpsert(key2, Post{Title: "Post 2"}), |
| datastore.NewUpdate(key3, Post{Title: "Post 3"}), |
| datastore.NewDelete(key4)) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| } |
| |
| func ExampleCommit_Key() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| var pk1, pk2 *datastore.PendingKey |
| // Create two posts in a single transaction. |
| commit, err := client.RunInTransaction(ctx, func(tx *datastore.Transaction) error { |
| var err error |
| pk1, err = tx.Put(datastore.IncompleteKey("Post", nil), &Post{Title: "Post 1", PublishedAt: time.Now()}) |
| if err != nil { |
| return err |
| } |
| pk2, err = tx.Put(datastore.IncompleteKey("Post", nil), &Post{Title: "Post 2", PublishedAt: time.Now()}) |
| if err != nil { |
| return err |
| } |
| return nil |
| }) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| // Now pk1, pk2 are valid PendingKeys. Let's convert them into real keys |
| // using the Commit object. |
| k1 := commit.Key(pk1) |
| k2 := commit.Key(pk2) |
| fmt.Println(k1, k2) |
| } |
| |
| func ExampleIterator_Next() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| it := client.Run(ctx, datastore.NewQuery("Post")) |
| for { |
| var p Post |
| key, err := it.Next(&p) |
| if err == iterator.Done { |
| break |
| } |
| if err != nil { |
| // TODO: Handle error. |
| } |
| fmt.Println(key, p) |
| } |
| } |
| |
| func ExampleIterator_Cursor() { |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| it := client.Run(ctx, datastore.NewQuery("Post")) |
| for { |
| var p Post |
| _, err := it.Next(&p) |
| if err == iterator.Done { |
| break |
| } |
| if err != nil { |
| // TODO: Handle error. |
| } |
| fmt.Println(p) |
| cursor, err := it.Cursor() |
| if err != nil { |
| // TODO: Handle error. |
| } |
| // When printed, a cursor will display as a string that can be passed |
| // to datastore.DecodeCursor. |
| fmt.Printf("to resume with this post, use cursor %s\n", cursor) |
| } |
| } |
| |
| func ExampleDecodeCursor() { |
| // See Query.Start for a fuller example of DecodeCursor. |
| // getCursor represents a function that returns a cursor from a previous |
| // iteration in string form. |
| cursorString := getCursor() |
| cursor, err := datastore.DecodeCursor(cursorString) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| _ = cursor // TODO: Use the cursor with Query.Start or Query.End. |
| } |
| |
| func getCursor() string { return "" } |
| |
| func ExampleQuery_Start() { |
| // This example demonstrates how to use cursors and Query.Start |
| // to resume an iteration. |
| ctx := context.Background() |
| client, err := datastore.NewClient(ctx, "project-id") |
| if err != nil { |
| // TODO: Handle error. |
| } |
| // getCursor represents a function that returns a cursor from a previous |
| // iteration in string form. |
| cursorString := getCursor() |
| cursor, err := datastore.DecodeCursor(cursorString) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| it := client.Run(ctx, datastore.NewQuery("Post").Start(cursor)) |
| _ = it // TODO: Use iterator. |
| } |
| |
| func ExampleLoadStruct() { |
| type Player struct { |
| User string |
| Score int |
| } |
| // Normally LoadStruct would only be used inside a custom implementation of |
| // PropertyLoadSaver; this is for illustrative purposes only. |
| props := []datastore.Property{ |
| {Name: "User", Value: "Alice"}, |
| {Name: "Score", Value: int64(97)}, |
| } |
| |
| var p Player |
| if err := datastore.LoadStruct(&p, props); err != nil { |
| // TODO: Handle error. |
| } |
| fmt.Println(p) |
| // Output: {Alice 97} |
| } |
| |
| func ExampleSaveStruct() { |
| type Player struct { |
| User string |
| Score int |
| } |
| |
| p := &Player{ |
| User: "Alice", |
| Score: 97, |
| } |
| props, err := datastore.SaveStruct(p) |
| if err != nil { |
| // TODO: Handle error. |
| } |
| fmt.Println(props) |
| // TODO(jba): make this output stable: Output: [{User Alice false} {Score 97 false}] |
| } |