fake_dynamo 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +14 -2
- data/lib/fake_dynamo/key.rb +5 -0
- data/lib/fake_dynamo/server.rb +2 -0
- data/lib/fake_dynamo/table.rb +17 -12
- data/lib/fake_dynamo/version.rb +1 -1
- data/spec/fake_dynamo/table_spec.rb +47 -11
- metadata +8 -8
data/README.md
CHANGED
@@ -6,10 +6,14 @@ local hosted, inmemory dynamodb emulator.
|
|
6
6
|
# Caveats
|
7
7
|
|
8
8
|
* `ConsumedCapacityUnits` value will be 1 always.
|
9
|
-
* The response size is not constrained by 1mb limit. So operation
|
9
|
+
* The response size is not constrained by 1mb limit. So operation
|
10
|
+
like `BatchGetItem` will return all items irrespective of the
|
11
|
+
response size
|
10
12
|
|
11
13
|
# Usage
|
12
14
|
|
15
|
+
requires ruby >= 1.9
|
16
|
+
|
13
17
|
````
|
14
18
|
gem install fake_dynamo
|
15
19
|
|
@@ -28,5 +32,13 @@ AWS.config(:use_ssl => false,
|
|
28
32
|
:secret_access_key => "xxx")
|
29
33
|
````
|
30
34
|
|
35
|
+
__please open a pull request with your configuration if you are using
|
36
|
+
fake_dynamo with clients other than the ones mentioned above__.
|
37
|
+
|
31
38
|
# Storage
|
32
|
-
fake_dynamo stores the `write operations` (request that changes the
|
39
|
+
fake_dynamo stores the `write operations` (request that changes the
|
40
|
+
data) in `/usr/local/var/fake_dynamo/db.fdb` and replays it before
|
41
|
+
starting the server. Because of the way fake_dynamo stores the data,
|
42
|
+
file size tend to grow by time. so fake_dynamo will compact the database
|
43
|
+
during start up if the file size is greater than 100mb. you can
|
44
|
+
manually compact it by passing --compact flag.
|
data/lib/fake_dynamo/key.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module FakeDynamo
|
2
2
|
class Key
|
3
|
+
include Comparable
|
3
4
|
extend Validation
|
4
5
|
|
5
6
|
attr_accessor :primary, :range
|
@@ -67,5 +68,9 @@ module FakeDynamo
|
|
67
68
|
result
|
68
69
|
end
|
69
70
|
|
71
|
+
def <=>(other)
|
72
|
+
[primary, range] <=> [other.primary, other.range]
|
73
|
+
end
|
74
|
+
|
70
75
|
end
|
71
76
|
end
|
data/lib/fake_dynamo/server.rb
CHANGED
data/lib/fake_dynamo/table.rb
CHANGED
@@ -200,16 +200,8 @@ module FakeDynamo
|
|
200
200
|
hash_attribute = Attribute.from_hash(key_schema.hash_key.name, data['HashKeyValue'])
|
201
201
|
matched_items = get_items_by_hash_key(hash_attribute)
|
202
202
|
|
203
|
-
|
204
203
|
forward = data.has_key?('ScanIndexForward') ? data['ScanIndexForward'] : true
|
205
|
-
|
206
|
-
if forward
|
207
|
-
matched_items.sort! { |a, b| a.key.range <=> b.key.range }
|
208
|
-
else
|
209
|
-
matched_items.sort! { |a, b| b.key.range <=> a.key.range }
|
210
|
-
end
|
211
|
-
|
212
|
-
matched_items = drop_till_start(matched_items, data['ExclusiveStartKey'])
|
204
|
+
matched_items = drop_till_start(matched_items, data['ExclusiveStartKey'], forward)
|
213
205
|
|
214
206
|
if data['RangeKeyCondition']
|
215
207
|
conditions = {key_schema.range_key.name => data['RangeKeyCondition']}
|
@@ -237,7 +229,7 @@ module FakeDynamo
|
|
237
229
|
count_and_attributes_to_get_present?(data)
|
238
230
|
validate_limit(data)
|
239
231
|
conditions = data['ScanFilter'] || {}
|
240
|
-
all_items = drop_till_start(items.values, data['ExclusiveStartKey'])
|
232
|
+
all_items = drop_till_start(items.values, data['ExclusiveStartKey'], true)
|
241
233
|
result, last_evaluated_item, scaned_count = filter(all_items, conditions, data['Limit'], false)
|
242
234
|
response = {
|
243
235
|
'Count' => result.size,
|
@@ -267,9 +259,22 @@ module FakeDynamo
|
|
267
259
|
end
|
268
260
|
end
|
269
261
|
|
270
|
-
def drop_till_start(all_items, start_key_hash)
|
262
|
+
def drop_till_start(all_items, start_key_hash, forward)
|
263
|
+
all_items = all_items.sort_by { |item| item.key }
|
264
|
+
|
265
|
+
unless forward
|
266
|
+
all_items = all_items.reverse
|
267
|
+
end
|
268
|
+
|
271
269
|
if start_key_hash
|
272
|
-
|
270
|
+
start_key = Key.from_data(start_key_hash, key_schema)
|
271
|
+
all_items.drop_while do |item|
|
272
|
+
if forward
|
273
|
+
item.key <= start_key
|
274
|
+
else
|
275
|
+
item.key >= start_key
|
276
|
+
end
|
277
|
+
end
|
273
278
|
else
|
274
279
|
all_items
|
275
280
|
end
|
data/lib/fake_dynamo/version.rb
CHANGED
@@ -373,7 +373,8 @@ module FakeDynamo
|
|
373
373
|
t = Table.new(data)
|
374
374
|
t.put_item(item)
|
375
375
|
(1..3).each do |i|
|
376
|
-
(1
|
376
|
+
(15.downto(1)).each do |j|
|
377
|
+
next if j.even?
|
377
378
|
item['Item']['AttributeName1']['S'] = "att#{i}"
|
378
379
|
item['Item']['AttributeName2']['N'] = j.to_s
|
379
380
|
t.put_item(item)
|
@@ -422,14 +423,32 @@ module FakeDynamo
|
|
422
423
|
|
423
424
|
it 'should handle scanindexforward' do
|
424
425
|
result = subject.query(query)
|
425
|
-
result['Items'].first['AttributeName2'].should eq({'N' => '
|
426
|
+
result['Items'].first['AttributeName2'].should eq({'N' => '3'})
|
426
427
|
result = subject.query(query.merge({'ScanIndexForward' => false}))
|
427
|
-
result['Items'].first['AttributeName2'].should eq({'N' => '
|
428
|
+
result['Items'].first['AttributeName2'].should eq({'N' => '15'})
|
429
|
+
|
430
|
+
query['ExclusiveStartKey'] = { 'HashKeyElement' => { 'S' => 'att1' }, 'RangeKeyElement' => { "N" => '7' }}
|
431
|
+
result = subject.query(query)
|
432
|
+
result['Items'][0]['AttributeName1'].should eq({'S' => 'att1'})
|
433
|
+
result['Items'][0]['AttributeName2'].should eq({'N' => '9'})
|
434
|
+
|
435
|
+
result = subject.query(query.merge({'ScanIndexForward' => false}))
|
436
|
+
result['Items'][0]['AttributeName1'].should eq({'S' => 'att1'})
|
437
|
+
result['Items'][0]['AttributeName2'].should eq({'N' => '5'})
|
438
|
+
|
439
|
+
query['ExclusiveStartKey'] = { 'HashKeyElement' => { 'S' => 'att1' }, 'RangeKeyElement' => { "N" => '8' }}
|
440
|
+
result = subject.query(query)
|
441
|
+
result['Items'][0]['AttributeName1'].should eq({'S' => 'att1'})
|
442
|
+
result['Items'][0]['AttributeName2'].should eq({'N' => '9'})
|
443
|
+
|
444
|
+
result = subject.query(query.merge({'ScanIndexForward' => false}))
|
445
|
+
result['Items'][0]['AttributeName1'].should eq({'S' => 'att1'})
|
446
|
+
result['Items'][0]['AttributeName2'].should eq({'N' => '7'})
|
428
447
|
end
|
429
448
|
|
430
449
|
it 'should return lastevaluated key' do
|
431
450
|
result = subject.query(query)
|
432
|
-
result['LastEvaluatedKey'].should == {"HashKeyElement"=>{"S"=>"att1"}, "RangeKeyElement"=>{"N"=>"
|
451
|
+
result['LastEvaluatedKey'].should == {"HashKeyElement"=>{"S"=>"att1"}, "RangeKeyElement"=>{"N"=>"11"}}
|
433
452
|
result = subject.query(query.merge('Limit' => 100))
|
434
453
|
result['LastEvaluatedKey'].should be_nil
|
435
454
|
|
@@ -439,14 +458,18 @@ module FakeDynamo
|
|
439
458
|
end
|
440
459
|
|
441
460
|
it 'should handle exclusive start key' do
|
442
|
-
result = subject.query(query.merge({'ExclusiveStartKey' => {"HashKeyElement"=>{"S"=>"att1"}, "RangeKeyElement"=>{"N"=>"
|
461
|
+
result = subject.query(query.merge({'ExclusiveStartKey' => {"HashKeyElement"=>{"S"=>"att1"}, "RangeKeyElement"=>{"N"=>"7"}}}))
|
443
462
|
result['Count'].should eq(4)
|
444
|
-
result['Items'].first['AttributeName2'].should eq({'N' => '
|
463
|
+
result['Items'].first['AttributeName2'].should eq({'N' => '9'})
|
464
|
+
result = subject.query(query.merge({'ExclusiveStartKey' => {"HashKeyElement"=>{"S"=>"att1"}, "RangeKeyElement"=>{"N"=>"8"}}}))
|
465
|
+
result['Count'].should eq(4)
|
466
|
+
result['Items'].first['AttributeName2'].should eq({'N' => '9'})
|
445
467
|
result = subject.query(query.merge({'ExclusiveStartKey' => {"HashKeyElement"=>{"S"=>"att1"}, "RangeKeyElement"=>{"N"=>"88"}}}))
|
446
468
|
result['Count'].should eq(0)
|
447
469
|
result['Items'].should be_empty
|
448
470
|
end
|
449
471
|
|
472
|
+
|
450
473
|
it 'should return all elements if not rangekeycondition is given' do
|
451
474
|
query.delete('RangeKeyCondition')
|
452
475
|
result = subject.query(query)
|
@@ -455,7 +478,7 @@ module FakeDynamo
|
|
455
478
|
|
456
479
|
it 'should handle between operator' do
|
457
480
|
query['RangeKeyCondition'] = {
|
458
|
-
'AttributeValueList' => [{'N' => '1'}, {'N' => '
|
481
|
+
'AttributeValueList' => [{'N' => '1'}, {'N' => '7'}],
|
459
482
|
'ComparisonOperator' => 'BETWEEN'
|
460
483
|
}
|
461
484
|
result = subject.query(query)
|
@@ -466,7 +489,7 @@ module FakeDynamo
|
|
466
489
|
query['AttributesToGet'] = ['AttributeName1', "AttributeName2"]
|
467
490
|
result = subject.query(query)
|
468
491
|
result['Items'].first.should eq('AttributeName1' => { 'S' => 'att1'},
|
469
|
-
'AttributeName2' => { 'N' => '
|
492
|
+
'AttributeName2' => { 'N' => '3' })
|
470
493
|
end
|
471
494
|
end
|
472
495
|
|
@@ -474,7 +497,8 @@ module FakeDynamo
|
|
474
497
|
subject do
|
475
498
|
t = Table.new(data)
|
476
499
|
(1..3).each do |i|
|
477
|
-
(1
|
500
|
+
(15.downto(1)).each do |j|
|
501
|
+
next if j.even?
|
478
502
|
item['Item']['AttributeName1']['S'] = "att#{i}"
|
479
503
|
item['Item']['AttributeName2']['N'] = j.to_s
|
480
504
|
t.put_item(item)
|
@@ -509,7 +533,7 @@ module FakeDynamo
|
|
509
533
|
|
510
534
|
it 'should handle basic scan' do
|
511
535
|
result = subject.scan(scan)
|
512
|
-
result['Count'].should eq(
|
536
|
+
result['Count'].should eq(24)
|
513
537
|
|
514
538
|
scan['ScanFilter']['AttributeName2']['ComparisonOperator'] = 'EQ'
|
515
539
|
subject.scan(scan)['Count'].should eq(3)
|
@@ -518,7 +542,7 @@ module FakeDynamo
|
|
518
542
|
it 'should return lastevaluated key' do
|
519
543
|
scan['Limit'] = 5
|
520
544
|
result = subject.scan(scan)
|
521
|
-
result['LastEvaluatedKey'].should == {"HashKeyElement"=>{"S"=>"att1"}, "RangeKeyElement"=>{"N"=>"
|
545
|
+
result['LastEvaluatedKey'].should == {"HashKeyElement"=>{"S"=>"att1"}, "RangeKeyElement"=>{"N"=>"9"}}
|
522
546
|
result = subject.scan(scan.merge('Limit' => 100))
|
523
547
|
result['LastEvaluatedKey'].should be_nil
|
524
548
|
|
@@ -526,6 +550,18 @@ module FakeDynamo
|
|
526
550
|
result = subject.scan(scan)
|
527
551
|
result['LastEvaluatedKey'].should be_nil
|
528
552
|
end
|
553
|
+
|
554
|
+
it 'should handle ordering' do
|
555
|
+
scan['ExclusiveStartKey'] = { 'HashKeyElement' => { 'S' => 'att2' }, 'RangeKeyElement' => { "N" => '7' }}
|
556
|
+
result = subject.scan(scan)
|
557
|
+
result['Items'][0]['AttributeName1'].should eq({'S' => 'att2'})
|
558
|
+
result['Items'][0]['AttributeName2'].should eq({'N' => '9'})
|
559
|
+
|
560
|
+
scan['ExclusiveStartKey'] = { 'HashKeyElement' => { 'S' => 'att2' }, 'RangeKeyElement' => { "N" => '8' }}
|
561
|
+
result['Items'][0]['AttributeName1'].should eq({'S' => 'att2'})
|
562
|
+
result['Items'][0]['AttributeName2'].should eq({'N' => '9'})
|
563
|
+
end
|
564
|
+
|
529
565
|
end
|
530
566
|
end
|
531
567
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fake_dynamo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-05
|
12
|
+
date: 2012-06-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sinatra
|
16
|
-
requirement: &
|
16
|
+
requirement: &70282333825460 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70282333825460
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: activesupport
|
27
|
-
requirement: &
|
27
|
+
requirement: &70282333824700 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70282333824700
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: json
|
38
|
-
requirement: &
|
38
|
+
requirement: &70282333823880 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70282333823880
|
47
47
|
description:
|
48
48
|
email:
|
49
49
|
- ananthakumaran@gmail.com
|