ddbcli 0.1.4 → 0.1.5

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 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