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 }