ddbcli 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MzMzZGJiNzFlZDY4ZGUwM2VkOTA3MzA4NjgxMzUzZjgxMjAyNmE0MQ==
5
- data.tar.gz: !binary |-
6
- OGE3NGE3ZTVmMzhiMGRiNTllMWU3MGVmMjJkODczZTA1YmUzNDI2Ng==
2
+ SHA1:
3
+ metadata.gz: 920be6266d63a91338388bb5c64ee492192bf4ea
4
+ data.tar.gz: 294e678d52312af238381e8166e4fbe5dbdea1a3
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NmU1Nzc3MzM3ZjJhNWRhYjNjYWZlYmE0MTA1OTMxYjkwMTAxZDU3NzFhZjQz
10
- ZjIzZDhmNmRmYjkyNzEwZDllNGVhZGY3Zjk0ZTZkNTE0OGJhZTMxZGViZmJi
11
- ZjczYWI3MjQxMWZiY2FiNThiZDA4ZWRhN2E1ZGI3MWRlYjBkMTk=
12
- data.tar.gz: !binary |-
13
- ZDk5ODQ1NjBkMTIxNmZmM2E2ZTA4MjBiOGQ4Njc2ZDBjYmFmYWY3YjA4Zjgz
14
- YmU1MTYyMDhiNWM2N2VhOTcwYWE1NTEwZmZkNmQzMDcxMDk0OTZlN2JhODdh
15
- NDk0N2JlY2Y1MjRmY2MwYmQ5ZjUxMTk2MTlkYmY2MTMxY2E4ODI=
6
+ metadata.gz: 6a5a3d587336ca8ade3dd5dd41b5edd103bbb3d04784b113f003ef2a4fcf244fcbed1e3c29893cb6975fd42a697a70895ef88617394d4fd42829f1bbdfbd7ab0
7
+ data.tar.gz: 9eb0c49ec7d16c1f7ed09564dae0b229cffad4984d0f2bee0575595b52d438967fe7a4b6d1ad309fcbe8d40510b7d3f6d202e196e332af441eae2e7d3f24b5b3
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --require spec_helper
2
+ --colour
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ddbcli.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Genki Sugawara
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,197 @@
1
+ # ddbcli
2
+
3
+ ddbcli is an interactive command-line client of Amazon DynamoDB.
4
+
5
+ [![Build Status](https://drone.io/bitbucket.org/winebarrel/ddbcli/status.png)](https://drone.io/bitbucket.org/winebarrel/ddbcli/latest)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'ddbcli'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install ddbcli
20
+
21
+ ## Usage
22
+
23
+ ```sh
24
+ export AWS_ACCESS_KEY_ID='...'
25
+ export AWS_SECRET_ACCESS_KEY='...'
26
+ export AWS_REGION=ap-northeast-1
27
+
28
+ ddbcli -e 'show tables'
29
+ # [
30
+ # "employees"
31
+ # ]
32
+
33
+ ddbcli # show prompt
34
+ ```
35
+
36
+ ### Use DynamoDB Local
37
+
38
+ $ ddbcli --url localhost:8000
39
+
40
+ ## Demo
41
+
42
+ ![ddbcli demo](https://bitbucket.org/winebarrel/ddbcli/downloads/ddbcli-demo.gif)
43
+
44
+ ## Use GSI
45
+
46
+ * [https://gist.github.com/winebarrel/7938971](https://gist.github.com/winebarrel/7938971)
47
+
48
+ ## Help
49
+
50
+ ```
51
+ ##### Query #####
52
+
53
+ SHOW TABLES [LIMIT num] [LIKE '...']
54
+ displays a table list
55
+
56
+ SHOW TABLE STATUS [LIKE '...']
57
+ displays table statues
58
+
59
+ SHOW REGIONS
60
+ displays a region list
61
+
62
+ SHOW CREATE TABLE table_name
63
+ displays a CREATE TABLE statement
64
+
65
+ CREATE TABLES table_name (
66
+ key_name {STRING|NUMBER|BINARY} HASH
67
+ [, key_name {STRING|NUMBER|BINARY} RANGE]
68
+ [, INDEX index1_name (attr1 {STRING|NUMBER|BINARY}) {ALL|KEYS_ONLY|INCLUDE (attr, ...)}
69
+ , INDEX index2_name (attr2 {STRING|NUMBER|BINARY}) {ALL|KEYS_ONLY|INCLUDE (attr, ...)}
70
+ , ...]
71
+ [, GLOBAL INDEX index1_name (hash_attr1 {STRING|NUMBER|BINARY} [, range_attr1 {STRING|NUMBER|BINARY}]) {ALL|KEYS_ONLY|INCLUDE (attr, ...)} [READ = num WRITE = num]
72
+ , GLOBAL INDEX index2_name (hash_attr2 {STRING|NUMBER|BINARY} [, range_attr2 {STRING|NUMBER|BINARY}]) {ALL|KEYS_ONLY|INCLUDE (attr, ...)} [READ = num WRITE = num]
73
+ , ...]
74
+ ) READ = num WRITE = num
75
+ creates a table
76
+
77
+ CREATE TABLES table_name LIKE another_table_name [READ = num, WRITE = num]
78
+ creates a table like another table
79
+
80
+ DROP TABLE table_name
81
+ deletes a table
82
+
83
+ ALTER TABLE table_name READ = num WRITE = num
84
+ updates the provisioned throughput
85
+
86
+ GET {*|attr1,attr2,...} FROM table_name WHERE key1 = '...' AND ...
87
+ gets items
88
+
89
+ INSERT INTO table_name (attr1, attr2, ...) VALUES ('val1', 'val2', ...), ('val3', 'val4', ...), ...
90
+ INSERT INTO table_name SELECT ...
91
+ INSERT INTO table_name SELECT ALL ...
92
+ creates items
93
+
94
+ UPDATE table_name {SET|ADD} attr1 = 'val1', ... WHERE key1 = '...' AND ...
95
+ UPDATE ALL table_name {SET|ADD} attr1 = 'val1', ... [WHERE attr1 = '...' AND ...] [LIMIT limit]
96
+ updates items
97
+ ("UPDATE" can update only one record. Please use "UPDATE ALL", when you update more than one.)
98
+
99
+ DELETE FROM table_name WHERE key1 = '...' AND ..
100
+ DELETE ALL FROM table_name WHERE [WHERE attr1 = '...' AND ...] [ORDER {ASC|DESC}] [LIMIT limit]
101
+ deletes items
102
+ ("DELETE" can delete only one record. Please use "DELETE ALL", when you update more than one.)
103
+
104
+ SELECT {*|attr1,attr2,...|COUNT(*)} FROM table_name [USE INDEX (index_name)] [WHERE key1 = '...' AND ...] [ORDER {ASC|DESC}] [LIMIT limit]
105
+ SELECT ALL {*|attr1,attr2,...|COUNT(*)} FROM table_name [WHERE attr1 = '...' AND ...] [LIMIT limit]
106
+ SELECT segment/total_segments {*|attr1,attr2,...|COUNT(*)} FROM table_name [WHERE attr1 = '...' AND ...] [LIMIT limit]
107
+ queries using the Query/Scan action
108
+ see http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/QueryAndScan.html
109
+
110
+ DESC[RIBE] table_name
111
+ displays information about the table
112
+
113
+ USE region_or_endpoint
114
+ changes an endpoint
115
+
116
+ NEXT
117
+ displays a continuation of a result
118
+ (NEXT statement is published after SELECT statement)
119
+
120
+
121
+ ##### Type #####
122
+
123
+ String
124
+ 'London Bridge is...', "is broken down..." ...
125
+
126
+ Number
127
+ 10, 100, 0.3 ...
128
+
129
+ Binary
130
+ x'123456789abcd...', x"123456789abcd..." ...
131
+
132
+ Identifier
133
+ `ABCD...` or Non-keywords
134
+
135
+ Array
136
+ ('String', 'String', ...), (1, 2, 3, ...)
137
+
138
+
139
+ ##### Operator #####
140
+
141
+ Query (SELECT)
142
+ = | <= | < | >= | > | BEGINS_WITH | BETWEEN
143
+ see http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html#DDB-Query-request-KeyConditions
144
+
145
+ Scan (SELECT ALL)
146
+ = | <> | != | <= | < | >= | > | IS NOT NULL | IS NULL | CONTAINS | NOT CONTAINS | BEGINS_WITH | IN | BETWEEN
147
+ see http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html#DDB-Scan-request-ScanFilter
148
+
149
+
150
+ ##### Pass to Ruby/Shell #####
151
+
152
+ Ryby
153
+ query | ruby_script
154
+
155
+ ex) SELECT ALL * FROM employees WHERE gender = 'M' | birth_date.map {|i| Time.parse(i) };
156
+ [
157
+ "1957-09-16 00:00:00 +0900",
158
+ "1954-12-16 00:00:00 +0900",
159
+ "1964-05-23 00:00:00 +0900",
160
+ ...
161
+
162
+ Shell
163
+ query ! shell_command
164
+
165
+ ex) SELECT ALL * FROM employees LIMIT 10 ! sort;
166
+ {"birth_date"=>"1957-09-16", "emp_no"=>452020,...
167
+ {"birth_date"=>"1963-07-14", "emp_no"=>16998, ...
168
+ {"birth_date"=>"1964-04-30", "emp_no"=>225407,...
169
+ ...
170
+
171
+
172
+ ##### Output to a file #####
173
+
174
+ Overwrite
175
+ SELECT ALL * FROM employees > 'foo.json';
176
+
177
+ Append
178
+ SELECT ALL * FROM employees >> 'foo.json';
179
+
180
+
181
+ ##### Command #####
182
+
183
+ .help displays this message
184
+ .quit | .exit exits ddbcli
185
+ .consistent (true|false)? displays ConsistentRead parameter or changes it
186
+ .iteratable (true|false)? displays iteratable option or changes it
187
+ all results are displayed if true
188
+ .debug (true|false)? displays a debug status or changes it
189
+ .retry NUM? displays number of times of a retry or changes it
190
+ .retry_interval SECOND? displays a retry interval second or changes it
191
+ .timeout SECOND? displays a timeout second or changes it
192
+ .version displays a version
193
+ ```
194
+
195
+ ## Link
196
+
197
+ * [RubyGems.org site](http://rubygems.org/gems/ddbcli)
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new('spec')
5
+ task :default => :spec
data/bin/ddbcli CHANGED
@@ -1,8 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
3
3
 
4
- Version = '0.3.0'
5
-
6
4
  HISTORY_FILE = File.join((ENV['HOME'] || ENV['USERPROFILE'] || '.'), '.ddbcli_history')
7
5
  HISTSIZE = 500
8
6
 
data/ddbcli.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ddbcli/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'ddbcli'
8
+ spec.version = DynamoDB::VERSION
9
+ spec.authors = 'Genki Sugawara'
10
+ spec.email = 'sgwr_dts@yahoo.co.jp'
11
+ spec.description = 'ddbcli is an interactive command-line client of Amazon DynamoDB.'
12
+ spec.summary = spec.description
13
+ spec.homepage = 'https://bitbucket.org/winebarrel/ddbcli'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'json'
22
+ spec.add_development_dependency 'bundler', '~> 1.3'
23
+ spec.add_development_dependency 'rake'
24
+ spec.add_development_dependency 'rspec', '>= 2.14.1'
25
+ end
@@ -34,7 +34,7 @@ CREATE TABLES table_name LIKE another_table_name [READ = num, WRITE = num]
34
34
  DROP TABLE table_name
35
35
  deletes a table
36
36
 
37
- ALTER TABLE table_name READ = num, WRITE = num
37
+ ALTER TABLE table_name READ = num WRITE = num
38
38
  updates the provisioned throughput
39
39
 
40
40
  GET {*|attr1,attr2,...} FROM table_name WHERE key1 = '...' AND ...
@@ -48,10 +48,12 @@ INSERT INTO table_name SELECT ALL ...
48
48
  UPDATE table_name {SET|ADD} attr1 = 'val1', ... WHERE key1 = '...' AND ...
49
49
  UPDATE ALL table_name {SET|ADD} attr1 = 'val1', ... [WHERE attr1 = '...' AND ...] [LIMIT limit]
50
50
  updates items
51
+ ("UPDATE" can update only one record. Please use "UPDATE ALL", when you update more than one.)
51
52
 
52
53
  DELETE FROM table_name WHERE key1 = '...' AND ..
53
54
  DELETE ALL FROM table_name WHERE [WHERE attr1 = '...' AND ...] [ORDER {ASC|DESC}] [LIMIT limit]
54
55
  deletes items
56
+ ("DELETE" can delete only one record. Please use "DELETE ALL", when you update more than one.)
55
57
 
56
58
  SELECT {*|attr1,attr2,...|COUNT(*)} FROM table_name [USE INDEX (index_name)] [WHERE key1 = '...' AND ...] [ORDER {ASC|DESC}] [LIMIT limit]
57
59
  SELECT ALL {*|attr1,attr2,...|COUNT(*)} FROM table_name [WHERE attr1 = '...' AND ...] [LIMIT limit]
@@ -7,7 +7,7 @@ def parse_options
7
7
  options.access_key_id = ENV['AWS_ACCESS_KEY_ID']
8
8
  options.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
9
9
  options.ddb_endpoint_or_region =
10
- ENV['DDB_ENDPOINT'] || ENV['DDB_REGION'] || 'dynamodb.us-east-1.amazonaws.com'
10
+ ENV['AWS_REGION'] || ENV['DDB_ENDPOINT'] || ENV['DDB_REGION'] || 'dynamodb.us-east-1.amazonaws.com'
11
11
 
12
12
  # default value
13
13
  options.timeout = 60
@@ -22,13 +22,16 @@ def parse_options
22
22
  opt.on('-s', '--secret-key=SECRET_KEY') {|v| options.secret_access_key = v }
23
23
  opt.on('-r', '--region=REGION_OR_ENDPOINT') {|v| options.ddb_endpoint_or_region = v }
24
24
 
25
- opt.on('', '--uri=URI') {|v|
25
+ url_opt = proc do |v|
26
26
  uri = v
27
27
  uri = "http://#{uri}" unless uri =~ %r|\A\w+://|
28
28
  uri = URI.parse(uri)
29
29
  raise URI::InvalidURIError, "invalid shceme: #{v}" unless /\Ahttps?\Z/ =~ uri.scheme
30
30
  options.ddb_endpoint_or_region = uri
31
- }
31
+ end
32
+
33
+ opt.on('', '--url=URL', &url_opt)
34
+ opt.on('', '--uri=URL (DEPRECATION)', &url_opt)
32
35
 
33
36
  opt.on('-e', '--eval=COMMAND') {|v| options.command = v }
34
37
  opt.on('-t', '--timeout=SECOND', Integer) {|v| options.timeout = v.to_i }
@@ -388,21 +388,32 @@ module DynamoDB
388
388
  local_indices = (parsed.indices || []).select {|i| not i[:global] }
389
389
  global_indices = (parsed.indices || []).select {|i| i[:global] }
390
390
 
391
+ define_attribute = lambda do |attr_name, attr_type|
392
+ attr_defs = req_hash['AttributeDefinitions']
393
+ same_attr = attr_defs.find {|i| i['AttributeName'] == attr_name }
394
+
395
+ if same_attr
396
+ if same_attr['AttributeType'] != attr_type
397
+ raise DynamoDB::Error, "different types have been defined: #{attr_name}"
398
+ end
399
+ else
400
+ attr_defs << {
401
+ 'AttributeName' => attr_name,
402
+ 'AttributeType' => attr_type,
403
+ }
404
+ end
405
+ end
406
+
391
407
  define_index = lambda do |idx_def, def_idx_opts|
392
408
  global_idx = def_idx_opts[:global]
393
409
 
410
+
394
411
  if global_idx
395
412
  idx_def[:keys].each do |key_type, name_type|
396
- req_hash['AttributeDefinitions'] << {
397
- 'AttributeName' => name_type[:key],
398
- 'AttributeType' => name_type[:type],
399
- }
413
+ define_attribute.call(name_type[:key], name_type[:type])
400
414
  end
401
415
  else
402
- req_hash['AttributeDefinitions'] << {
403
- 'AttributeName' => idx_def[:key],
404
- 'AttributeType' => idx_def[:type],
405
- }
416
+ define_attribute.call(idx_def[:key], idx_def[:type])
406
417
  end
407
418
 
408
419
  secondary_index = {
@@ -0,0 +1,5 @@
1
+ module DynamoDB
2
+ VERSION = "0.3.1"
3
+ end
4
+
5
+ Version = DynamoDB::VERSION
data/lib/ddbcli.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'ddbcli/version'
2
+
1
3
  require 'ddbcli/ddb-binary'
2
4
  require 'ddbcli/ddb-client'
3
5
  require 'ddbcli/ddb-driver'
@@ -0,0 +1,196 @@
1
+ describe 'ddbcli' do
2
+ it 'version' do
3
+ out = ddbcli(nil, ['-v'])
4
+ expect(out).to match /ddbcli \d+\.\d+\.\d+/
5
+ end
6
+
7
+ it 'show tables' do
8
+ ddbcli(<<-'EOS')
9
+ CREATE TABLE `foo` (
10
+ `id` STRING HASH,
11
+ `val` STRING RANGE
12
+ ) read=2 write=2
13
+ EOS
14
+
15
+ out = ddbcli('show tables')
16
+ out = JSON.parse(out)
17
+ expect(out).to eq(['foo'])
18
+ end
19
+
20
+ it 'create table (hash only)' do
21
+ ddbcli(<<-'EOS')
22
+ CREATE TABLE `foo` (
23
+ `id` NUMBER HASH
24
+ ) read=2 write=2
25
+ EOS
26
+
27
+ out = ddbcli('desc foo')
28
+ out = JSON.parse(out)
29
+ out.delete('CreationDateTime')
30
+
31
+ expect(out).to eq(
32
+ {"AttributeDefinitions"=>[{"AttributeName"=>"id", "AttributeType"=>"N"}],
33
+ "TableName"=>"foo",
34
+ "KeySchema"=>[{"AttributeName"=>"id", "KeyType"=>"HASH"}],
35
+ "TableStatus"=>"ACTIVE",
36
+ "ProvisionedThroughput"=>
37
+ {"NumberOfDecreasesToday"=>0,
38
+ "ReadCapacityUnits"=>2,
39
+ "WriteCapacityUnits"=>2},
40
+ "TableSizeBytes"=>0,
41
+ "ItemCount"=>0}
42
+ )
43
+ end
44
+
45
+ it 'create table (hash and range)' do
46
+ ddbcli(<<-'EOS')
47
+ CREATE TABLE `foo` (
48
+ `id` NUMBER HASH,
49
+ `val` STRING RANGE
50
+ ) read=2 write=2
51
+ EOS
52
+
53
+ out = ddbcli('desc foo')
54
+ out = JSON.parse(out)
55
+ out.delete('CreationDateTime')
56
+
57
+ expect(out).to eq(
58
+ {"AttributeDefinitions"=>
59
+ [{"AttributeName"=>"id", "AttributeType"=>"N"},
60
+ {"AttributeName"=>"val", "AttributeType"=>"S"}],
61
+ "TableName"=>"foo",
62
+ "KeySchema"=>
63
+ [{"AttributeName"=>"id", "KeyType"=>"HASH"},
64
+ {"AttributeName"=>"val", "KeyType"=>"RANGE"}],
65
+ "TableStatus"=>"ACTIVE",
66
+ "ProvisionedThroughput"=>
67
+ {"NumberOfDecreasesToday"=>0,
68
+ "ReadCapacityUnits"=>2,
69
+ "WriteCapacityUnits"=>2},
70
+ "TableSizeBytes"=>0,
71
+ "ItemCount"=>0}
72
+ )
73
+ end
74
+
75
+ it 'create table with LSI' do
76
+ ddbcli(<<-'EOS')
77
+ CREATE TABLE `foo` (
78
+ `id` NUMBER HASH,
79
+ `val` STRING RANGE,
80
+ INDEX `idx_bar` (`val2` STRING) ALL
81
+ ) read=2 write=2
82
+ EOS
83
+
84
+ out = ddbcli('desc foo')
85
+ out = JSON.parse(out)
86
+ out.delete('CreationDateTime')
87
+
88
+ expect(out).to eq(
89
+ {"AttributeDefinitions"=>
90
+ [{"AttributeName"=>"id", "AttributeType"=>"N"},
91
+ {"AttributeName"=>"val", "AttributeType"=>"S"},
92
+ {"AttributeName"=>"val2", "AttributeType"=>"S"}],
93
+ "TableName"=>"foo",
94
+ "KeySchema"=>
95
+ [{"AttributeName"=>"id", "KeyType"=>"HASH"},
96
+ {"AttributeName"=>"val", "KeyType"=>"RANGE"}],
97
+ "TableStatus"=>"ACTIVE",
98
+ "ProvisionedThroughput"=>
99
+ {"NumberOfDecreasesToday"=>0,
100
+ "ReadCapacityUnits"=>2,
101
+ "WriteCapacityUnits"=>2},
102
+ "TableSizeBytes"=>0,
103
+ "ItemCount"=>0,
104
+ "LocalSecondaryIndexes"=>
105
+ [{"IndexName"=>"idx_bar",
106
+ "KeySchema"=>
107
+ [{"AttributeName"=>"id", "KeyType"=>"HASH"},
108
+ {"AttributeName"=>"val2", "KeyType"=>"RANGE"}],
109
+ "Projection"=>{"ProjectionType"=>"ALL"},
110
+ "IndexSizeBytes"=>0,
111
+ "ItemCount"=>0}]}
112
+ )
113
+ end
114
+
115
+ it 'create table with GSI' do
116
+ ddbcli(<<-'EOS')
117
+ CREATE TABLE `foo` (
118
+ `id` NUMBER HASH,
119
+ `val` STRING RANGE,
120
+ GLOBAL INDEX `idx_bar` (`val2` STRING) ALL read=1 write=1
121
+ ) read=2 write=2
122
+ EOS
123
+
124
+ out = ddbcli('desc foo')
125
+ out = JSON.parse(out)
126
+ out.delete('CreationDateTime')
127
+
128
+ expect(out).to eq(
129
+ {"AttributeDefinitions"=>
130
+ [{"AttributeName"=>"id", "AttributeType"=>"N"},
131
+ {"AttributeName"=>"val", "AttributeType"=>"S"},
132
+ {"AttributeName"=>"val2", "AttributeType"=>"S"}],
133
+ "TableName"=>"foo",
134
+ "KeySchema"=>
135
+ [{"AttributeName"=>"id", "KeyType"=>"HASH"},
136
+ {"AttributeName"=>"val", "KeyType"=>"RANGE"}],
137
+ "TableStatus"=>"ACTIVE",
138
+ "ProvisionedThroughput"=>
139
+ {"NumberOfDecreasesToday"=>0,
140
+ "ReadCapacityUnits"=>2,
141
+ "WriteCapacityUnits"=>2},
142
+ "TableSizeBytes"=>0,
143
+ "ItemCount"=>0,
144
+ "GlobalSecondaryIndexes"=>
145
+ [{"IndexName"=>"idx_bar",
146
+ "KeySchema"=>[{"AttributeName"=>"val2", "KeyType"=>"HASH"}],
147
+ "Projection"=>{"ProjectionType"=>"ALL"},
148
+ "IndexStatus"=>"ACTIVE",
149
+ "ProvisionedThroughput"=>{"ReadCapacityUnits"=>1, "WriteCapacityUnits"=>1},
150
+ "IndexSizeBytes"=>0,
151
+ "ItemCount"=>0}]}
152
+ )
153
+ end
154
+
155
+ it 'create table with GSI' do
156
+ ddbcli(<<-'EOS')
157
+ CREATE TABLE `foo` (
158
+ `id` NUMBER HASH,
159
+ `val` STRING RANGE,
160
+ GLOBAL INDEX `idx_bar` (`val2` STRING) ALL read=1 write=1
161
+ ) read=2 write=2
162
+ EOS
163
+
164
+ out = ddbcli('alter table foo read=4 write=4')
165
+
166
+ out = ddbcli('desc foo')
167
+ out = JSON.parse(out)
168
+ out.delete('CreationDateTime')
169
+
170
+ expect(out).to eq(
171
+ {"AttributeDefinitions"=>
172
+ [{"AttributeName"=>"id", "AttributeType"=>"N"},
173
+ {"AttributeName"=>"val", "AttributeType"=>"S"},
174
+ {"AttributeName"=>"val2", "AttributeType"=>"S"}],
175
+ "TableName"=>"foo",
176
+ "KeySchema"=>
177
+ [{"AttributeName"=>"id", "KeyType"=>"HASH"},
178
+ {"AttributeName"=>"val", "KeyType"=>"RANGE"}],
179
+ "TableStatus"=>"ACTIVE",
180
+ "ProvisionedThroughput"=>
181
+ {"NumberOfDecreasesToday"=>0,
182
+ "ReadCapacityUnits"=>4,
183
+ "WriteCapacityUnits"=>4},
184
+ "TableSizeBytes"=>0,
185
+ "ItemCount"=>0,
186
+ "GlobalSecondaryIndexes"=>
187
+ [{"IndexName"=>"idx_bar",
188
+ "KeySchema"=>[{"AttributeName"=>"val2", "KeyType"=>"HASH"}],
189
+ "Projection"=>{"ProjectionType"=>"ALL"},
190
+ "IndexStatus"=>"ACTIVE",
191
+ "ProvisionedThroughput"=>{"ReadCapacityUnits"=>1, "WriteCapacityUnits"=>1},
192
+ "IndexSizeBytes"=>0,
193
+ "ItemCount"=>0}]}
194
+ )
195
+ end
196
+ end