-
Notifications
You must be signed in to change notification settings - Fork 9
/
Examples.fsx
567 lines (459 loc) · 31.9 KB
/
Examples.fsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
// Author : Yan Cui (twitter @theburningmonk)
// Email : theburningmonk@gmail.com
// Blog : http://theburningmonk.com
(*
This script contains query and scan examples using the V2 API (with Local and Global
Secondary Index support).
For more details on the query index, please check the Wiki page:
https://github.com/theburningmonk/DynamoDb.SQL/wiki
This script does not execute against Amazon DynamoDB but executes against the
DynamoDBLocal instead. For more detais, please see:
http://aws.typepad.com/aws/2013/09/dynamodb-local-for-desktop-development.html
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Tools.DynamoDBLocal.html
*)
(*
RUNNING INSTRUCTIONS
In order for this script to run, you need to have version 7 of the Java Runtime Environement
installed, which you can download from:
http://java.com/en/
Before you start running the scripts, please double click the
lib/start_dynamodb_local.bat
file to start an instance of the DynamoDBLocal database for testing.
*)
#r @"bin\AWSSDK.Core.dll"
#r @"bin\AWSSDK.DynamoDBv2.dll"
#r @"bin\DynamoDb.SQL.dll"
#load "Common.fs"
open Common
open System
open System.Linq
open Amazon.DynamoDBv2
open Amazon.DynamoDBv2.DataModel
module QueryExamples =
let userId = "theburningmonk-1"
//#region Hepers
let assertCount n (response : Amazon.DynamoDBv2.Model.QueryResponse) =
assertThat (response.Count = n)
(sprintf "Response has incorrect Count : %d %d" response.Count n)
response
let assertItemsCount n (response : Amazon.DynamoDBv2.Model.QueryResponse) =
assertThat (response.Items.Count = n)
(sprintf "Response has incorrect Items count : %d %d" response.Items.Count n)
response |> assertCount n
let assertUserId userId (response : Amazon.DynamoDBv2.Model.QueryResponse) =
assertThat (response.Items |> Seq.forall (fun attrs -> attrs.["UserId"].S = userId))
(sprintf "UserId should all be \"%s\"" userId)
response
let assertGameScores n userId (gameScores : GameScore[]) =
assertThat (gameScores.Length = n)
(sprintf "Game scores has incorrect length : %d %d" gameScores.Length n)
assertThat (gameScores |> Seq.forall (fun gs -> gs.UserId = userId))
(sprintf "GameScore.UserId should all be \"%s\"" userId)
gameScores
//#endregion
/// Basic query using only key conditions
/// NOTE: in the DynamoDBv2 API you no longer have to specify hash and range conditions explicitly, but
/// instead all conditions now go into a single array.
/// So the query syntax has also changed accordingly to remove the need to use the @HashKey and @RangeKey
/// special keywords to specify hash and range key conditions. For more details, please check the wiki page:
/// https://github.com/theburningmonk/DynamoDb.SQL/wiki
let queryByHashKey () =
// this query should return all 5 results
let selectQuery = sprintf "SELECT * FROM GameScores WHERE UserId = \"%s\"" userId
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running basic hash key query :\n\t\t%s" selectQuery
let response = client.Query(selectQuery)
response |> assertItemsCount 5 |> assertUserId userId |> ignore
(* ---------------- query using DynamoDBContext ---------------- *)
printfn "(DynamoDBContext) Running basic hash key query :\n\t\t%s" selectQuery
let gameScores = ctx.ExecQuery<GameScore>(selectQuery) |> Seq.toArray
gameScores |> assertGameScores 5 userId |> ignore
(* --------------------------------------------------------------- *)
let countQuery = "COUNT * FROM GameScores WHERE UserId = \"theburningmonk-1\""
printfn "(AmazonDynamoDBClient) Running basic hash key count :\n\t\t%s" countQuery
let countResponse = client.Query(countQuery)
countResponse |> assertCount 5 |> ignore
/// Basic query using both hash and range key
/// NOTE: only a subset of the operators are allowed in a query (by DynamoDB)
/// For the list of allowed operators, please check the Wiki
/// https://github.com/theburningmonk/DynamoDb.SQL/wiki
let queryByHashAndRangeKey () =
// this query should return 2 result
let selectQuery = sprintf "SELECT * FROM GameScores WHERE UserId = \"%s\" AND GameTitle BEGINS WITH \"A\"" userId
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running hash key and range key query:\n\t\t%s" selectQuery
let response = client.Query(selectQuery)
response |> assertItemsCount 2 |> assertUserId userId |> ignore
assertThat (response.Items |> Seq.forall (fun attrs -> attrs.["GameTitle"].S.StartsWith "A"))
(sprintf "GameScore.GameTitle should all start with \"A\"")
(* ---------------- query using DynamoDBContext ---------------- *)
printfn "(DynamoDBContext) Running hash key and range key query:\n\t\t%s" selectQuery
let gameScores = ctx.ExecQuery<GameScore>(selectQuery) |> Seq.toArray
gameScores |> assertGameScores 2 userId |> ignore
assertThat (gameScores |> Seq.forall (fun gameScore -> gameScore.GameTitle.StartsWith "A"))
(sprintf "GameScore.GameTitle should all start with \"A\"")
(* --------------------------------------------------------------- *)
let countQuery = "COUNT * FROM GameScores WHERE UserId = \"theburningmonk-1\" AND GameTitle BEGINS WITH \"A\""
printfn "(AmazonDynamoDBClient) Running hash key and range key count:\n\t\t%s" countQuery
let countResponse = client.Query(countQuery)
countResponse |> assertCount 2 |> ignore
/// You can use ORDER ASC/DESC and LIMIT to get the first/last X number of items that
/// matches the Hash/Range key filters
let queryWithOrderByAndLimit () =
// this query should return the first 3 scores
let selectQuery = sprintf "SELECT * FROM GameScores WHERE UserId = \"%s\" ORDER ASC LIMIT 3" userId
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running query with ORDER ASC and LIMIT :\n\t\t%s" selectQuery
let response = client.Query(selectQuery)
response |> assertItemsCount 3 |> assertUserId userId |> ignore
assertThat (response.Items |> Seq.forall (fun attrs -> attrs.["GameTitle"].S < meteorBlasters))
(sprintf "GameTitle should all be before %s" meteorBlasters)
(* ---------------- query using DynamoDBContext ---------------- *)
printfn "(DynamoDBContext) Running query with ORDER ASC and LIMIT :\n\t\t%s" selectQuery
let gameScores = ctx.ExecQuery<GameScore>(selectQuery) |> Seq.toArray
gameScores |> assertGameScores 3 userId |> ignore
assertThat (gameScores |> Seq.forall (fun gameScore -> gameScore.GameTitle < meteorBlasters))
(sprintf "GameScore.GameTitle should all be before %s" meteorBlasters)
// this query should return the last 3 scores
let selectQuery = sprintf "SELECT * FROM GameScores WHERE UserId = \"%s\" ORDER DESC LIMIT 3" userId
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running query with ORDER DESC and LIMIT :\n\t\t%s" selectQuery
let response = client.Query(selectQuery)
response |> assertItemsCount 3 |> assertUserId userId |> ignore
assertThat (response.Items |> Seq.forall (fun attrs -> attrs.["GameTitle"].S > attackShips))
(sprintf "GameTitle should all be after %s" attackShips)
(* ---------------- query using DynamoDBContext ---------------- *)
printfn "(DynamoDBContext) Running query with ORDER DESC and LIMIT :\n\t\t%s" selectQuery
let gameScores = ctx.ExecQuery<GameScore>(selectQuery) |> Seq.toArray
gameScores |> assertGameScores 3 userId |> ignore
assertThat (gameScores |> Seq.forall (fun gameScore -> gameScore.GameTitle > attackShips))
(sprintf "GameScore.GameTitle should all be after %s" attackShips)
/// By defaut, queries are executed with ConsistentRead switched on.
/// To disable consistent read, use the NoConsistentRead query option
let queryWithNoConsistentRead () =
// this query should return all 5 game scores
let selectQuery = sprintf "SELECT * FROM GameScores WHERE UserId = \"%s\" WITH (NoConsistentRead)" userId
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running query with NoConsistentRead :\n\t\t%s" selectQuery
let response = client.Query(selectQuery)
response |> assertItemsCount 5 |> assertUserId userId |> ignore
(* ---------------- query using DynamoDBContext ---------------- *)
printfn "(DynamoDBContext) Running query with NoConsistentRead :\n\t\t%s" selectQuery
let gameScores = ctx.ExecQuery<GameScore>(selectQuery) |> Seq.toArray
gameScores |> assertGameScores 5 userId |> ignore
/// AWS Guideline says that you should avoid sudden bursts of read activity:
/// http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/QueryAndScanGuidelines.html
/// To accomplish this you can specify the page size for each request by using the PageSize query option
let throttlingWithQueryPageSize () =
// this query should return 3 game scores, but 3 requests are made (behind the scene) with each returning
// only one item before the results are aggregated
let selectQuery = sprintf "SELECT * FROM GameScores WHERE UserId = \"%s\" LIMIT 3 WITH (PageSize(1))" userId
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running query with PageSize :\n\t\t%s" selectQuery
let response = client.Query(selectQuery)
response |> assertItemsCount 3 |> assertUserId userId |> ignore
(* ---------------- query using DynamoDBContext ---------------- *)
printfn "(DynamoDBContext) Running query with PageSize :\n\t\t%s" selectQuery
let gameScores = ctx.ExecQuery<GameScore>(selectQuery) |> Seq.toArray
gameScores |> assertGameScores 3 userId |> ignore
/// Rather than always getting all the attributes back, you can also choose a specific subset of
/// the available attributes
let selectSpecificAttributes () =
// should return all 5 scores with only a subset of attributes
let selectQuery = sprintf "SELECT UserId, GameTitle, Wins FROM GameScores WHERE UserId = \"%s\"" userId
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running query with speicifc attributes :\n\t\t%s" selectQuery
let response = client.Query(selectQuery)
response |> assertItemsCount 5 |> assertUserId userId |> ignore
assertThat (response.Items |> Seq.forall (fun attrs -> attrs.Count = 3 && attrs.ContainsKey "UserId" && attrs.ContainsKey "GameTitle" && attrs.ContainsKey "Wins"))
"QueryResult items should only contain UserId, GameTitle and Wins attributes"
(* ---------------- query using DynamoDBContext ---------------- *)
printfn "(DynamoDBContext) Running query with speicifc attributes :\n\t\t%s" selectQuery
let gameScores = ctx.ExecQuery<GameScore>(selectQuery) |> Seq.toArray
gameScores |> assertGameScores 5 userId |> ignore
assertThat (gameScores |> Seq.forall (fun gs -> gs.UserId.Length > 0 && gs.GameTitle.Length > 0 && gs.Wins > 0 &&
gs.Losses = 0 && gs.TopScore = 0 && gs.TopScoreDateTime = DateTime.MinValue))
"GameScore.Losses, GameScore.TopScore and GameScore.TopScoreDateTime should not be set"
/// Whilst I'm not sure of the rationale behind this decision, but you can now optionally set the flag in
/// the query request to tell DynamoDB to not report the consumed capacity units.
/// To accomplish this, simply include the NoReturnedCapacity option in the WITH clause
let queryWithNoReturnedConsumedCapacity () =
let selectQuery = sprintf "SELECT * FROM GameScores WHERE UserId = \"%s\" WITH (NoReturnedCapacity)" userId
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running basic query with NoReturnedCapacity :\n\t\t%s" selectQuery
let response = client.Query(selectQuery)
response |> assertItemsCount 5 |> assertUserId userId |> ignore
assertThat (response.ConsumedCapacity = null)
"ConsumedCapacity should not be returned"
/// You can additionally query using a Local Secondary Index (DynamoDB V2 functionality) by specifying
/// the name of the index, and whether or not to fetch ALL attributes in the WITH clause.
/// For the attributes that are not part of the index, DynamoDB will automatically fetch those from the
/// table, consuming additional capacity unit in the process. For more details, please refer to docs:
/// http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html
let queryWithLocalSecondaryIndexAllAttributes () =
// this query uses the TopScoreIndex to return all game scores with top score >= 1000
// because the Indx query option specifies that all attributes are returned, attributes that are NOT part of
// the index - i.e. TopScoreDateTime - will be fetched from the table
let selectQuery = sprintf "SELECT * FROM GameScores
WHERE UserId = \"%s\"
AND TopScore >= 1000
WITH(Index(TopScoreIndex, true))"
userId
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running query with Index (all attributes) :\n\t\t%s" selectQuery
let response = client.Query(selectQuery)
response |> assertUserId userId |> ignore
assertThat (response.Count > 0)
"Response should have a non-zero count"
assertThat (response.Items.Count > 0)
"Response should have contained some items"
assertThat (response.Items |> Seq.forall (fun attrs -> attrs.["TopScore"].N >= "1000"))
"TopScore should all be >= 1000"
assertThat (response.Items |> Seq.forall (fun attrs -> attrs.Count = 6))
"All 6 attributes should be returned"
(* ---------------- query using DynamoDBContext ---------------- *)
printfn "(DynamoDBContext) Running query with Index (all attributes) :\n\t\t%s" selectQuery
let gameScores = ctx.ExecQuery<GameScore>(selectQuery) |> Seq.toArray
assertThat (gameScores.Length > 0)
"Game scores should have some items"
assertThat (gameScores |> Seq.forall (fun gs -> gs.UserId = userId))
(sprintf "GameScore.UserId should all be %s" userId)
assertThat (gameScores |> Seq.forall (fun gs -> gs.TopScore >= 1000))
"GameScore.TopScore should all >= 1000"
assertThat (gameScores |> Seq.forall (fun gs -> gs.TopScoreDateTime > DateTime.MinValue))
"GameScore.TopScoreDateTime should all be populated"
(* --------------------------------------------------------------- *)
let countQuery = sprintf "COUNT * FROM GameScores
WHERE UserId = \"%s\"
AND TopScore >= 1000
WITH(Index(TopScoreIndex, true))"
userId
printfn "(AmazonDynamoDBClient) Running count query with index :\n\t\t%s" countQuery
let countResponse = client.Query(countQuery)
assertThat (countResponse.Count > 0)
"Count response should have some count"
/// You can additionally query using a Local Secondary Index (DynamoDB V2 functionality) by specifying
/// the name of the index, and whether or not to fetch ALL attributes in the WITH clause.
/// For the attributes that are not part of the index, DynamoDB will automatically fetch those from the
/// table, consuming additional capacity unit in the process. For more details, please refer to docs:
/// http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html
let queryWithLocalSecondaryIndexProjectedAttributes () =
// this query uses the TopScoreIndex to return all game scores with top score >= 1000
// because the Indx query option specifies that NOT all attributes are returned, attributes that are NOT part
// of the index - i.e. TopScoreDateTime - will NOT be fetched from the table
let selectQuery = sprintf "SELECT * FROM GameScores
WHERE UserId = \"%s\"
AND TopScore >= 1000
WITH(Index(TopScoreIndex, false))"
userId
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running query with Index (index attributes only) :\n\t\t%s" selectQuery
let response = client.Query(selectQuery)
response |> assertUserId userId |> ignore
assertThat (response.Count > 0)
"Response should have a non-zero count"
assertThat (response.Items.Count > 0)
"Response should have contained some items"
assertThat (response.Items |> Seq.forall (fun attrs -> attrs.["TopScore"].N >= "1000"))
"TopScore should all be >= 1000"
assertThat (response.Items |> Seq.forall (fun attrs -> attrs.Count = 3 && (not <| attrs.ContainsKey "TopScoreDateTime")))
"GameScore.TopScoreDateTim should not be returned"
(* ---------------- query using DynamoDBContext ---------------- *)
printfn "(DynamoDBContext) Running query with Index (index attributes only) :\n\t\t%s" selectQuery
let gameScores = ctx.ExecQuery<GameScore>(selectQuery) |> Seq.toArray
assertThat (gameScores.Length > 0)
"Game scores should have some items"
assertThat (gameScores |> Seq.forall (fun gs -> gs.UserId = userId))
(sprintf "GameScore.UserId should all be %s" userId)
assertThat (gameScores |> Seq.forall (fun gs -> gs.TopScore >= 1000))
"GameScore.TopScore should all >= 1000"
assertThat (gameScores |> Seq.forall (fun gs -> gs.TopScoreDateTime = DateTime.MinValue))
"GameScore.TopScoreDateTime should not be populated"
/// You can query using a Global Secondary Index (DynamoDB V2 functionality) by specifying
/// the name of the index, and whether or not to fetch ALL attributes in the WITH clause.
/// If the projection type of the index is not ALL_ATTRIBUTES then you have to specify the
/// attributes explicitly and to set the `AllAttributes` flag in the `Index` option to false.
/// For more details, please refer to docs:
/// http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html
let queryWithGlobalSecondaryIndexProjectedAttributes () =
// this query uses the TopScoreIndex to return all game scores with top score >= 1000
// because the Indx query option specifies that all attributes are returned, attributes that are NOT part of
// the index - i.e. TopScoreDateTime - will be fetched from the table
let selectQuery = sprintf "SELECT * FROM GameScores
WHERE GameTitle = \"%s\"
AND TopScore >= 1000
WITH(Index(GameTitleIndex, false), NoConsistentRead)"
starshipX
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running query with Index (all attributes) :\n\t\t%s" selectQuery
let response = client.Query(selectQuery)
assertThat (response.Count > 0)
"Response should have a non-zero count"
assertThat (response.Items.Count > 0)
"Response should have contained some items"
assertThat (response.Items |> Seq.forall (fun attrs -> attrs.["GameTitle"].S = starshipX))
(sprintf "GameTitle should all be %s" starshipX)
assertThat (response.Items |> Seq.forall (fun attrs -> attrs.["TopScore"].N >= "1000"))
"TopScore should all be >= 1000"
assertThat (response.Items |> Seq.forall (fun attrs -> attrs.Count = 3 && (not <| attrs.ContainsKey "TopScoreDateTime")))
"GameScore.TopScoreDateTim should not be returned"
(* ---------------- query using DynamoDBContext ---------------- *)
printfn "(DynamoDBContext) Running query with Index (all attributes) :\n\t\t%s" selectQuery
let gameScores = ctx.ExecQuery<GameScore>(selectQuery) |> Seq.toArray
assertThat (gameScores.Length > 0)
"Game scores should have some items"
assertThat (gameScores |> Seq.forall (fun gs -> gs.GameTitle = starshipX))
(sprintf "GameScore.GameTitle should all be %s" starshipX)
assertThat (gameScores |> Seq.forall (fun gs -> gs.TopScore >= 1000))
"GameScore.TopScore should all >= 1000"
assertThat (gameScores |> Seq.forall (fun gs -> gs.TopScoreDateTime = DateTime.MinValue))
"GameScore.TopScoreDateTime should not be populated"
(* --------------------------------------------------------------- *)
let countQuery = sprintf "COUNT * FROM GameScores
WHERE GameTitle = \"%s\"
AND TopScore >= 1000
WITH(Index(GameTitleIndex, false), NoConsistentRead)"
starshipX
printfn "(AmazonDynamoDBClient) Running count query with index :\n\t\t%s" countQuery
let countResponse = client.Query(countQuery)
assertThat (countResponse.Count > 0)
"Count response should have some count"
module ScanExamples =
//#region Hepers
let assertCount n (response : Amazon.DynamoDBv2.Model.ScanResponse) =
assertThat (response.Count = n)
(sprintf "Response has incorrect Count : %d %d" response.Count n)
response
let assertItemsCount n (response : Amazon.DynamoDBv2.Model.ScanResponse) =
assertThat (response.Items.Count = n)
(sprintf "Response has incorrect Items count : %d %d" response.Items.Count n)
response |> assertCount n
let assertGameTitle title (response : Amazon.DynamoDBv2.Model.ScanResponse) =
assertThat (response.Items |> Seq.forall (fun attrs -> attrs.["GameTitle"].S = title))
(sprintf "GameTitle should all be %s" title)
response
let assertGameScores n title (gameScores : GameScore[]) =
assertThat (gameScores.Length = n)
(sprintf "Game scores has incorrect length : %d %d" gameScores.Length n)
assertThat (gameScores |> Seq.forall (fun gs -> gs.GameTitle = title))
(sprintf "GameScore.GameTitle should all be %s" title)
gameScores
//#endregion
/// Basic scan example
let basicScan () =
// this scan should return quite a number of items... all the game scores should be for starship x
let selectQuery = sprintf "SELECT * FROM GameScores WHERE GameTitle = \"%s\"" starshipX
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running basic scan :\n\t\t%s" selectQuery
let response = client.Scan(selectQuery)
response |> assertItemsCount 1000 |> assertGameTitle starshipX |> ignore
(* ---------------- query using DynamoDBContext ---------------- *)
printfn "(DynamoDBContext) Running basic scan :\n\t\t%s" selectQuery
let gameScores = ctx.ExecScan<GameScore>(selectQuery) |> Seq.toArray
gameScores |> assertGameScores 1000 starshipX |> ignore
(* --------------------------------------------------------------- *)
let countQuery = sprintf "COUNT * FROM GameScores WHERE GameTitle = \"%s\"" starshipX
printfn "(AmazonDynamoDBClient) Running basic scan count :\n\t\t%s" countQuery
let countResponse = client.Scan(countQuery)
countResponse |> assertCount 1000 |> ignore
/// You can use ORDER ASC/DESC and LIMIT to get the first/last X number of items that
/// matches the scan filters
let scanWithLimit () =
// this scan should return 10 replies, posted by John or James
let selectQuery = sprintf "SELECT * FROM GameScores WHERE GameTitle = \"%s\" LIMIT 10" starshipX
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running scan with LIMIT :\n\t\t%s" selectQuery
let response = client.Scan(selectQuery)
response |> assertItemsCount 10 |> assertGameTitle starshipX |> ignore
(* ---------------- query using DynamoDBContext ---------------- *)
printfn "(DynamoDBContext) Running scan with LIMIT :\n\t\t%s" selectQuery
let gameScores = ctx.ExecScan<GameScore>(selectQuery) |> Seq.toArray
gameScores |> assertGameScores 10 starshipX |> ignore
(* --------------------------------------------------------------- *)
let countQuery = sprintf "Count * FROM GameScores WHERE GameTitle = \"%s\" LIMIT 10" starshipX
printfn "(AmazonDynamoDBClient) Running scan count with LIMIT :\n\t\t%s" countQuery
let countResponse = client.Scan(countQuery)
countResponse |> assertCount 10 |> ignore
/// Similar to throttling queries, you can do the same with scans too, using the PageSize scan option
let throttlingWithScanPageSize () =
// this scan should return the same results as the basic example, but
// - requires more requests
// - less capacity consumed per request
// - takes longer
let selectQuery = sprintf "SELECT * FROM GameScores WHERE GameTitle = \"%s\" WITH (PageSize(20))" starshipX
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running basic scan with PageSize :\n\t\t%s" selectQuery
let response = client.Scan(selectQuery)
response |> assertItemsCount 1000 |> assertGameTitle starshipX |> ignore
(* ---------------- query using DynamoDBContext ---------------- *)
printfn "(DynamoDBContext) Running basic scan with PageSize :\n\t\t%s" selectQuery
let gameScores = ctx.ExecScan<GameScore>(selectQuery) |> Seq.toArray
gameScores |> assertGameScores 1000 starshipX |> ignore
/// Select specific attributes
let selectSpecificAttributes () =
// this scan should return quite a number of items... all the game scores should be for starship x
let selectQuery = sprintf "SELECT GameTitle, TopScoreDateTime FROM GameScores WHERE GameTitle = \"%s\"" starshipX
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running basic scan :\n\t\t%s" selectQuery
let response = client.Scan(selectQuery)
response |> assertItemsCount 1000 |> assertGameTitle starshipX |> ignore
assertThat (response.Items |> Seq.forall (fun attrs -> attrs.Count = 2 && attrs.ContainsKey "GameTitle" && attrs.ContainsKey "TopScoreDateTime"))
"QueryResult items should only contain GameTitle and TopScoreDateTime attributes"
(* ---------------- query using DynamoDBContext ---------------- *)
printfn "(DynamoDBContext) Running basic scan :\n\t\t%s" selectQuery
let gameScores = ctx.ExecScan<GameScore>(selectQuery) |> Seq.toArray
gameScores |> assertGameScores 1000 starshipX |> ignore
assertThat (gameScores |> Seq.forall (fun gs -> gs.GameTitle.Length > 0 && gs.TopScoreDateTime > DateTime.MinValue &&
gs.Wins = 0 && gs.Losses = 0 && gs.TopScore = 0 && String.IsNullOrWhiteSpace gs.UserId))
"Only GameScore.GameTitle and GameScore.TopScoreDateTime should be set"
/// You can use Scan segments to carry out scans in multiple segments simultaneously
let scanWithScanPageSizeAndSegments () =
// this scan should return the same results as the basic example, but
// - requires more requests
// - less capacity consumed per request
// - takes longer
let selectQuery = sprintf "SELECT * FROM GameScores WHERE GameTitle = \"%s\" WITH (PageSize(20), Segments(2))" starshipX
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running basic scan with PageSize and 2 segments :\n\t\t%s" selectQuery
let response = client.Scan(selectQuery)
response |> assertItemsCount 1000 |> assertGameTitle starshipX |> ignore
(* ---------------- query using DynamoDBContext ---------------- *)
printfn "(DynamoDBContext) Running basic scan with PageSize and 2 segments :\n\t\t%s" selectQuery
let gameScores = ctx.ExecScan<GameScore>(selectQuery) |> Seq.toArray
gameScores |> assertGameScores 1000 starshipX |> ignore
/// Whilst I'm not sure of the rationale behind this decision, but you can now optionally set the flag in
/// the scan request to tell DynamoDB to not report the consumed capacity units.
/// To accomplish this, simply include the NoReturnedCapacity option in the WITH clause
let scanWithNoReturnedConsumedCapacity () =
// this scan should return quite a number of items... all the game scores should be for starship x
let selectQuery = sprintf "SELECT * FROM GameScores WHERE GameTitle = \"%s\" WITH (NoReturnedCapacity)" starshipX
(* ---------------- query using AmazonDynamoDBClient ---------------- *)
printfn "(AmazonDynamoDBClient) Running basic scan with NoReturnedCapacity :\n\t\t%s" selectQuery
let response = client.Scan(selectQuery)
response |> assertItemsCount 1000 |> assertGameTitle starshipX |> ignore
assertThat (response.ConsumedCapacity = null)
"ConsumedCapacity should not be returned"
// you don't need to run these.
//let cmdFile = System.IO.Path.Combine(__SOURCE_DIRECTORY__, "..\..\lib\start_dynamodb_local.bat")
//let jarFile = System.IO.Path.Combine(__SOURCE_DIRECTORY__, "..\..\lib\dynamodb_local_2013-12-12/DynamoDBLocal.jar")
//let dynamoDbLocal = startDynamoDBLocal cmdFile jarFile
// uncomment these to create the table and seed the test data if you need to build the local DynamoDB table from scratch
//deleteTable()
//createTable()
//seedData()
time <| QueryExamples.queryByHashKey
time <| QueryExamples.queryByHashAndRangeKey
time <| QueryExamples.queryWithOrderByAndLimit
time <| QueryExamples.queryWithNoConsistentRead
time <| QueryExamples.throttlingWithQueryPageSize
time <| QueryExamples.selectSpecificAttributes
time <| QueryExamples.queryWithNoReturnedConsumedCapacity
time <| QueryExamples.queryWithLocalSecondaryIndexAllAttributes
time <| QueryExamples.queryWithLocalSecondaryIndexProjectedAttributes
time <| QueryExamples.queryWithGlobalSecondaryIndexProjectedAttributes
time <| ScanExamples.basicScan
time <| ScanExamples.scanWithLimit
time <| ScanExamples.throttlingWithScanPageSize
time <| ScanExamples.selectSpecificAttributes
time <| ScanExamples.scanWithScanPageSizeAndSegments
time <| ScanExamples.scanWithNoReturnedConsumedCapacity