You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

594 lines
14 KiB

  1. // Copyright 2014 Google LLC
  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. // http://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. package datastore_test
  15. import (
  16. "context"
  17. "fmt"
  18. "log"
  19. "time"
  20. "cloud.google.com/go/datastore"
  21. "google.golang.org/api/iterator"
  22. )
  23. func ExampleNewClient() {
  24. ctx := context.Background()
  25. client, err := datastore.NewClient(ctx, "project-id")
  26. if err != nil {
  27. // TODO: Handle error.
  28. }
  29. _ = client // TODO: Use client.
  30. }
  31. func ExampleClient_Get() {
  32. ctx := context.Background()
  33. client, err := datastore.NewClient(ctx, "project-id")
  34. if err != nil {
  35. // TODO: Handle error.
  36. }
  37. type Article struct {
  38. Title string
  39. Description string
  40. Body string `datastore:",noindex"`
  41. Author *datastore.Key
  42. PublishedAt time.Time
  43. }
  44. key := datastore.NameKey("Article", "articled1", nil)
  45. article := &Article{}
  46. if err := client.Get(ctx, key, article); err != nil {
  47. // TODO: Handle error.
  48. }
  49. }
  50. func ExampleClient_Put() {
  51. ctx := context.Background()
  52. client, err := datastore.NewClient(ctx, "project-id")
  53. if err != nil {
  54. // TODO: Handle error.
  55. }
  56. type Article struct {
  57. Title string
  58. Description string
  59. Body string `datastore:",noindex"`
  60. Author *datastore.Key
  61. PublishedAt time.Time
  62. }
  63. newKey := datastore.IncompleteKey("Article", nil)
  64. _, err = client.Put(ctx, newKey, &Article{
  65. Title: "The title of the article",
  66. Description: "The description of the article...",
  67. Body: "...",
  68. Author: datastore.NameKey("Author", "jbd", nil),
  69. PublishedAt: time.Now(),
  70. })
  71. if err != nil {
  72. // TODO: Handle error.
  73. }
  74. }
  75. func ExampleClient_Put_flatten() {
  76. ctx := context.Background()
  77. client, err := datastore.NewClient(ctx, "project-id")
  78. if err != nil {
  79. log.Fatal(err)
  80. }
  81. type Animal struct {
  82. Name string
  83. Type string
  84. Breed string
  85. }
  86. type Human struct {
  87. Name string
  88. Height int
  89. Pet Animal `datastore:",flatten"`
  90. }
  91. newKey := datastore.IncompleteKey("Human", nil)
  92. _, err = client.Put(ctx, newKey, &Human{
  93. Name: "Susan",
  94. Height: 67,
  95. Pet: Animal{
  96. Name: "Fluffy",
  97. Type: "Cat",
  98. Breed: "Sphynx",
  99. },
  100. })
  101. if err != nil {
  102. log.Fatal(err)
  103. }
  104. }
  105. func ExampleClient_Delete() {
  106. ctx := context.Background()
  107. client, err := datastore.NewClient(ctx, "project-id")
  108. if err != nil {
  109. // TODO: Handle error.
  110. }
  111. key := datastore.NameKey("Article", "articled1", nil)
  112. if err := client.Delete(ctx, key); err != nil {
  113. // TODO: Handle error.
  114. }
  115. }
  116. func ExampleClient_DeleteMulti() {
  117. ctx := context.Background()
  118. client, err := datastore.NewClient(ctx, "project-id")
  119. if err != nil {
  120. // TODO: Handle error.
  121. }
  122. var keys []*datastore.Key
  123. for i := 1; i <= 10; i++ {
  124. keys = append(keys, datastore.IDKey("Article", int64(i), nil))
  125. }
  126. if err := client.DeleteMulti(ctx, keys); err != nil {
  127. // TODO: Handle error.
  128. }
  129. }
  130. type Post struct {
  131. Title string
  132. PublishedAt time.Time
  133. Comments int
  134. }
  135. func ExampleClient_GetMulti() {
  136. ctx := context.Background()
  137. client, err := datastore.NewClient(ctx, "project-id")
  138. if err != nil {
  139. // TODO: Handle error.
  140. }
  141. keys := []*datastore.Key{
  142. datastore.NameKey("Post", "post1", nil),
  143. datastore.NameKey("Post", "post2", nil),
  144. datastore.NameKey("Post", "post3", nil),
  145. }
  146. posts := make([]Post, 3)
  147. if err := client.GetMulti(ctx, keys, posts); err != nil {
  148. // TODO: Handle error.
  149. }
  150. }
  151. func ExampleMultiError() {
  152. ctx := context.Background()
  153. client, err := datastore.NewClient(ctx, "project-id")
  154. if err != nil {
  155. // TODO: Handle error.
  156. }
  157. keys := []*datastore.Key{
  158. datastore.NameKey("bad-key", "bad-key", nil),
  159. }
  160. posts := make([]Post, 1)
  161. if err := client.GetMulti(ctx, keys, posts); err != nil {
  162. if merr, ok := err.(datastore.MultiError); ok {
  163. for _, err := range merr {
  164. // TODO: Handle error.
  165. _ = err
  166. }
  167. } else {
  168. // TODO: Handle error.
  169. }
  170. }
  171. }
  172. func ExampleClient_PutMulti_slice() {
  173. ctx := context.Background()
  174. client, err := datastore.NewClient(ctx, "project-id")
  175. if err != nil {
  176. // TODO: Handle error.
  177. }
  178. keys := []*datastore.Key{
  179. datastore.NameKey("Post", "post1", nil),
  180. datastore.NameKey("Post", "post2", nil),
  181. }
  182. // PutMulti with a Post slice.
  183. posts := []*Post{
  184. {Title: "Post 1", PublishedAt: time.Now()},
  185. {Title: "Post 2", PublishedAt: time.Now()},
  186. }
  187. if _, err := client.PutMulti(ctx, keys, posts); err != nil {
  188. // TODO: Handle error.
  189. }
  190. }
  191. func ExampleClient_PutMulti_interfaceSlice() {
  192. ctx := context.Background()
  193. client, err := datastore.NewClient(ctx, "project-id")
  194. if err != nil {
  195. // TODO: Handle error.
  196. }
  197. keys := []*datastore.Key{
  198. datastore.NameKey("Post", "post1", nil),
  199. datastore.NameKey("Post", "post2", nil),
  200. }
  201. // PutMulti with an empty interface slice.
  202. posts := []interface{}{
  203. &Post{Title: "Post 1", PublishedAt: time.Now()},
  204. &Post{Title: "Post 2", PublishedAt: time.Now()},
  205. }
  206. if _, err := client.PutMulti(ctx, keys, posts); err != nil {
  207. // TODO: Handle error.
  208. }
  209. }
  210. func ExampleNewQuery() {
  211. // Query for Post entities.
  212. q := datastore.NewQuery("Post")
  213. _ = q // TODO: Use the query with Client.Run.
  214. }
  215. func ExampleNewQuery_options() {
  216. // Query to order the posts by the number of comments they have received.
  217. q := datastore.NewQuery("Post").Order("-Comments")
  218. // Start listing from an offset and limit the results.
  219. q = q.Offset(20).Limit(10)
  220. _ = q // TODO: Use the query.
  221. }
  222. func ExampleClient_Count() {
  223. ctx := context.Background()
  224. client, err := datastore.NewClient(ctx, "project-id")
  225. if err != nil {
  226. // TODO: Handle error.
  227. }
  228. // Count the number of the post entities.
  229. q := datastore.NewQuery("Post")
  230. n, err := client.Count(ctx, q)
  231. if err != nil {
  232. // TODO: Handle error.
  233. }
  234. fmt.Printf("There are %d posts.", n)
  235. }
  236. func ExampleClient_Run() {
  237. ctx := context.Background()
  238. client, err := datastore.NewClient(ctx, "project-id")
  239. if err != nil {
  240. // TODO: Handle error.
  241. }
  242. // List the posts published since yesterday.
  243. yesterday := time.Now().Add(-24 * time.Hour)
  244. q := datastore.NewQuery("Post").Filter("PublishedAt >", yesterday)
  245. it := client.Run(ctx, q)
  246. _ = it // TODO: iterate using Next.
  247. }
  248. func ExampleClient_NewTransaction() {
  249. ctx := context.Background()
  250. client, err := datastore.NewClient(ctx, "project-id")
  251. if err != nil {
  252. // TODO: Handle error.
  253. }
  254. const retries = 3
  255. // Increment a counter.
  256. // See https://cloud.google.com/appengine/articles/sharding_counters for
  257. // a more scalable solution.
  258. type Counter struct {
  259. Count int
  260. }
  261. key := datastore.NameKey("counter", "CounterA", nil)
  262. var tx *datastore.Transaction
  263. for i := 0; i < retries; i++ {
  264. tx, err = client.NewTransaction(ctx)
  265. if err != nil {
  266. break
  267. }
  268. var c Counter
  269. if err = tx.Get(key, &c); err != nil && err != datastore.ErrNoSuchEntity {
  270. break
  271. }
  272. c.Count++
  273. if _, err = tx.Put(key, &c); err != nil {
  274. break
  275. }
  276. // Attempt to commit the transaction. If there's a conflict, try again.
  277. if _, err = tx.Commit(); err != datastore.ErrConcurrentTransaction {
  278. break
  279. }
  280. }
  281. if err != nil {
  282. // TODO: Handle error.
  283. }
  284. }
  285. func ExampleClient_RunInTransaction() {
  286. ctx := context.Background()
  287. client, err := datastore.NewClient(ctx, "project-id")
  288. if err != nil {
  289. // TODO: Handle error.
  290. }
  291. // Increment a counter.
  292. // See https://cloud.google.com/appengine/articles/sharding_counters for
  293. // a more scalable solution.
  294. type Counter struct {
  295. Count int
  296. }
  297. var count int
  298. key := datastore.NameKey("Counter", "singleton", nil)
  299. _, err = client.RunInTransaction(ctx, func(tx *datastore.Transaction) error {
  300. var x Counter
  301. if err := tx.Get(key, &x); err != nil && err != datastore.ErrNoSuchEntity {
  302. return err
  303. }
  304. x.Count++
  305. if _, err := tx.Put(key, &x); err != nil {
  306. return err
  307. }
  308. count = x.Count
  309. return nil
  310. })
  311. if err != nil {
  312. // TODO: Handle error.
  313. }
  314. // The value of count is only valid once the transaction is successful
  315. // (RunInTransaction has returned nil).
  316. fmt.Printf("Count=%d\n", count)
  317. }
  318. func ExampleClient_AllocateIDs() {
  319. ctx := context.Background()
  320. client, err := datastore.NewClient(ctx, "project-id")
  321. if err != nil {
  322. // TODO: Handle error.
  323. }
  324. var keys []*datastore.Key
  325. for i := 0; i < 10; i++ {
  326. keys = append(keys, datastore.IncompleteKey("Article", nil))
  327. }
  328. keys, err = client.AllocateIDs(ctx, keys)
  329. if err != nil {
  330. // TODO: Handle error.
  331. }
  332. _ = keys // TODO: Use keys.
  333. }
  334. func ExampleKey_Encode() {
  335. key := datastore.IDKey("Article", 1, nil)
  336. encoded := key.Encode()
  337. fmt.Println(encoded)
  338. // Output: EgsKB0FydGljbGUQAQ
  339. }
  340. func ExampleDecodeKey() {
  341. const encoded = "EgsKB0FydGljbGUQAQ"
  342. key, err := datastore.DecodeKey(encoded)
  343. if err != nil {
  344. // TODO: Handle error.
  345. }
  346. fmt.Println(key)
  347. // Output: /Article,1
  348. }
  349. func ExampleIDKey() {
  350. // Key with numeric ID.
  351. k := datastore.IDKey("Article", 1, nil)
  352. _ = k // TODO: Use key.
  353. }
  354. func ExampleNameKey() {
  355. // Key with string ID.
  356. k := datastore.NameKey("Article", "article8", nil)
  357. _ = k // TODO: Use key.
  358. }
  359. func ExampleIncompleteKey() {
  360. k := datastore.IncompleteKey("Article", nil)
  361. _ = k // TODO: Use incomplete key.
  362. }
  363. func ExampleClient_GetAll() {
  364. ctx := context.Background()
  365. client, err := datastore.NewClient(ctx, "project-id")
  366. if err != nil {
  367. // TODO: Handle error.
  368. }
  369. var posts []*Post
  370. keys, err := client.GetAll(ctx, datastore.NewQuery("Post"), &posts)
  371. if err != nil {
  372. // TODO: Handle error.
  373. }
  374. for i, key := range keys {
  375. fmt.Println(key)
  376. fmt.Println(posts[i])
  377. }
  378. }
  379. func ExampleClient_Mutate() {
  380. ctx := context.Background()
  381. client, err := datastore.NewClient(ctx, "project-id")
  382. if err != nil {
  383. // TODO: Handle error.
  384. }
  385. key1 := datastore.NameKey("Post", "post1", nil)
  386. key2 := datastore.NameKey("Post", "post2", nil)
  387. key3 := datastore.NameKey("Post", "post3", nil)
  388. key4 := datastore.NameKey("Post", "post4", nil)
  389. _, err = client.Mutate(ctx,
  390. datastore.NewInsert(key1, Post{Title: "Post 1"}),
  391. datastore.NewUpsert(key2, Post{Title: "Post 2"}),
  392. datastore.NewUpdate(key3, Post{Title: "Post 3"}),
  393. datastore.NewDelete(key4))
  394. if err != nil {
  395. // TODO: Handle error.
  396. }
  397. }
  398. func ExampleCommit_Key() {
  399. ctx := context.Background()
  400. client, err := datastore.NewClient(ctx, "")
  401. if err != nil {
  402. // TODO: Handle error.
  403. }
  404. var pk1, pk2 *datastore.PendingKey
  405. // Create two posts in a single transaction.
  406. commit, err := client.RunInTransaction(ctx, func(tx *datastore.Transaction) error {
  407. var err error
  408. pk1, err = tx.Put(datastore.IncompleteKey("Post", nil), &Post{Title: "Post 1", PublishedAt: time.Now()})
  409. if err != nil {
  410. return err
  411. }
  412. pk2, err = tx.Put(datastore.IncompleteKey("Post", nil), &Post{Title: "Post 2", PublishedAt: time.Now()})
  413. if err != nil {
  414. return err
  415. }
  416. return nil
  417. })
  418. if err != nil {
  419. // TODO: Handle error.
  420. }
  421. // Now pk1, pk2 are valid PendingKeys. Let's convert them into real keys
  422. // using the Commit object.
  423. k1 := commit.Key(pk1)
  424. k2 := commit.Key(pk2)
  425. fmt.Println(k1, k2)
  426. }
  427. func ExampleIterator_Next() {
  428. ctx := context.Background()
  429. client, err := datastore.NewClient(ctx, "project-id")
  430. if err != nil {
  431. // TODO: Handle error.
  432. }
  433. it := client.Run(ctx, datastore.NewQuery("Post"))
  434. for {
  435. var p Post
  436. key, err := it.Next(&p)
  437. if err == iterator.Done {
  438. break
  439. }
  440. if err != nil {
  441. // TODO: Handle error.
  442. }
  443. fmt.Println(key, p)
  444. }
  445. }
  446. func ExampleIterator_Cursor() {
  447. ctx := context.Background()
  448. client, err := datastore.NewClient(ctx, "project-id")
  449. if err != nil {
  450. // TODO: Handle error.
  451. }
  452. it := client.Run(ctx, datastore.NewQuery("Post"))
  453. for {
  454. var p Post
  455. _, err := it.Next(&p)
  456. if err == iterator.Done {
  457. break
  458. }
  459. if err != nil {
  460. // TODO: Handle error.
  461. }
  462. fmt.Println(p)
  463. cursor, err := it.Cursor()
  464. if err != nil {
  465. // TODO: Handle error.
  466. }
  467. // When printed, a cursor will display as a string that can be passed
  468. // to datastore.NewCursor.
  469. fmt.Printf("to resume with this post, use cursor %s\n", cursor)
  470. }
  471. }
  472. func ExampleDecodeCursor() {
  473. // See Query.Start for a fuller example of DecodeCursor.
  474. // getCursor represents a function that returns a cursor from a previous
  475. // iteration in string form.
  476. cursorString := getCursor()
  477. cursor, err := datastore.DecodeCursor(cursorString)
  478. if err != nil {
  479. // TODO: Handle error.
  480. }
  481. _ = cursor // TODO: Use the cursor with Query.Start or Query.End.
  482. }
  483. func getCursor() string { return "" }
  484. func ExampleQuery_Start() {
  485. // This example demonstrates how to use cursors and Query.Start
  486. // to resume an iteration.
  487. ctx := context.Background()
  488. client, err := datastore.NewClient(ctx, "project-id")
  489. if err != nil {
  490. // TODO: Handle error.
  491. }
  492. // getCursor represents a function that returns a cursor from a previous
  493. // iteration in string form.
  494. cursorString := getCursor()
  495. cursor, err := datastore.DecodeCursor(cursorString)
  496. if err != nil {
  497. // TODO: Handle error.
  498. }
  499. it := client.Run(ctx, datastore.NewQuery("Post").Start(cursor))
  500. _ = it // TODO: Use iterator.
  501. }
  502. func ExampleLoadStruct() {
  503. type Player struct {
  504. User string
  505. Score int
  506. }
  507. // Normally LoadStruct would only be used inside a custom implementation of
  508. // PropertyLoadSaver; this is for illustrative purposes only.
  509. props := []datastore.Property{
  510. {Name: "User", Value: "Alice"},
  511. {Name: "Score", Value: int64(97)},
  512. }
  513. var p Player
  514. if err := datastore.LoadStruct(&p, props); err != nil {
  515. // TODO: Handle error.
  516. }
  517. fmt.Println(p)
  518. // Output: {Alice 97}
  519. }
  520. func ExampleSaveStruct() {
  521. type Player struct {
  522. User string
  523. Score int
  524. }
  525. p := &Player{
  526. User: "Alice",
  527. Score: 97,
  528. }
  529. props, err := datastore.SaveStruct(p)
  530. if err != nil {
  531. // TODO: Handle error.
  532. }
  533. fmt.Println(props)
  534. // TODO(jba): make this output stable: Output: [{User Alice false} {Score 97 false}]
  535. }