blob: b819dd9318bd2660c6fa0580053e2e2a2b1916ee [file] [log] [blame]
// 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}]
}