class Object
Public Instance Methods
evaluate_command(driver, cmd_arg)
click to toggle source
# File lib/ddbcli/cli/functions.rb, line 69 def evaluate_command(driver, cmd_arg) cmd, arg = cmd_arg.split(/\s+/, 2).map {|i| i.strip } arg = nil if (arg || '').strip.empty? r = /\A#{Regexp.compile(cmd)}/i commands = { 'help' => lambda { print_help(:pagerize => true) }, ['exit', 'quit'] => lambda { exit 0 }, 'timeout' => lambda { case arg when nil puts driver.timeout when /\d+/ driver.timeout = arg.to_i else print_error('Invalid argument') end }, 'consistent' => lambda { if arg r_arg = /\A#{Regexp.compile(arg)}/i if r_arg =~ 'true' driver.consistent = true elsif r_arg =~ 'false' driver.consistent = false else print_error('Invalid argument') end else puts driver.consistent end }, 'iteratable' => lambda { if arg r_arg = /\A#{Regexp.compile(arg)}/i if r_arg =~ 'true' driver.iteratable = true elsif r_arg =~ 'false' driver.iteratable = false else print_error('Invalid argument') end else puts driver.iteratable end }, 'retry' => lambda { case arg when nil puts driver.retry_num when /\d+/ driver.retry_num = arg.to_i else print_error('Invalid argument') end }, 'retry_interval' => lambda { case arg when nil puts driver.retry_intvl when /\d+/ driver.retry_intvl = arg.to_i else print_error('Invalid argument') end }, 'debug' => lambda { if arg r_arg = /\A#{Regexp.compile(arg)}/i if r_arg =~ 'true' driver.debug = true elsif r_arg =~ 'false' driver.debug = false else print_error('Invalid argument') end else puts driver.debug end }, 'version' => lambda { print_version } } cmd_name, cmd_proc = commands.find do |name, proc| if name.kind_of?(Array) name.any? {|i| r =~ i } else r =~ name end end if cmd_proc cmd_proc.call else print_error('Unknown command') end end
evaluate_query(driver, src, opts = {})
click to toggle source
# File lib/ddbcli/cli/evaluate.rb, line 1 def evaluate_query(driver, src, opts = {}) ss = StringScanner.new(src.dup) buf = '' until ss.eos? if (tok = ss.scan %r{[^`'";\\/#]+}) #' buf << tok elsif (tok = ss.scan /`(?:[^`]|``)*`/) buf << tok elsif (tok = ss.scan /'(?:[^']|'')*'/) #' buf << tok elsif (tok = ss.scan /"(?:[^"]|"")*"/) #" buf << tok elsif (tok = ss.scan %r{/\*/?(?:\n|[^/]|[^*]/)*\*/}) # nothing to do elsif (tok = ss.scan /--[^\r\n]*(?:\r\n|\r|\n|\Z)/) # nothing to do elsif (tok = ss.scan /#[^\r\n]*(?:\r\n|\r|\n|\Z)/) # nothing to do elsif (tok = ss.scan /(?:\\;)/) buf << ';' # escape of ';' elsif (tok = ss.scan /(?:;|\\G)/) src.replace(ss.rest) query = buf buf = '' if query.strip.empty? print_error('No query specified') next end start_time = Time.new out = driver.execute(query, opts.merge(:inline => (tok != '\G'))) elapsed = Time.now - start_time if out.kind_of?(DynamoDB::Driver::Rownum) print_rownum(out, opts.merge(:time => elapsed)) elsif out.kind_of?(String) puts out elsif out opts = opts.merge(:inline => (tok != '\G'), :time => elapsed) print_json(out, $stdout, opts) end elsif (tok = ss.scan /./) buf << tok # 落ち穂拾い end end src.replace(buf.strip) buf end
parse_options()
click to toggle source
# File lib/ddbcli/cli/options.rb, line 5 def parse_options options = OpenStruct.new options.access_key_id = ENV['AWS_ACCESS_KEY_ID'] options.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY'] options.ddb_endpoint_or_region = ENV['AWS_REGION'] || ENV['AWS_DEFAULT_REGION'] || ENV['DDB_ENDPOINT'] || ENV['DDB_REGION'] || 'dynamodb.us-east-1.amazonaws.com' # default value options.timeout = 60 options.consistent = false options.iteratable = false options.retry_num = 3 options.retry_intvl = 10 options.debug = false ARGV.options do |opt| opt.on('-k', '--access-key=ACCESS_KEY') {|v| options.access_key_id = v } opt.on('-s', '--secret-key=SECRET_KEY') {|v| options.secret_access_key = v } opt.on('-r', '--region=REGION_OR_ENDPOINT') {|v| options.ddb_endpoint_or_region = v } url_opt = proc do |v| uri = v uri = "http://#{uri}" unless uri =~ %r|\A\w+://| uri = URI.parse(uri) raise URI::InvalidURIError, "invalid shceme: #{v}" unless /\Ahttps?\Z/ =~ uri.scheme options.ddb_endpoint_or_region = uri end opt.on('', '--url=URL', &url_opt) opt.on('', '--uri=URL (DEPRECATION)', &url_opt) opt.on('-e', '--eval=COMMAND') {|v| options.command = v } opt.on('-t', '--timeout=SECOND', Integer) {|v| options.timeout = v.to_i } opt.on('', '--import=TABLE,JSON_FILE') {|v| v = v.split(/\s*,\s*/, 2) options.import = {:table => v[0], :file => v[1]} } opt.on('', '--consistent-read') { options.consistent = true } opt.on('', '--iteratable') { options.iteratable = true } opt.on('', '--retry=NUM', Integer) {|v| options.retry_num = v.to_i } opt.on('', '--retry-interval=SECOND', Integer) {|v| options.retry_intvl = v.to_i } opt.on('', '--debug') { options.debug = true } opt.on('-h', '--help') { puts opt.help exit } opt.parse! if options.ddb_endpoint_or_region.kind_of?(URI) and not (options.access_key_id and options.secret_access_key) options.access_key_id = 'scott' options.secret_access_key = 'tiger' puts 'Warning: dummy auth key was set because ACCESS_KEY/SECRET_KEY is not set' end unless options.access_key_id and options.secret_access_key and options.ddb_endpoint_or_region puts opt.help exit 1 end end options end
print_error(errmsg, opts = {})
click to toggle source
# File lib/ddbcli/cli/functions.rb, line 1 def print_error(errmsg, opts = {}) errmsg = errmsg.join("\n") if errmsg.kind_of?(Array) errmsg = errmsg.strip.split("\n").map {|i| "// #{i.strip}" }.join("\n") errmsg += "\n\n" unless opts[:strip] $stderr.puts errmsg end
print_help(options = {})
click to toggle source
# File lib/ddbcli/cli/help.rb, line 3 def print_help(options = {}) doc =<<EOS ##### Query ##### SHOW TABLES [LIMIT num] [LIKE '...'] display a table list SHOW TABLE STATUS [LIKE '...'] display table statues SHOW REGIONS display a region list SHOW CREATE TABLE table_name display a CREATE TABLE statement CREATE TABLE table_name ( key_name {STRING|NUMBER|BINARY} HASH [, key_name {STRING|NUMBER|BINARY} RANGE] [, INDEX index1_name (attr1 {STRING|NUMBER|BINARY}) {ALL|KEYS_ONLY|INCLUDE (attr, ...)} , INDEX index2_name (attr2 {STRING|NUMBER|BINARY}) {ALL|KEYS_ONLY|INCLUDE (attr, ...)} , ...] [, GLOBAL INDEX index1_name (hash_attr1 {STRING|NUMBER|BINARY} [, range_attr1 {STRING|NUMBER|BINARY}]) {ALL|KEYS_ONLY|INCLUDE (attr, ...)} [READ = num WRITE = num] , GLOBAL INDEX index2_name (hash_attr2 {STRING|NUMBER|BINARY} [, range_attr2 {STRING|NUMBER|BINARY}]) {ALL|KEYS_ONLY|INCLUDE (attr, ...)} [READ = num WRITE = num] , ...] ) READ = num WRITE = num [STREAM = {true|false|NEW_IMAGE|OLD_IMAGE|NEW_AND_OLD_IMAGES|KEYS_ONLY}] create a table CREATE TABLE table_name LIKE another_table_name [READ = num WRITE = num] [STREAM = {true|false|NEW_IMAGE|OLD_IMAGE|NEW_AND_OLD_IMAGES|KEYS_ONLY}] create a table like another table DROP TABLE table_name [, table_name2, ...] delete tables ALTER TABLE table_name {READ = num WRITE = num|STREAM = {true|false|NEW_IMAGE|OLD_IMAGE|NEW_AND_OLD_IMAGES|KEYS_ONLY}} update the provisioned throughput ALTER TABLE table_name CHANGE GLOBAL INDEX index_name READ = num WRITE = num update GSI provisioned throughput ALTER TABLE table_name ADD GLOBAL INDEX index_name (hash_attr1 {STRING|NUMBER|BINARY} [, range_attr1 {STRING|NUMBER|BINARY}]) {ALL|KEYS_ONLY|INCLUDE (attr, ...)} READ = num WRITE = num add GSI ALTER TABLE table_name DROP GLOBAL INDEX index_name delete GSI GET {*|attr1,attr2,...} FROM table_name WHERE key1 = '...' AND ... get items INSERT INTO table_name (attr1, attr2, ...) VALUES ('val1', 'val2', ...), ('val3', 'val4', ...), ... INSERT INTO table_name SELECT ... INSERT INTO table_name SELECT ALL ... create items UPDATE table_name {SET|ADD} attr1 = 'val1', ... WHERE key1 = '...' AND ... UPDATE ALL table_name {SET|ADD} attr1 = 'val1', ... [WHERE attr1 = '...' AND ...] [LIMIT limit] update items ("UPDATE" can update only one record. Please use "UPDATE ALL", when you update more than one.) UPDATE table_name DEL[ETE] attr1, ... WHERE key1 = '...' AND ... UPDATE ALL table_name DEL[ETE] attr1, ... [WHERE attr1 = '...' AND ...] [LIMIT limit] update items (delete attribute) DELETE FROM table_name WHERE key1 = '...' AND .. DELETE ALL FROM table_name WHERE [WHERE attr1 = '...' AND ...] [ORDER {ASC|DESC}] [LIMIT limit] delete items ("DELETE" can delete only one record. Please use "DELETE ALL", when you update more than one.) SELECT {*|attr1,attr2,...|COUNT(*)} FROM table_name [USE INDEX (index_name)] [WHERE key1 = '...' AND ...] [HAVING attr1 = '...' AND ...] [ORDER {ASC|DESC}] [LIMIT limit] SELECT ALL {*|attr1,attr2,...|COUNT(*)} FROM table_name [USE INDEX (index_name)] [WHERE attr1 = '...' AND ...] [LIMIT limit] SELECT segment/total_segments {*|attr1,attr2,...|COUNT(*)} FROM table_name [USE INDEX (index_name)] [WHERE attr1 = '...' AND ...] [LIMIT limit] query using the Query/Scan action see http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/QueryAndScan.html DESC[RIBE] table_name display information about the table USE region_or_endpoint change an endpoint NEXT display a continuation of a result (NEXT statement is published after SELECT statement) ##### Type ##### String 'London Bridge is...', "is falling down..." ... Number 10, 100, 0.3 ... Binary x'123456789abcd...', x"123456789abcd..." ... Identifier `ABCD...` or Non-keywords Set ('String', 'String', ...), (1, 2, 3, ...) List ['String', (1, 2, 3), {foo: 'FOO', bar: 'BAR'}, ...] Map {key1:'String', "key2":(1, 2, 3), key3: ['FOO', 'BAR'], ...} Bool true, false Null null ##### Operator ##### Query (SELECT) = | <= | < | >= | > | BEGINS_WITH | BETWEEN see http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html#DDB-Query-request-KeyConditions Scan (SELECT ALL), QueryFilter (HAVING) = | <> | != | <= | < | >= | > | IS NOT NULL | IS NULL | CONTAINS | NOT CONTAINS | BEGINS_WITH | IN | BETWEEN see http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html#DDB-Scan-request-ScanFilter, http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html#DDB-Query-request-QueryFilter ##### Pass to Ruby/Shell ##### Ryby query | ruby_script ex) SELECT ALL * FROM employees WHERE gender = 'M' | map {|i| Time.parse(i["birth_date"]) }; [ "1957-09-16 00:00:00 +0900", "1954-12-16 00:00:00 +0900", "1964-05-23 00:00:00 +0900", ... Shell query ! shell_command ex) SELECT ALL * FROM employees LIMIT 10 ! sort; {"birth_date"=>"1957-09-16", "emp_no"=>452020,... {"birth_date"=>"1963-07-14", "emp_no"=>16998, ... {"birth_date"=>"1964-04-30", "emp_no"=>225407,... ... ##### Output to a file ##### Overwrite SELECT ALL * FROM employees > 'foo.json'; Append SELECT ALL * FROM employees >> 'foo.json'; ##### Command ##### .help display this message .quit | .exit exit ddbcli .consistent (true|false)? display ConsistentRead parameter or changes it .iteratable (true|false)? display iteratable option or changes it all results are displayed if true .debug (true|false)? display a debug status or changes it .retry NUM? display number of times of a retry or changes it .retry_interval SECOND? display a retry interval second or changes it .timeout SECOND? display a timeout second or changes it .version display a version EOS if options[:pagerize] Tempfile.open("ddbcli.#{$$}.#{Time.now.to_i}") do |f| f.puts(doc) f.flush unless system("less #{f.path}") puts doc end end else puts doc end end
print_json(data, out, opts = {})
click to toggle source
# File lib/ddbcli/cli/functions.rb, line 21 def print_json(data, out, opts = {}) str = nil last_evaluated_key = nil if data.kind_of?(DynamoDB::Iteratorable) last_evaluated_key = data.last_evaluated_key data = data.data end if data.kind_of?(Array) and opts[:inline] str = "[\n" data.each_with_index do |item, i| str << " #{item.to_json}" str << ',' if i < (data.length - 1) str << "\n" end str << "]" else if data.kind_of?(Array) or data.kind_of?(Hash) str = JSON.pretty_generate(data) else str = data.to_json end end str.sub!(/(?:\r\n|\r|\n)*\Z/, "\n") if opts[:show_rows] if [Array, Hash].any? {|i| data.kind_of?(i) } str << "// #{data.length} #{data.length > 1 ? 'rows' : 'row'} in set" else str << '// 1 row in set' end str << " (%.2f sec)" % opts[:time] if opts[:time] str << "\n" end if last_evaluated_key str << "// has more\n" end str << "\n" unless opts[:strip] out.puts(str) end
print_rownum(data, opts = {})
click to toggle source
# File lib/ddbcli/cli/functions.rb, line 8 def print_rownum(data, opts = {}) rownum = data.to_i msg = "// #{rownum} #{rownum > 1 ? 'rows' : 'row'} changed" msg << " (%.2f sec)" % opts[:time] if opts[:time] msg << "\n" msg << "\n" unless opts[:strip] puts msg end
print_version()
click to toggle source
# File lib/ddbcli/cli/functions.rb, line 17 def print_version puts "#{File.basename($0)} #{Version}" end