sdbcli 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,48 @@
1
+ = sdbcli
2
+
3
+ == Description
4
+
5
+ sdbcli is command line client of Amazon SimpleDB.
6
+
7
+ == Source Code
8
+
9
+ https://bitbucket.org/winebarrel/sdbcli
10
+
11
+ == Install
12
+
13
+ shell> gem install sdbcli
14
+ shell> export AWS_ACCESS_KEY_ID='...'
15
+ shell> export AWS_SECRET_ACCESS_KEY='...'
16
+ shell> export SDB_ENDPOINT='sdb.ap-northeast-1.amazonaws.com'
17
+ shell> sdbcli
18
+
19
+ == Example
20
+
21
+ ap-northeast-1> help
22
+ commands:
23
+ show domains
24
+ create domain domain_name
25
+ drop domain domain_name
26
+ get [output_list] from domain_name where itemname = '...'
27
+ insert into domain_name (itemname, attr1, attr2, ...) values ('name', 'val1', 'val2', ...)
28
+ update domain_name set attr1 = 'val1', attr2 = 'val2', ... where itemname = '...'
29
+ delete [attr1, attr2, ...] from domain_name itemname = '...'
30
+ select output_list from domain_name [where expression] [sort_instructions] [limit limit]
31
+ ap-northeast-1> select * from test
32
+ ---
33
+ - - itemname1
34
+ - attr1: val1
35
+ attr2: val2
36
+ - - itemname2
37
+ - attr1: val1
38
+ attr2: val2
39
+
40
+ shell> echo 'select * from test' | sdbcli
41
+ ---
42
+ - - itemname1
43
+ - attr1: val1
44
+ attr2: val2
45
+ - - itemname2
46
+ - attr1: val1
47
+ attr2: val2
48
+
data/bin/sdbcli ADDED
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
3
+
4
+ require 'rubygems'
5
+ require 'sdbcli'
6
+
7
+ require 'optparse'
8
+ require 'readline'
9
+ require 'yaml'
10
+
11
+ access_key_id = ENV['AWS_ACCESS_KEY_ID']
12
+ secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
13
+ sdb_endpoint = ENV['SDB_ENDPOINT'] || 'sdb.amazonaws.com'
14
+
15
+ ARGV.options do |opt|
16
+ opt.on('-k', '--access-key-id=AWS_ACCESS_KEY_ID') {|v| access_key_id = v }
17
+ opt.on('-s', '--secret-access-key=AWS_SECRET_ACCESS_KEY') {|v| secret_access_key = v }
18
+ opt.on('-e', '--endpoint=SDB_ENDPOINT') {|v| sdb_endpoint = v }
19
+ opt.parse!
20
+
21
+ unless access_key_id and secret_access_key and sdb_endpoint
22
+ puts opt.help
23
+ exit 1
24
+ end
25
+ end
26
+
27
+ $runner = SimpleDB::Runner.new(access_key_id, secret_access_key, sdb_endpoint)
28
+
29
+ def execute(query)
30
+ out = $runner.execute(query)
31
+ puts YAML.dump(out) if out
32
+ end
33
+
34
+ unless $stdin.tty?
35
+ execute($stdin.read)
36
+ exit 0
37
+ end
38
+
39
+ if sdb_endpoint =~ /sdb\.([^.]+)\.amazonaws\.com/
40
+ region = $1
41
+ else
42
+ region = 'us-east-1'
43
+ end
44
+
45
+ def help
46
+ <<-EOS
47
+ commands:
48
+ show domains
49
+ create domain domain_name
50
+ drop domain domain_name
51
+ get [output_list] from domain_name where itemname = '...'
52
+ insert into domain_name (itemname, attr1, attr2, ...) values ('name', 'val1', 'val2', ...)
53
+ update domain_name set attr1 = 'val1', attr2 = 'val2', ... where itemname = '...'
54
+ delete [attr1, attr2, ...] from domain_name itemname = '...'
55
+ select output_list from domain_name [where expression] [sort_instructions] [limit limit]
56
+ EOS
57
+ end
58
+
59
+ while buf = Readline.readline("#{region}> ", true)
60
+ begin
61
+ case buf.downcase
62
+ when 'help'
63
+ puts help
64
+ when 'exit', 'quit'
65
+ exit
66
+ else
67
+ execute(buf.sub(/;\Z/, ''))
68
+ end
69
+ rescue => e
70
+ puts e.message
71
+ end
72
+ end
@@ -0,0 +1,128 @@
1
+ require 'cgi'
2
+ require 'base64'
3
+ require 'net/https'
4
+ require 'openssl'
5
+ require 'nokogiri'
6
+
7
+ module SimpleDB
8
+ class Error < StandardError; end
9
+
10
+ class Client
11
+ API_VERSION = '2009-04-15'
12
+ SIGNATURE_VERSION = 2
13
+ SIGNATURE_ALGORITHM = :SHA256
14
+
15
+ attr_accessor :endpoint
16
+
17
+ def initialize(accessKeyId, secretAccessKey, endpoint = 'sdb.amazonaws.com')
18
+ @accessKeyId = accessKeyId
19
+ @secretAccessKey = secretAccessKey
20
+ @endpoint = endpoint
21
+ end
22
+
23
+ # domain action
24
+
25
+ def create_domain(domain_name, params = {})
26
+ params = params.merge(:DomainName => domain_name)
27
+ query('CreateDomain', params)
28
+ end
29
+
30
+ def list_domains(params = {})
31
+ query('ListDomains', params)
32
+ end
33
+
34
+ def delete_domain(domain_name, params = {})
35
+ params = params.merge(:DomainName => domain_name)
36
+ query('DeleteDomain', params)
37
+ end
38
+
39
+ # attr action
40
+
41
+ def put_attributes(domain_name, item_name, params = {})
42
+ params = params.merge(:DomainName => domain_name, :ItemName => item_name)
43
+ query('PutAttributes', params)
44
+ end
45
+
46
+ def get_attributes(domain_name, item_name, params = {})
47
+ params = params.merge(:DomainName => domain_name, :ItemName => item_name)
48
+ query('GetAttributes', params)
49
+ end
50
+
51
+ def select(params = {})
52
+ query('Select', params)
53
+ end
54
+
55
+ def delete_attributes(domain_name, item_name, params = {})
56
+ params = params.merge(:DomainName => domain_name, :ItemName => item_name)
57
+ query('DeleteAttributes', params)
58
+ end
59
+
60
+ # batch attr action
61
+
62
+ def batch_put_attributes(domain_name, params = {})
63
+ params = params.merge(:DomainName => domain_name)
64
+ query('BatchPutAttributes', params)
65
+ end
66
+
67
+ def batch_delete_attributes(domain_name, params = {})
68
+ params = params.merge(:DomainName => domain_name)
69
+ query('BatchDeleteAttributes', params)
70
+ end
71
+
72
+ private
73
+
74
+ def query(action, params = {})
75
+ params = {
76
+ :Action => action,
77
+ :Version => API_VERSION,
78
+ :Timestamp => Time.now.getutc.strftime('%Y-%m-%dT%H:%M:%SZ'),
79
+ :SignatureVersion => SIGNATURE_VERSION,
80
+ :SignatureMethod => "Hmac#{SIGNATURE_ALGORITHM}",
81
+ :AWSAccessKeyId => @accessKeyId,
82
+ }.merge(params)
83
+
84
+ signature = aws_sign(params)
85
+ params[:Signature] = signature
86
+
87
+ Net::HTTP.version_1_2
88
+ https = Net::HTTP.new(@endpoint, 443)
89
+ https.use_ssl = true
90
+ https.verify_mode = OpenSSL::SSL::VERIFY_NONE
91
+
92
+ doc = https.start do |w|
93
+ req = Net::HTTP::Post.new('/',
94
+ 'Host' => @endpoint,
95
+ 'Content-Type' => 'application/x-www-form-urlencoded'
96
+ )
97
+
98
+ req.set_form_data(params)
99
+ res = w.request(req)
100
+
101
+ Nokogiri::XML(res.body)
102
+ end
103
+
104
+ validate(doc)
105
+ return doc
106
+ end
107
+
108
+ private
109
+ def aws_sign(params)
110
+ params = params.sort_by {|a, b| a.to_s }.map {|k, v| "#{escape(k)}=#{escape(v)}" }.join('&')
111
+ string_to_sign = "POST\n#{@endpoint}\n/\n#{params}"
112
+ digest = OpenSSL::HMAC.digest(OpenSSL::Digest.const_get(SIGNATURE_ALGORITHM).new, @secretAccessKey, string_to_sign)
113
+ Base64.encode64(digest).gsub("\n", '')
114
+ end
115
+
116
+ def validate(doc)
117
+ if (error = doc.at_css('Errors Error'))
118
+ code = error.at_css('Code').content
119
+ message = error.at_css('Message').content
120
+ raise Error, "#{code}: #{message}"
121
+ end
122
+ end
123
+
124
+ def escape(str)
125
+ CGI.escape(str.to_s).gsub('+', '%20')
126
+ end
127
+ end # Client
128
+ end # SimpleDB
@@ -0,0 +1,165 @@
1
+ require 'sdbcli/sdb-client'
2
+
3
+ module SimpleDB
4
+ class Error < StandardError; end
5
+
6
+ class Driver
7
+ def initialize(accessKeyId, secretAccessKey, endpoint = 'sdb.amazonaws.com')
8
+ @client = Client.new(accessKeyId, secretAccessKey, endpoint)
9
+ end
10
+
11
+ def endpoint
12
+ @client.endpoint
13
+ end
14
+
15
+ def endpoint=(v)
16
+ @client.endpoint = v
17
+ end
18
+
19
+ # domain action
20
+
21
+ def create_domain(domain_name)
22
+ @client.create_domain(domain_name)
23
+ end
24
+
25
+ def show_domains
26
+ domains = []
27
+
28
+ iterate(:list_domains) do |doc|
29
+ doc.css('DomainName').each do |i|
30
+ domains << i.content
31
+ end
32
+ end
33
+
34
+ return domains
35
+ end
36
+
37
+ def drop_domain(domain_name)
38
+ @client.delete_domain(domain_name)
39
+ end
40
+
41
+ # attr action
42
+
43
+ def insert(domain_name, item_name, attrs = {}, consistent = false)
44
+ params = {:ConsistentRead => consistent}
45
+ i = 0
46
+
47
+ attrs.each do |name, values|
48
+ [values].flatten.each do |v|
49
+ i += 1
50
+ params["Attribute.#{i}.Name"] = name
51
+ params["Attribute.#{i}.Value"] = v
52
+ params["Attribute.#{i}.Replace"] = false
53
+ end
54
+ end
55
+
56
+ @client.put_attributes(domain_name, item_name, params)
57
+ end
58
+
59
+ def update(domain_name, items = {}, consistent = false)
60
+ params = {:ConsistentRead => consistent}
61
+ i = j = 0
62
+
63
+ items.each do |item_name, attrs|
64
+ i += 1
65
+ params["Item.#{i}.ItemName"] = item_name
66
+
67
+ (attrs || {}).each do |attr_name, values|
68
+ [values].flatten.each do |v|
69
+ j += 1
70
+ params["Item.#{i}.Attribute.#{j}.Name"] = attr_name
71
+ params["Item.#{i}.Attribute.#{j}.Value"] = v
72
+ params["Item.#{i}.Attribute.#{j}.Replace"] = true
73
+ end
74
+ end
75
+ end
76
+
77
+ @client.batch_put_attributes(domain_name, params)
78
+ end
79
+
80
+ def get(domain_name, item_name, attr_names = [], consistent = false)
81
+ params = {:ConsistentRead => consistent}
82
+ attr_names.each_with_index {|name, i| params["AttributeName.#{i}"] = name }
83
+ doc = @client.get_attributes(domain_name, item_name, params)
84
+ attrs_to_hash(doc)
85
+ end
86
+
87
+ def select(expr, consistent = false)
88
+ params = {:SelectExpression => expr, :ConsistentRead => consistent}
89
+ items = []
90
+
91
+ iterate(:select, params) do |doc|
92
+ doc.css('Item').map do |i|
93
+ items << [i.at_css('Name').content, attrs_to_hash(i)]
94
+ end
95
+ end
96
+
97
+ return items
98
+ end
99
+
100
+ def delete(domain_name, items = {}, consistent = false)
101
+ params = {:ConsistentRead => consistent}
102
+ i = j = 0
103
+
104
+ items.each do |item_name, attrs|
105
+ i += 1
106
+ params["Item.#{i}.ItemName"] = item_name
107
+
108
+ (attrs || []).each do |attr_name, values|
109
+ [values].flatten.each do |v|
110
+ j += 1
111
+ params["Item.#{i}.Attribute.#{j}.Name"] = attr_name
112
+ params["Item.#{i}.Attribute.#{j}.Value"] = v if v
113
+ end
114
+ end
115
+ end
116
+
117
+ @client.batch_delete_attributes(domain_name, params)
118
+ end
119
+
120
+ private
121
+
122
+ def attrs_to_hash(node)
123
+ h = {}
124
+
125
+ node.css('Attribute').map do |i|
126
+ name = i.at_css('Name').content
127
+ value = i.at_css('Value').content
128
+
129
+ if h[name].kind_of?(Array)
130
+ h[name] << value
131
+ elsif h.has_key?(name)
132
+ h[name] = [h[name], value]
133
+ else
134
+ h[name] = value
135
+ end
136
+ end
137
+
138
+ return h
139
+ end
140
+
141
+ def iterate(method, params = {})
142
+ Iterator.new(@client, method, params).each do |doc|
143
+ yield(doc)
144
+ end
145
+ end
146
+
147
+ class Iterator
148
+ def initialize(client, method, params = {})
149
+ @client = client
150
+ @method = method
151
+ @params = params.dup
152
+ @token = :first
153
+ end
154
+
155
+ def each
156
+ while @token
157
+ @params.update(:NextToken => @token.content) if @token != :first
158
+ doc = @client.send(@method, @params)
159
+ yield(doc)
160
+ @token = doc.at_css('NextToken')
161
+ end
162
+ end
163
+ end # Iterator
164
+ end # Driver
165
+ end # SimpleDB
@@ -0,0 +1,466 @@
1
+ #
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by racc 1.4.5
4
+ # from racc grammer file "sdb-parser.y".
5
+ #
6
+
7
+ require 'racc/parser'
8
+
9
+
10
+
11
+ require 'strscan'
12
+
13
+ module SimpleDB
14
+
15
+
16
+ class Parser < Racc::Parser
17
+
18
+ module_eval <<'..end sdb-parser.y modeval..idc908e49d79', 'sdb-parser.y', 119
19
+
20
+ KEYWORDS = %w(
21
+ AND
22
+ ASC
23
+ BETWEEN
24
+ BY
25
+ CREATE
26
+ DELETE
27
+ DESC
28
+ DOMAINS
29
+ DOMAIN
30
+ DROP
31
+ EVERY
32
+ FROM
33
+ GET
34
+ INSERT
35
+ INTERSECTION
36
+ INTO
37
+ IN
38
+ IS
39
+ ITEMNAME
40
+ LIKE
41
+ LIMIT
42
+ NOT
43
+ ORDER
44
+ OR
45
+ SET
46
+ SHOW
47
+ UPDATE
48
+ VALUES
49
+ WHERE
50
+ )
51
+
52
+ KEYWORD_REGEXP = Regexp.compile("#{KEYWORDS.join '|'}\\b", Regexp::IGNORECASE)
53
+
54
+ def initialize(obj)
55
+ src = obj.is_a?(IO) ? obj.read : obj.to_s
56
+ @ss = StringScanner.new(src)
57
+ end
58
+
59
+ @@structs = {}
60
+
61
+ def struct(name, attrs = {})
62
+ unless (clazz = @@structs[name])
63
+ clazz = attrs.empty? ? Struct.new(name.to_s) : Struct.new(name.to_s, *attrs.keys)
64
+ @@structs[name] = clazz
65
+ end
66
+
67
+ obj = clazz.new
68
+
69
+ attrs.each do |key, val|
70
+ obj.send("#{key}=", val)
71
+ end
72
+
73
+ return obj
74
+ end
75
+ private :struct
76
+
77
+ def scan
78
+ tok = nil
79
+
80
+ until @ss.eos?
81
+ if (tok = @ss.scan /\s+/)
82
+ # nothing to do
83
+ elsif (tok = @ss.scan /(?:!=|>=|<=|>|<|=)/)
84
+ yield tok, tok
85
+ elsif (tok = @ss.scan KEYWORD_REGEXP)
86
+ yield tok.upcase.to_sym, tok
87
+ elsif (tok = @ss.scan /SELECT\b/i)
88
+ yield :SELECT, tok + @ss.scan(/.*/)
89
+ elsif (tok = @ss.scan /NULL\b/i)
90
+ yield :NULL, nil
91
+ elsif (tok = @ss.scan /`([^`]|``)*`/)
92
+ yield :IDENTIFIER, tok.slice(1...-1).gsub(/``/, '`')
93
+ elsif (tok = @ss.scan /'([^']|'')*'/) #'
94
+ yield :VALUE, tok.slice(1...-1).gsub(/''/, "'")
95
+ elsif (tok = @ss.scan /"([^"]|"")*"/) #"
96
+ yield :VALUE, tok.slice(1...-1).gsub(/""/, '"')
97
+ elsif (tok = @ss.scan /(0|[1-9]\d*)/)
98
+ yield :NATURAL_NUMBER, tok.to_i
99
+ elsif (tok = @ss.scan /[,\(\)\*]/)
100
+ yield tok, tok
101
+ elsif (tok = @ss.scan /[a-z_$][0-9a-z_$]*\b/i)
102
+ yield :IDENTIFIER, tok
103
+ else
104
+ raise Racc::ParseError, ('parse error on value "%s"' % @ss.rest.inspect)
105
+ end
106
+ end
107
+
108
+ yield false, '$'
109
+ end
110
+ private :scan
111
+
112
+ def parse
113
+ yyparse self, :scan
114
+ end
115
+
116
+ def self.parse(obj)
117
+ self.new(obj).parse
118
+ end
119
+
120
+ ..end sdb-parser.y modeval..idc908e49d79
121
+
122
+ ##### racc 1.4.5 generates ###
123
+
124
+ racc_reduce_table = [
125
+ 0, 0, :racc_error,
126
+ 1, 27, :_reduce_none,
127
+ 1, 27, :_reduce_none,
128
+ 1, 27, :_reduce_none,
129
+ 1, 27, :_reduce_none,
130
+ 1, 27, :_reduce_none,
131
+ 1, 27, :_reduce_none,
132
+ 1, 27, :_reduce_none,
133
+ 1, 27, :_reduce_none,
134
+ 1, 27, :_reduce_none,
135
+ 8, 28, :_reduce_10,
136
+ 0, 36, :_reduce_11,
137
+ 1, 36, :_reduce_12,
138
+ 1, 36, :_reduce_none,
139
+ 10, 29, :_reduce_14,
140
+ 3, 38, :_reduce_15,
141
+ 8, 30, :_reduce_16,
142
+ 1, 40, :_reduce_17,
143
+ 3, 40, :_reduce_18,
144
+ 3, 41, :_reduce_19,
145
+ 8, 31, :_reduce_20,
146
+ 0, 42, :_reduce_21,
147
+ 1, 42, :_reduce_none,
148
+ 1, 32, :_reduce_23,
149
+ 3, 33, :_reduce_24,
150
+ 3, 34, :_reduce_25,
151
+ 2, 35, :_reduce_26,
152
+ 1, 37, :_reduce_27,
153
+ 3, 37, :_reduce_28,
154
+ 1, 39, :_reduce_29,
155
+ 3, 39, :_reduce_30 ]
156
+
157
+ racc_reduce_n = 31
158
+
159
+ racc_shift_n = 74
160
+
161
+ racc_action_table = [
162
+ 6, 8, 51, 24, 71, 48, 72, 26, 25, 1,
163
+ 27, 24, 50, 30, 31, 10, 32, 13, 15, 17,
164
+ 33, 3, 5, 34, 35, 36, 34, 37, 38, 39,
165
+ 40, 41, 42, 45, 47, 21, 49, 20, 52, 53,
166
+ 54, 55, 56, 42, 58, 59, 60, 24, 62, 63,
167
+ 64, 65, 34, 66, 67, 68, 70, 19, 73 ]
168
+
169
+ racc_action_check = [
170
+ 0, 0, 43, 8, 69, 40, 69, 9, 8, 0,
171
+ 10, 13, 43, 17, 19, 0, 20, 0, 0, 0,
172
+ 22, 0, 0, 23, 26, 27, 28, 29, 30, 31,
173
+ 33, 34, 36, 37, 39, 5, 42, 3, 45, 46,
174
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 58,
175
+ 59, 60, 61, 62, 63, 64, 65, 1, 72 ]
176
+
177
+ racc_action_pointer = [
178
+ -2, 45, nil, 15, nil, 10, nil, nil, -2, 7,
179
+ 5, nil, nil, 6, nil, nil, nil, -9, nil, 9,
180
+ 11, nil, 16, 7, nil, nil, 24, 7, 10, 23,
181
+ 23, 16, nil, 25, 26, nil, 27, 28, nil, 27,
182
+ -1, nil, 28, -4, nil, 32, 25, 24, 34, 33,
183
+ 38, 37, 38, 31, 42, 40, nil, nil, 41, 42,
184
+ 38, 36, 44, 45, 46, 47, nil, nil, nil, -10,
185
+ nil, nil, 49, nil ]
186
+
187
+ racc_action_default = [
188
+ -31, -31, -6, -31, -7, -31, -9, -8, -11, -31,
189
+ -31, -1, -2, -21, -3, -23, -4, -31, -5, -31,
190
+ -31, -26, -31, -13, -27, -12, -31, -31, -22, -31,
191
+ -31, -31, -25, -31, -31, 74, -31, -31, -24, -31,
192
+ -31, -28, -31, -31, -17, -31, -31, -31, -31, -31,
193
+ -31, -31, -31, -31, -31, -31, -19, -18, -31, -31,
194
+ -31, -15, -31, -31, -31, -31, -10, -16, -20, -31,
195
+ -29, -14, -31, -30 ]
196
+
197
+ racc_goto_table = [
198
+ 23, 44, 7, 14, 16, 28, 18, 2, 4, 12,
199
+ 22, 9, 46, 69, 43, 57, 11, 29, nil, nil,
200
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
201
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
202
+ nil, nil, nil, nil, nil, nil, 61 ]
203
+
204
+ racc_goto_check = [
205
+ 11, 15, 9, 4, 5, 11, 6, 7, 8, 3,
206
+ 10, 1, 12, 13, 14, 15, 2, 16, nil, nil,
207
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
208
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
209
+ nil, nil, nil, nil, nil, nil, 11 ]
210
+
211
+ racc_goto_pointer = [
212
+ nil, 11, 16, 9, 3, 4, 6, 7, 8, 2,
213
+ 2, -8, -27, -52, -22, -35, 4 ]
214
+
215
+ racc_goto_default = [
216
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
217
+ nil, nil, nil, nil, nil, nil, nil ]
218
+
219
+ racc_token_table = {
220
+ false => 0,
221
+ Object.new => 1,
222
+ :use_stmt => 2,
223
+ :GET => 3,
224
+ :FROM => 4,
225
+ :IDENTIFIER => 5,
226
+ :WHERE => 6,
227
+ :ITEMNAME => 7,
228
+ "=" => 8,
229
+ :VALUE => 9,
230
+ "*" => 10,
231
+ :INSERT => 11,
232
+ :INTO => 12,
233
+ "(" => 13,
234
+ ")" => 14,
235
+ :VALUES => 15,
236
+ "," => 16,
237
+ :UPDATE => 17,
238
+ :SET => 18,
239
+ :DELETE => 19,
240
+ :SELECT => 20,
241
+ :CREATE => 21,
242
+ :DOMAIN => 22,
243
+ :DROP => 23,
244
+ :SHOW => 24,
245
+ :DOMAINS => 25 }
246
+
247
+ racc_use_result_var = false
248
+
249
+ racc_nt_base = 26
250
+
251
+ Racc_arg = [
252
+ racc_action_table,
253
+ racc_action_check,
254
+ racc_action_default,
255
+ racc_action_pointer,
256
+ racc_goto_table,
257
+ racc_goto_check,
258
+ racc_goto_default,
259
+ racc_goto_pointer,
260
+ racc_nt_base,
261
+ racc_reduce_table,
262
+ racc_token_table,
263
+ racc_shift_n,
264
+ racc_reduce_n,
265
+ racc_use_result_var ]
266
+
267
+ Racc_token_to_s_table = [
268
+ '$end',
269
+ 'error',
270
+ 'use_stmt',
271
+ 'GET',
272
+ 'FROM',
273
+ 'IDENTIFIER',
274
+ 'WHERE',
275
+ 'ITEMNAME',
276
+ '"="',
277
+ 'VALUE',
278
+ '"*"',
279
+ 'INSERT',
280
+ 'INTO',
281
+ '"("',
282
+ '")"',
283
+ 'VALUES',
284
+ '","',
285
+ 'UPDATE',
286
+ 'SET',
287
+ 'DELETE',
288
+ 'SELECT',
289
+ 'CREATE',
290
+ 'DOMAIN',
291
+ 'DROP',
292
+ 'SHOW',
293
+ 'DOMAINS',
294
+ '$start',
295
+ 'stmt',
296
+ 'get_stmt',
297
+ 'insert_stmt',
298
+ 'update_stmt',
299
+ 'delete_stmt',
300
+ 'select_stmt',
301
+ 'create_stmt',
302
+ 'drop_stmt',
303
+ 'show_stmt',
304
+ 'get_output_list',
305
+ 'identifier_list',
306
+ 'insert_attr_list',
307
+ 'value_list',
308
+ 'set_clause_list',
309
+ 'set_clause',
310
+ 'delete_attr_list']
311
+
312
+ Racc_debug_parser = false
313
+
314
+ ##### racc system variables end #####
315
+
316
+ # reduce 0 omitted
317
+
318
+ # reduce 1 omitted
319
+
320
+ # reduce 2 omitted
321
+
322
+ # reduce 3 omitted
323
+
324
+ # reduce 4 omitted
325
+
326
+ # reduce 5 omitted
327
+
328
+ # reduce 6 omitted
329
+
330
+ # reduce 7 omitted
331
+
332
+ # reduce 8 omitted
333
+
334
+ # reduce 9 omitted
335
+
336
+ module_eval <<'.,.,', 'sdb-parser.y', 17
337
+ def _reduce_10( val, _values)
338
+ struct(:GET, :domain => val[3], :item_name => val[7], :attr_names => val[1])
339
+ end
340
+ .,.,
341
+
342
+ module_eval <<'.,.,', 'sdb-parser.y', 22
343
+ def _reduce_11( val, _values)
344
+ []
345
+ end
346
+ .,.,
347
+
348
+ module_eval <<'.,.,', 'sdb-parser.y', 26
349
+ def _reduce_12( val, _values)
350
+ []
351
+ end
352
+ .,.,
353
+
354
+ # reduce 13 omitted
355
+
356
+ module_eval <<'.,.,', 'sdb-parser.y', 35
357
+ def _reduce_14( val, _values)
358
+ attrs = {}
359
+ val[4].zip(val[8]).each {|k, v| attrs[k] = v }
360
+ item_name = attrs.delete(:item_name)
361
+ struct(:INSERT, :domain => val[2], :item_name => item_name, :attrs => attrs)
362
+ end
363
+ .,.,
364
+
365
+ module_eval <<'.,.,', 'sdb-parser.y', 40
366
+ def _reduce_15( val, _values)
367
+ [:item_name, val[2]].flatten
368
+ end
369
+ .,.,
370
+
371
+ module_eval <<'.,.,', 'sdb-parser.y', 47
372
+ def _reduce_16( val, _values)
373
+ attrs = {}
374
+ val[3].each {|k, v| attrs[k] = v }
375
+ struct(:UPDATE, :domain => val[1], :items => [[val[7], attrs]])
376
+ end
377
+ .,.,
378
+
379
+ module_eval <<'.,.,', 'sdb-parser.y', 52
380
+ def _reduce_17( val, _values)
381
+ [val[0]]
382
+ end
383
+ .,.,
384
+
385
+ module_eval <<'.,.,', 'sdb-parser.y', 56
386
+ def _reduce_18( val, _values)
387
+ val[0] + [val[2]]
388
+ end
389
+ .,.,
390
+
391
+ module_eval <<'.,.,', 'sdb-parser.y', 61
392
+ def _reduce_19( val, _values)
393
+ [val[0], val[2]]
394
+ end
395
+ .,.,
396
+
397
+ module_eval <<'.,.,', 'sdb-parser.y', 66
398
+ def _reduce_20( val, _values)
399
+ struct(:DELETE, :domain => val[3], :items => [[val[7], val[1]]])
400
+ end
401
+ .,.,
402
+
403
+ module_eval <<'.,.,', 'sdb-parser.y', 71
404
+ def _reduce_21( val, _values)
405
+ []
406
+ end
407
+ .,.,
408
+
409
+ # reduce 22 omitted
410
+
411
+ module_eval <<'.,.,', 'sdb-parser.y', 77
412
+ def _reduce_23( val, _values)
413
+ struct(:SELECT, :query => val[0])
414
+ end
415
+ .,.,
416
+
417
+ module_eval <<'.,.,', 'sdb-parser.y', 82
418
+ def _reduce_24( val, _values)
419
+ struct(:CREATE, :domain => val[2])
420
+ end
421
+ .,.,
422
+
423
+ module_eval <<'.,.,', 'sdb-parser.y', 87
424
+ def _reduce_25( val, _values)
425
+ struct(:DROP, :domain => val[2])
426
+ end
427
+ .,.,
428
+
429
+ module_eval <<'.,.,', 'sdb-parser.y', 92
430
+ def _reduce_26( val, _values)
431
+ struct(:SHOW, :operand => :domains)
432
+ end
433
+ .,.,
434
+
435
+ module_eval <<'.,.,', 'sdb-parser.y', 97
436
+ def _reduce_27( val, _values)
437
+ [val[0]]
438
+ end
439
+ .,.,
440
+
441
+ module_eval <<'.,.,', 'sdb-parser.y', 101
442
+ def _reduce_28( val, _values)
443
+ val[0] + [val[2]]
444
+ end
445
+ .,.,
446
+
447
+ module_eval <<'.,.,', 'sdb-parser.y', 106
448
+ def _reduce_29( val, _values)
449
+ [val[0]]
450
+ end
451
+ .,.,
452
+
453
+ module_eval <<'.,.,', 'sdb-parser.y', 110
454
+ def _reduce_30( val, _values)
455
+ [val[0], val[2]].flatten
456
+ end
457
+ .,.,
458
+
459
+ def _reduce_none( val, _values)
460
+ val[0]
461
+ end
462
+
463
+ end # class Parser
464
+
465
+
466
+ end # module SimpleDB
@@ -0,0 +1,222 @@
1
+ class Parser
2
+ options no_result_var
3
+ rule
4
+ stmt : get_stmt
5
+ | insert_stmt
6
+ | update_stmt
7
+ | delete_stmt
8
+ | select_stmt
9
+ | create_stmt
10
+ | drop_stmt
11
+ | show_stmt
12
+ | use_stmt
13
+
14
+ get_stmt : GET get_output_list FROM IDENTIFIER WHERE ITEMNAME '=' VALUE
15
+ {
16
+ struct(:GET, :domain => val[3], :item_name => val[7], :attr_names => val[1])
17
+ }
18
+
19
+ get_output_list :
20
+ {
21
+ []
22
+ }
23
+ | '*'
24
+ {
25
+ []
26
+ }
27
+ | identifier_list
28
+
29
+ insert_stmt : INSERT INTO IDENTIFIER '(' insert_attr_list ')' VALUES '(' value_list ')'
30
+ {
31
+ attrs = {}
32
+ val[4].zip(val[8]).each {|k, v| attrs[k] = v }
33
+ item_name = attrs.delete(:item_name)
34
+ struct(:INSERT, :domain => val[2], :item_name => item_name, :attrs => attrs)
35
+ }
36
+
37
+ insert_attr_list : ITEMNAME ',' identifier_list
38
+ {
39
+ [:item_name, val[2]].flatten
40
+ }
41
+
42
+ update_stmt : UPDATE IDENTIFIER SET set_clause_list WHERE ITEMNAME '=' VALUE
43
+ {
44
+ attrs = {}
45
+ val[3].each {|k, v| attrs[k] = v }
46
+ struct(:UPDATE, :domain => val[1], :items => [[val[7], attrs]])
47
+ }
48
+
49
+ set_clause_list : set_clause
50
+ {
51
+ [val[0]]
52
+ }
53
+ | set_clause_list ',' set_clause
54
+ {
55
+ val[0] + [val[2]]
56
+ }
57
+
58
+ set_clause : IDENTIFIER '=' VALUE
59
+ {
60
+ [val[0], val[2]]
61
+ }
62
+
63
+ delete_stmt : DELETE delete_attr_list FROM IDENTIFIER WHERE ITEMNAME '=' VALUE
64
+ {
65
+ struct(:DELETE, :domain => val[3], :items => [[val[7], val[1]]])
66
+ }
67
+
68
+ delete_attr_list :
69
+ {
70
+ []
71
+ }
72
+ | identifier_list
73
+
74
+ select_stmt : SELECT
75
+ {
76
+ struct(:SELECT, :query => val[0])
77
+ }
78
+
79
+ create_stmt : CREATE DOMAIN IDENTIFIER
80
+ {
81
+ struct(:CREATE, :domain => val[2])
82
+ }
83
+
84
+ drop_stmt : DROP DOMAIN IDENTIFIER
85
+ {
86
+ struct(:DROP, :domain => val[2])
87
+ }
88
+
89
+ show_stmt : SHOW DOMAINS
90
+ {
91
+ struct(:SHOW, :operand => :domains)
92
+ }
93
+
94
+ identifier_list: IDENTIFIER
95
+ {
96
+ [val[0]]
97
+ }
98
+ | identifier_list ',' IDENTIFIER
99
+ {
100
+ val[0] + [val[2]]
101
+ }
102
+
103
+ value_list : VALUE
104
+ {
105
+ [val[0]]
106
+ }
107
+ | value_list ',' VALUE
108
+ {
109
+ [val[0], val[2]].flatten
110
+ }
111
+
112
+ ---- header
113
+
114
+ require 'strscan'
115
+
116
+ module SimpleDB
117
+
118
+ ---- inner
119
+
120
+ KEYWORDS = %w(
121
+ AND
122
+ ASC
123
+ BETWEEN
124
+ BY
125
+ CREATE
126
+ DELETE
127
+ DESC
128
+ DOMAINS
129
+ DOMAIN
130
+ DROP
131
+ EVERY
132
+ FROM
133
+ GET
134
+ INSERT
135
+ INTERSECTION
136
+ INTO
137
+ IN
138
+ IS
139
+ ITEMNAME
140
+ LIKE
141
+ LIMIT
142
+ NOT
143
+ ORDER
144
+ OR
145
+ SET
146
+ SHOW
147
+ UPDATE
148
+ VALUES
149
+ WHERE
150
+ )
151
+
152
+ KEYWORD_REGEXP = Regexp.compile("#{KEYWORDS.join '|'}\\b", Regexp::IGNORECASE)
153
+
154
+ def initialize(obj)
155
+ src = obj.is_a?(IO) ? obj.read : obj.to_s
156
+ @ss = StringScanner.new(src)
157
+ end
158
+
159
+ @@structs = {}
160
+
161
+ def struct(name, attrs = {})
162
+ unless (clazz = @@structs[name])
163
+ clazz = attrs.empty? ? Struct.new(name.to_s) : Struct.new(name.to_s, *attrs.keys)
164
+ @@structs[name] = clazz
165
+ end
166
+
167
+ obj = clazz.new
168
+
169
+ attrs.each do |key, val|
170
+ obj.send("#{key}=", val)
171
+ end
172
+
173
+ return obj
174
+ end
175
+ private :struct
176
+
177
+ def scan
178
+ tok = nil
179
+
180
+ until @ss.eos?
181
+ if (tok = @ss.scan /\s+/)
182
+ # nothing to do
183
+ elsif (tok = @ss.scan /(?:!=|>=|<=|>|<|=)/)
184
+ yield tok, tok
185
+ elsif (tok = @ss.scan KEYWORD_REGEXP)
186
+ yield tok.upcase.to_sym, tok
187
+ elsif (tok = @ss.scan /SELECT\b/i)
188
+ yield :SELECT, tok + @ss.scan(/.*/)
189
+ elsif (tok = @ss.scan /NULL\b/i)
190
+ yield :NULL, nil
191
+ elsif (tok = @ss.scan /`([^`]|``)*`/)
192
+ yield :IDENTIFIER, tok.slice(1...-1).gsub(/``/, '`')
193
+ elsif (tok = @ss.scan /'([^']|'')*'/) #'
194
+ yield :VALUE, tok.slice(1...-1).gsub(/''/, "'")
195
+ elsif (tok = @ss.scan /"([^"]|"")*"/) #"
196
+ yield :VALUE, tok.slice(1...-1).gsub(/""/, '"')
197
+ elsif (tok = @ss.scan /(0|[1-9]\d*)/)
198
+ yield :NATURAL_NUMBER, tok.to_i
199
+ elsif (tok = @ss.scan /[,\(\)\*]/)
200
+ yield tok, tok
201
+ elsif (tok = @ss.scan /[a-z_$][0-9a-z_$]*\b/i)
202
+ yield :IDENTIFIER, tok
203
+ else
204
+ raise Racc::ParseError, ('parse error on value "%s"' % @ss.rest.inspect)
205
+ end
206
+ end
207
+
208
+ yield false, '$'
209
+ end
210
+ private :scan
211
+
212
+ def parse
213
+ yyparse self, :scan
214
+ end
215
+
216
+ def self.parse(obj)
217
+ self.new(obj).parse
218
+ end
219
+
220
+ ---- footer
221
+
222
+ end # module SimpleDB
@@ -0,0 +1,51 @@
1
+ require 'sdbcli/sdb-driver'
2
+ require 'sdbcli/sdb-parser.tab'
3
+
4
+ module SimpleDB
5
+ class Error < StandardError; end
6
+
7
+ class Runner
8
+ def initialize(accessKeyId, secretAccessKey, endpoint = 'sdb.amazonaws.com')
9
+ @driver = Driver.new(accessKeyId, secretAccessKey, endpoint)
10
+ end
11
+
12
+ def endpoint
13
+ @driver.endpoint
14
+ end
15
+
16
+ def endpoint=(v)
17
+ @driver.endpoint = v
18
+ end
19
+
20
+ def execute(query)
21
+ parsed = Parser.parse(query)
22
+ command = parsed.class.name.split('::').last.to_sym
23
+
24
+ case command
25
+ when :GET
26
+ @driver.get(parsed.domain, parsed.item_name, parsed.attr_names)
27
+ when :INSERT
28
+ @driver.insert(parsed.domain, parsed.item_name, parsed.attrs)
29
+ nil
30
+ when :UPDATE
31
+ @driver.update(parsed.domain, parsed.items)
32
+ nil
33
+ when :DELETE
34
+ @driver.delete(parsed.domain, parsed.items)
35
+ nil
36
+ when :SELECT
37
+ @driver.select(parsed.query)
38
+ when :CREATE
39
+ @driver.create_domain(parsed.domain)
40
+ nil
41
+ when :DROP
42
+ @driver.drop_domain(parsed.domain)
43
+ nil
44
+ when :SHOW
45
+ @driver.show_domains
46
+ else
47
+ raise 'must not happen'
48
+ end
49
+ end
50
+ end # Runner
51
+ end # SimpleDB
data/lib/sdbcli.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'sdbcli/sdb-client'
2
+ require 'sdbcli/sdb-driver'
3
+ require 'sdbcli/sdb-runner'
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sdbcli
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - winebarrel
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-01-16 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: nokogiri
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description:
35
+ email: sgwr_dts@yahoo.co.jp
36
+ executables:
37
+ - sdbcli
38
+ extensions: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ files:
43
+ - README
44
+ - bin/sdbcli
45
+ - lib/sdbcli/sdb-client.rb
46
+ - lib/sdbcli/sdb-driver.rb
47
+ - lib/sdbcli/sdb-parser.tab.rb
48
+ - lib/sdbcli/sdb-parser.y
49
+ - lib/sdbcli/sdb-runner.rb
50
+ - lib/sdbcli.rb
51
+ homepage: https://bitbucket.org/winebarrel/sdbcli
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options: []
56
+
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ hash: 3
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ requirements: []
78
+
79
+ rubyforge_project:
80
+ rubygems_version: 1.8.11
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: sdbcli is command line client of Amazon SimpleDB.
84
+ test_files: []
85
+