sdbcli 0.1.0

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