github.com/thiagoyeds/go-cloud@v0.26.0/docstore/example_test.go (about)

     1  // Copyright 2019 The Go Cloud Development Kit Authors
     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  //     https://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  
    15  package docstore_test
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"io"
    21  	"log"
    22  	"time"
    23  
    24  	firestore "cloud.google.com/go/firestore/apiv1"
    25  	"github.com/aws/aws-sdk-go/aws/awserr"
    26  	"gocloud.dev/docstore"
    27  	_ "gocloud.dev/docstore/awsdynamodb"
    28  	_ "gocloud.dev/docstore/gcpfirestore"
    29  	"gocloud.dev/docstore/memdocstore"
    30  	"gocloud.dev/gcerrors"
    31  )
    32  
    33  type Player struct {
    34  	Name             string
    35  	Score            int
    36  	DocstoreRevision interface{}
    37  }
    38  
    39  func ExampleCollection_Actions_bulkWrite() {
    40  	// PRAGMA: This example is used on gocloud.dev; PRAGMA comments adjust how it is shown and can be ignored.
    41  	// PRAGMA: On gocloud.dev, hide lines until the next blank line.
    42  	ctx := context.Background()
    43  	var coll *docstore.Collection
    44  
    45  	// Build an ActionList to create several new players, then execute it.
    46  	// The actions may happen in any order.
    47  	newPlayers := []string{"Pat", "Mel", "Fran"}
    48  	actionList := coll.Actions()
    49  	for _, p := range newPlayers {
    50  		actionList.Create(&Player{Name: p, Score: 0})
    51  	}
    52  	if err := actionList.Do(ctx); err != nil {
    53  		log.Fatal(err)
    54  	}
    55  }
    56  
    57  func ExampleCollection_Actions_getAfterWrite() {
    58  	// PRAGMA: This example is used on gocloud.dev; PRAGMA comments adjust how it is shown and can be ignored.
    59  	// PRAGMA: On gocloud.dev, hide lines until the next blank line.
    60  	ctx := context.Background()
    61  	var coll *docstore.Collection
    62  
    63  	// Add a document to the collection, then retrieve it.
    64  	// Because both the Put and the Get refer to the same document,
    65  	// they happen in order.
    66  	got := Player{Name: "Pat"}
    67  	err := coll.Actions().Put(&Player{Name: "Pat", Score: 88}).Get(&got).Do(ctx)
    68  	if err != nil {
    69  		log.Fatal(err)
    70  	}
    71  	fmt.Println(got.Name, got.Score)
    72  }
    73  
    74  func ExampleCollection_Update() {
    75  	// PRAGMA: This example is used on gocloud.dev; PRAGMA comments adjust how it is shown and can be ignored.
    76  	// PRAGMA: On gocloud.dev, hide lines until the next blank line.
    77  	ctx := context.Background()
    78  	var coll *docstore.Collection
    79  
    80  	// Create a player.
    81  	pat := &Player{Name: "Pat", Score: 0}
    82  	if err := coll.Create(ctx, pat); err != nil {
    83  		log.Fatal(err)
    84  	}
    85  
    86  	// Set the score to a new value.
    87  	pat2 := &Player{Name: "Pat"}
    88  	err := coll.Actions().Update(pat, docstore.Mods{"Score": 15}).Get(pat2).Do(ctx)
    89  	if err != nil {
    90  		log.Fatal(err)
    91  	}
    92  
    93  	// Increment the score.
    94  	err = coll.Actions().Update(pat, docstore.Mods{"Score": docstore.Increment(5)}).Get(pat2).Do(ctx)
    95  	if err != nil {
    96  		log.Fatal(err)
    97  	}
    98  }
    99  
   100  func ExampleOpenCollection() {
   101  	ctx := context.Background()
   102  	// Open a collection using the gcpfirestore package.
   103  	// You will need to blank-import the package for this to work:
   104  	//   import _ "gocloud.dev/docstore/gcpfirestore"
   105  	coll, err := docstore.OpenCollection(ctx, "firestore://my-collection")
   106  	if err != nil {
   107  		log.Fatal(err)
   108  	}
   109  	defer coll.Close()
   110  
   111  	_ = coll // Use the collection.
   112  }
   113  
   114  func ExampleCollection_As() {
   115  	// This example is specific to the gcpfirestore implementation; it demonstrates
   116  	// access to the underlying *cloud.google.com/go/firestore/apiv1.Client.
   117  
   118  	// You will need to blank-import the package for this to work:
   119  	//   import _ "gocloud.dev/docstore/gcpfirestore"
   120  
   121  	// The types exposed for As by gcpfirestore are documented in
   122  	// https://godoc.org/gocloud.dev/docstore/gcpfirestore#hdr-As
   123  
   124  	// This URL will open the collection using default credentials.
   125  	ctx := context.Background()
   126  	coll, err := docstore.OpenCollection(ctx,
   127  		"firestore://projects/myproject/databases/(default)/documents/mycollection?name_field=myID")
   128  	if err != nil {
   129  		log.Fatal(err)
   130  	}
   131  	defer coll.Close()
   132  
   133  	// Try to access and use the underlying mongo.Collection.
   134  	var fsClient *firestore.Client
   135  	if coll.As(&fsClient) {
   136  		_ = fsClient // TODO: Use the client.
   137  	} else {
   138  		log.Println("Unable to access firestore.Client through Collection.As")
   139  	}
   140  }
   141  
   142  func ExampleCollection_ErrorAs() {
   143  	// This example is specific to the awsdynamodb implementation.
   144  	// You will need to blank-import the package for this to work:
   145  	//   import _ "gocloud.dev/docstore/awsdynamodb"
   146  
   147  	// The types exposed for As by mongodocstore are documented in
   148  	// https://godoc.org/gocloud.dev/docstore/mongodocstore#hdr-As
   149  
   150  	// This URL will open the collection using default credentials.
   151  	ctx := context.Background()
   152  	coll, err := docstore.OpenCollection(ctx, "dynamodb://mytable?partition_key=partkey")
   153  	if err != nil {
   154  		log.Fatal(err)
   155  	}
   156  	defer coll.Close()
   157  
   158  	doc := map[string]interface{}{"_id": "a"}
   159  	if err := coll.Create(ctx, doc); err != nil {
   160  		var aerr awserr.Error
   161  		if coll.ErrorAs(err, &aerr) {
   162  			fmt.Println("got", aerr)
   163  		} else {
   164  			fmt.Println("could not convert error")
   165  		}
   166  	}
   167  }
   168  
   169  func ExampleQuery_Get() {
   170  	// PRAGMA: This example is used on gocloud.dev; PRAGMA comments adjust how it is shown and can be ignored.
   171  	// PRAGMA: On gocloud.dev, hide lines until the next blank line.
   172  	ctx := context.Background()
   173  	var coll *docstore.Collection
   174  
   175  	// Ask for all players with scores at least 20.
   176  	iter := coll.Query().Where("Score", ">=", 20).OrderBy("Score", docstore.Descending).Get(ctx)
   177  	defer iter.Stop()
   178  
   179  	// Query.Get returns an iterator. Call Next on it until io.EOF.
   180  	for {
   181  		var p Player
   182  		err := iter.Next(ctx, &p)
   183  		if err == io.EOF {
   184  			break
   185  		} else if err != nil {
   186  			log.Fatal(err)
   187  		} else {
   188  			fmt.Printf("%s: %d\n", p.Name, p.Score)
   189  		}
   190  	}
   191  }
   192  
   193  func ExampleQuery_Get_full() {
   194  	ctx := context.Background()
   195  	coll, err := memdocstore.OpenCollection("Name", nil)
   196  	if err != nil {
   197  		log.Fatal(err)
   198  	}
   199  	defer coll.Close()
   200  
   201  	// Add some documents to the collection.
   202  	err = coll.Actions().
   203  		Put(&Player{Name: "Pat", Score: 10}).
   204  		Put(&Player{Name: "Mel", Score: 20}).
   205  		Put(&Player{Name: "Fran", Score: 30}).
   206  		Do(ctx)
   207  	if err != nil {
   208  		log.Fatal(err)
   209  	}
   210  
   211  	// Ask for all players with scores at least 20.
   212  	iter := coll.Query().Where("Score", ">=", 20).OrderBy("Score", docstore.Descending).Get(ctx)
   213  	defer iter.Stop()
   214  
   215  	// Query.Get returns an iterator. Call Next on it until io.EOF.
   216  	for {
   217  		var p Player
   218  		err := iter.Next(ctx, &p)
   219  		if err == io.EOF {
   220  			break
   221  		} else if err != nil {
   222  			log.Fatal(err)
   223  		} else {
   224  			fmt.Printf("%s: %d\n", p.Name, p.Score)
   225  		}
   226  	}
   227  
   228  	// Output:
   229  	// Fran: 30
   230  	// Mel: 20
   231  }
   232  
   233  func Example_optimisticLocking() {
   234  	// PRAGMA: This example is used on gocloud.dev; PRAGMA comments adjust how it is shown and can be ignored.
   235  	// PRAGMA: On gocloud.dev, hide lines until the next blank line.
   236  	ctx := context.Background()
   237  
   238  	coll, err := memdocstore.OpenCollection("Name", nil)
   239  	if err != nil {
   240  		log.Fatal(err)
   241  	}
   242  	defer coll.Close()
   243  
   244  	// Create a player.
   245  	pat := &Player{Name: "Pat", Score: 7}
   246  	if err := coll.Create(ctx, pat); err != nil {
   247  		log.Fatal(err)
   248  	}
   249  	fmt.Println(pat) // memdocstore revisions are deterministic, so we can check the output.
   250  
   251  	// Double a player's score. We cannot use Update to multiply, so we use optimistic
   252  	// locking instead.
   253  
   254  	// We may have to retry a few times; put a time limit on that.
   255  	ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
   256  	defer cancel()
   257  	for {
   258  		// Get the document.
   259  		player := &Player{Name: "Pat"}
   260  		if err := coll.Get(ctx, player); err != nil {
   261  			log.Fatal(err)
   262  		}
   263  		// player.DocstoreRevision is set to the document's revision.
   264  
   265  		// Modify the document locally.
   266  		player.Score *= 2
   267  
   268  		// Replace the document. player.DocstoreRevision will be checked against
   269  		// the stored document's revision.
   270  		err := coll.Replace(ctx, player)
   271  		if err != nil {
   272  			code := gcerrors.Code(err)
   273  			// On FailedPrecondition or NotFound, try again.
   274  			if code == gcerrors.FailedPrecondition || code == gcerrors.NotFound {
   275  				continue
   276  			}
   277  			log.Fatal(err)
   278  		}
   279  		fmt.Println(player)
   280  		break
   281  	}
   282  
   283  	// Output:
   284  	// &{Pat 7 1}
   285  	// &{Pat 14 2}
   286  }