ddbcli 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -26,6 +26,7 @@ https://bitbucket.org/winebarrel/ddbcli
26
26
  -r, --region=REGION_OR_ENDPOINT
27
27
  -e, --eval=COMMAND
28
28
  -t, --timeout=SECOND
29
+ --import=TABLE,JSON_FILE
29
30
  --consistent-read
30
31
  --retry=NUM
31
32
  --retry-interval=SECOND
@@ -56,6 +57,9 @@ https://bitbucket.org/winebarrel/ddbcli
56
57
  ) READ = num, WRITE = num
57
58
  creates a table
58
59
 
60
+ CREATE TABLES table_name LIKE another_table_name [READ = num, WRITE = num]
61
+ creates a table like another table
62
+
59
63
  DROP TABLE table_name
60
64
  deletes a table
61
65
 
data/bin/ddbcli CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
3
3
 
4
- Version = '0.1.4'
4
+ Version = '0.1.5'
5
5
 
6
6
  HISTORY_FILE = File.join((ENV['HOME'] || ENV['USERPROFILE'] || '.'), '.ddbcli_history')
7
7
  HISTSIZE = 500
@@ -24,7 +24,13 @@ driver.retry_num = options.retry_num
24
24
  driver.retry_intvl = options.retry_intvl
25
25
  driver.debug = options.debug
26
26
 
27
- if not $stdin.tty? or options.command
27
+ if options.import
28
+ # import mode
29
+ table, file = options.import.values_at(:table, :file)
30
+ items = open(file) {|f| JSON.load(f) }
31
+ n = driver.import(table, items)
32
+ print_rownum(n)
33
+ elsif not $stdin.tty? or options.command
28
34
 
29
35
  # run mode
30
36
  src = options.command || $stdin.read.strip
@@ -20,6 +20,9 @@ CREATE TABLES table_name (
20
20
  ) READ = num, WRITE = num
21
21
  creates a table
22
22
 
23
+ CREATE TABLES table_name LIKE another_table_name [READ = num, WRITE = num]
24
+ creates a table like another table
25
+
23
26
  DROP TABLE table_name
24
27
  deletes a table
25
28
 
@@ -22,6 +22,12 @@ def parse_options
22
22
  opt.on('-r', '--region=REGION_OR_ENDPOINT') {|v| options.ddb_endpoint_or_region = v }
23
23
  opt.on('-e', '--eval=COMMAND') {|v| options.command = v }
24
24
  opt.on('-t', '--timeout=SECOND', Integer) {|v| options.timeout = v.to_i }
25
+
26
+ opt.on('', '--import=TABLE,JSON_FILE') {|v|
27
+ v = v.split(/\s*,\s*/, 2)
28
+ options.import = {:table => v[0], :file => v[1]}
29
+ }
30
+
25
31
  opt.on('', '--consistent-read') { options.consistent = true }
26
32
  opt.on('', '--iteratable') { options.iteratable = true }
27
33
  opt.on('', '--retry=NUM', Integer) {|v| options.retry_num = v.to_i }
@@ -62,6 +62,8 @@ module DynamoDB
62
62
  do_use(parsed)
63
63
  when :CREATE
64
64
  do_create(parsed)
65
+ when :CREATE_LIKE
66
+ do_create_like(parsed)
65
67
  when :DROP
66
68
  do_drop(parsed)
67
69
  when :DESCRIBE
@@ -94,25 +96,58 @@ module DynamoDB
94
96
  raise 'must not happen'
95
97
  end
96
98
 
97
- begin
98
- case script_type
99
- when :ruby
100
- retval = retval.data if retval.kind_of?(DynamoDB::Iteratorable)
101
- retval.instance_eval(script)
102
- when :shell
103
- retval = retval.data if retval.kind_of?(DynamoDB::Iteratorable)
104
- IO.popen(script, "r+") do |f|
105
- f.puts(retval.kind_of?(Array) ? retval.map {|i| i.to_s }.join("\n") : retval.to_s)
106
- f.close_write
107
- f.read
108
- end
109
- else
110
- retval
111
- end
112
- rescue Exception => e
113
- raise DynamoDB::Error, e.message, e.backtrace
114
- end
115
- end
99
+ begin
100
+ case script_type
101
+ when :ruby
102
+ retval = retval.data if retval.kind_of?(DynamoDB::Iteratorable)
103
+ retval.instance_eval(script)
104
+ when :shell
105
+ retval = retval.data if retval.kind_of?(DynamoDB::Iteratorable)
106
+ IO.popen(script, "r+") do |f|
107
+ f.puts(retval.kind_of?(Array) ? retval.map {|i| i.to_s }.join("\n") : retval.to_s)
108
+ f.close_write
109
+ f.read
110
+ end
111
+ else
112
+ retval
113
+ end
114
+ rescue Exception => e
115
+ raise DynamoDB::Error, e.message, e.backtrace
116
+ end
117
+ end
118
+
119
+ def import(table, items)
120
+ n = 0
121
+
122
+ until (chunk = items.slice!(0, MAX_NUMBER_BATCH_PROCESS_ITEMS)).empty?
123
+ operations = []
124
+
125
+ req_hash = {
126
+ 'RequestItems' => {
127
+ table => operations,
128
+ },
129
+ }
130
+
131
+ chunk.each do |item|
132
+ h = {}
133
+
134
+ operations << {
135
+ 'PutRequest' => {
136
+ 'Item' => h,
137
+ },
138
+ }
139
+
140
+ item.each do |name, val|
141
+ h[name] = convert_to_attribute_value(val)
142
+ end
143
+ end
144
+
145
+ batch_write_item(req_hash)
146
+ n += chunk.length
147
+ end
148
+
149
+ return n
150
+ end
116
151
 
117
152
  private
118
153
 
@@ -303,6 +338,42 @@ module DynamoDB
303
338
  nil
304
339
  end
305
340
 
341
+ def do_create_like(parsed)
342
+ table_info = @client.query('DescribeTable', 'TableName' => parsed.like)['Table']
343
+
344
+ req_hash = {
345
+ 'TableName' => parsed.table,
346
+ 'AttributeDefinitions' => table_info['AttributeDefinitions'],
347
+ 'KeySchema' => table_info['KeySchema'],
348
+ }
349
+
350
+ local_secondary_indexes = (table_info['LocalSecondaryIndexes'] || [])
351
+
352
+ unless local_secondary_indexes.empty?
353
+ req_hash['LocalSecondaryIndexes'] = local_secondary_indexes.map do |lsi|
354
+ h = {}
355
+
356
+ %w(IndexName KeySchema Projection).each do |i|
357
+ h[i] = lsi[i]
358
+ end
359
+
360
+ h
361
+ end
362
+ end
363
+
364
+ if parsed.capacity
365
+ req_hash['ProvisionedThroughput'] = {
366
+ 'ReadCapacityUnits' => parsed.capacity[:read],
367
+ 'WriteCapacityUnits' => parsed.capacity[:write],
368
+ }
369
+ else
370
+ req_hash['ProvisionedThroughput'] = table_info['ProvisionedThroughput']
371
+ end
372
+
373
+ @client.query('CreateTable', req_hash)
374
+ nil
375
+ end
376
+
306
377
  def do_drop(parsed)
307
378
  @client.query('DeleteTable', 'TableName' => parsed.table)
308
379
  nil