ddbcli 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.
@@ -0,0 +1,598 @@
1
+ class Parser
2
+ options no_result_var
3
+ rule
4
+ stmt : query
5
+ {
6
+ [val[0], nil, nil]
7
+ }
8
+ | query RUBY_SCRIPT
9
+ {
10
+ [val[0], :ruby, val[1]]
11
+ }
12
+ | query SHELL_SCRIPT
13
+ {
14
+ [val[0], :shell, val[1]]
15
+ }
16
+
17
+ query : show_stmt
18
+ | alter_stmt
19
+ | use_stmt
20
+ | create_stmt
21
+ | drop_stmt
22
+ | describe_stmt
23
+ | select_stmt
24
+ | scan_stmt
25
+ | get_stmt
26
+ | update_stmt
27
+ | delete_stmt
28
+ | insert_stmt
29
+ | next_stmt
30
+
31
+ show_stmt : SHOW TABLES limit_clause
32
+ {
33
+ struct(:SHOW_TABLES, :limit => val[2])
34
+ }
35
+ | SHOW REGIONS
36
+ {
37
+ struct(:SHOW_REGIONS)
38
+ }
39
+ | SHOW CREATE TABLE IDENTIFIER
40
+ {
41
+ struct(:SHOW_CREATE_TABLE, :table => val[3])
42
+ }
43
+
44
+ alter_stmt : ALTER TABLE IDENTIFIER capacity_clause
45
+ {
46
+ struct(:ALTER_TABLE, :table => val[2], :capacity => val[3])
47
+ }
48
+
49
+ use_stmt : USE IDENTIFIER
50
+ {
51
+ struct(:USE, :endpoint_or_region => val[1])
52
+ }
53
+
54
+ create_stmt : CREATE TABLE IDENTIFIER '(' create_definition ')' capacity_clause
55
+ {
56
+ struct(:CREATE, val[4].merge(:table => val[2], :capacity => val[6]))
57
+ }
58
+
59
+ create_definition : IDENTIFIER attr_type_list HASH
60
+ {
61
+ {:hash => {:name => val[0], :type => val[1]}, :range => nil, :indices => nil}
62
+ }
63
+ | IDENTIFIER attr_type_list HASH ',' IDENTIFIER attr_type_list RANGE
64
+ {
65
+ {:hash => {:name => val[0], :type => val[1]}, :range => {:name => val[4], :type => val[5]}, :indices => nil}
66
+ }
67
+ | IDENTIFIER attr_type_list HASH ',' IDENTIFIER attr_type_list RANGE ',' index_definition_list
68
+ {
69
+ {:hash => {:name => val[0], :type => val[1]}, :range => {:name => val[4], :type => val[5]}, :indices => val[8]}
70
+ }
71
+
72
+ attr_type_list : STRING
73
+ {
74
+ 'S'
75
+ }
76
+ | NUMBER
77
+ {
78
+ 'N'
79
+ }
80
+ | BINARY
81
+ {
82
+ 'B'
83
+ }
84
+
85
+ capacity_clause : READ EQ NUMBER_VALUE ',' WRITE EQ NUMBER_VALUE
86
+ {
87
+ {:read => val[2], :write => val[6]}
88
+ }
89
+ | WRITE EQ NUMBER_VALUE ',' READ EQ NUMBER_VALUE
90
+ {
91
+ {:read => val[6], :write => val[2]}
92
+ }
93
+
94
+ index_definition_list : index_definition
95
+ {
96
+ [val[0]]
97
+ }
98
+ | index_definition_list ',' index_definition
99
+ {
100
+ val[0] + [val[2]]
101
+ }
102
+
103
+ index_definition : INDEX IDENTIFIER '(' IDENTIFIER attr_type_list ')' index_type_definition
104
+ {
105
+ {:name => val[1], :key => val[3], :type => val[4], :projection => val[6]}
106
+ }
107
+
108
+ index_type_definition : ALL
109
+ {
110
+ {:type => 'ALL'}
111
+ }
112
+ | KEYS_ONLY
113
+ {
114
+ {:type => 'KEYS_ONLY'}
115
+ }
116
+ | INCLUDE '(' index_include_attr_list ')'
117
+ {
118
+ {:type => 'INCLUDE', :attrs => val[2]}
119
+ }
120
+
121
+ index_include_attr_list : IDENTIFIER
122
+ {
123
+ [val[0]]
124
+ }
125
+ | index_include_attr_list ',' IDENTIFIER
126
+ {
127
+ val[0] + [val[2]]
128
+ }
129
+
130
+ drop_stmt : DROP TABLE IDENTIFIER
131
+ {
132
+ struct(:DROP, :table => val[2])
133
+ }
134
+
135
+ describe_stmt : DESCRIBE IDENTIFIER
136
+ {
137
+ struct(:DESCRIBE, :table => val[1])
138
+ }
139
+ | DESC IDENTIFIER
140
+ {
141
+ struct(:DESCRIBE, :table => val[1])
142
+ }
143
+
144
+ select_stmt : SELECT attrs_to_get FROM IDENTIFIER use_index_clause select_where_clause order_clause limit_clause
145
+ {
146
+ struct(:SELECT, :attrs => val[1], :table => val[3], :index => val[4], :conds => val[5], :order_asc => val[6], :limit => val[7], :count => false)
147
+ }
148
+ | SELECT COUNT '(' '*' ')' FROM IDENTIFIER use_index_clause select_where_clause order_clause limit_clause
149
+ {
150
+ struct(:SELECT, :attrs => [], :table => val[6], :index => val[7], :conds => val[8], :order_asc => val[9], :limit => val[10], :count => true)
151
+ }
152
+
153
+ scan_stmt : SELECT ALL attrs_to_get FROM IDENTIFIER scan_where_clause limit_clause
154
+ {
155
+ struct(:SCAN, :attrs => val[2], :table => val[4], :conds => val[5], :limit => val[6], :count => false)
156
+ }
157
+ | SELECT ALL COUNT '(' '*' ')' FROM IDENTIFIER scan_where_clause limit_clause
158
+ {
159
+ struct(:SCAN, :attrs => [], :table => val[7], :conds => val[8], :limit => val[9], :count => true)
160
+ }
161
+
162
+ get_stmt : GET attrs_to_get FROM IDENTIFIER update_where_clause
163
+ {
164
+ struct(:GET, :attrs => val[1], :table => val[3], :conds => val[4])
165
+ }
166
+
167
+ attrs_to_get: '*'
168
+ {
169
+ []
170
+ }
171
+ | attrs_list
172
+ {
173
+ val[0]
174
+ }
175
+
176
+ attrs_list : IDENTIFIER
177
+ {
178
+ [val[0]]
179
+ }
180
+ | attrs_list ',' IDENTIFIER
181
+ {
182
+ val[0] + [val[2]]
183
+ }
184
+
185
+ use_index_clause :
186
+ | USE INDEX '(' IDENTIFIER ')'
187
+ {
188
+ val[3]
189
+ }
190
+
191
+ select_where_clause :
192
+ | WHERE select_expr_list
193
+ {
194
+ val[1]
195
+ }
196
+
197
+ select_expr_list : select_expr
198
+ {
199
+ [val[0]]
200
+ }
201
+ | select_expr_list AND select_expr
202
+ {
203
+ val[0] + [val[2]]
204
+ }
205
+
206
+ select_expr : IDENTIFIER select_operator value
207
+ {
208
+ [val[0], val[1].to_s.upcase.to_sym, [val[2]]]
209
+ }
210
+ | IDENTIFIER BETWEEN value AND value
211
+ {
212
+ [val[0], val[1].to_s.upcase.to_sym, [val[2], val[4]]]
213
+ }
214
+
215
+ select_operator : common_operator
216
+
217
+ common_operator : EQ
218
+ {
219
+ :EQ
220
+ }
221
+ | LE
222
+ {
223
+ :LE
224
+ }
225
+ | LT
226
+ {
227
+ :LT
228
+ }
229
+ | GE
230
+ {
231
+ :GE
232
+ }
233
+ | GT
234
+ {
235
+ :GT
236
+ }
237
+ | BEGINS_WITH
238
+
239
+ scan_where_clause :
240
+ | WHERE scan_expr_list
241
+ {
242
+ val[1]
243
+ }
244
+
245
+ scan_expr_list : scan_expr
246
+ {
247
+ [val[0]]
248
+ }
249
+ | scan_expr_list AND scan_expr
250
+ {
251
+ val[0] + [val[2]]
252
+ }
253
+
254
+ scan_expr : IDENTIFIER scan_operator value
255
+ {
256
+ [val[0], val[1].to_s.upcase.to_sym, [val[2]]]
257
+ }
258
+ | IDENTIFIER IN value_list
259
+ {
260
+ [val[0], val[1].to_s.upcase.to_sym, val[2]]
261
+ }
262
+ | IDENTIFIER BETWEEN value AND value
263
+ {
264
+ [val[0], val[1].to_s.upcase.to_sym, [val[2], val[4]]]
265
+ }
266
+ | IDENTIFIER IS null_operator
267
+ {
268
+ [val[0], val[2].to_s.upcase.to_sym, []]
269
+ }
270
+
271
+ scan_operator : common_operator | contains_operator
272
+ | NE
273
+ {
274
+ :NE
275
+ }
276
+
277
+ contains_operator : CONTAINS
278
+ | NOT CONTAINS
279
+ {
280
+ :NOT_CONTAINS
281
+ }
282
+ null_operator : NULL
283
+ {
284
+ :NULL
285
+ }
286
+ | NOT NULL
287
+ {
288
+ :NOT_NULL
289
+ }
290
+
291
+ order_clause :
292
+ | ORDER ASC
293
+ {
294
+ true
295
+ }
296
+ | ORDER DESC
297
+ {
298
+ false
299
+ }
300
+
301
+ limit_clause :
302
+ | LIMIT NUMBER_VALUE
303
+ {
304
+ val[1]
305
+ }
306
+
307
+ update_stmt : UPDATE IDENTIFIER set_or_add attr_to_update_list update_where_clause
308
+ {
309
+ struct(:UPDATE, :table => val[1], :action => val[2], :attrs => val[3], :conds => val[4])
310
+ }
311
+ | UPDATE ALL IDENTIFIER set_or_add attr_to_update_list scan_where_clause limit_clause
312
+ {
313
+ struct(:UPDATE_ALL, :table => val[2], :action => val[3], :attrs => val[4], :conds => val[5], :limit => val[6])
314
+ }
315
+
316
+ set_or_add : SET
317
+ {
318
+ :PUT
319
+ }
320
+ | ADD
321
+ {
322
+ :ADD
323
+ }
324
+
325
+ attr_to_update_list : attr_to_update
326
+ {
327
+ [val[0]]
328
+ }
329
+ | attr_to_update_list ',' attr_to_update
330
+ {
331
+ val[0] + [val[2]]
332
+ }
333
+
334
+ attr_to_update : IDENTIFIER EQ value_or_null
335
+ {
336
+ [val[0], val[2]]
337
+ }
338
+
339
+ update_where_clause : WHERE update_expr_list
340
+ {
341
+ val[1]
342
+ }
343
+
344
+ update_expr_list : update_expr
345
+ {
346
+ [val[0]]
347
+ }
348
+ | update_expr_list AND update_expr
349
+ {
350
+ val[0] + [val[2]]
351
+ }
352
+
353
+ update_expr : IDENTIFIER EQ value
354
+ {
355
+ [val[0], val[2]]
356
+ }
357
+
358
+ delete_stmt : DELETE FROM IDENTIFIER update_where_clause
359
+ {
360
+ struct(:DELETE, :table => val[2], :conds => val[3])
361
+ }
362
+ | DELETE ALL FROM IDENTIFIER scan_where_clause limit_clause
363
+ {
364
+ struct(:DELETE_ALL, :table => val[3], :conds => val[4], :limit => val[5])
365
+ }
366
+
367
+ insert_stmt : INSERT INTO IDENTIFIER '(' attr_to_insert_list ')' VALUES insert_value_clause
368
+ {
369
+ struct(:INSERT, :table => val[2], :attrs => val[4], :values => val[7])
370
+ }
371
+
372
+ attr_to_insert_list : IDENTIFIER
373
+ {
374
+ [val[0]]
375
+ }
376
+ | attr_to_insert_list ',' IDENTIFIER
377
+ {
378
+ val[0] + [val[2]]
379
+ }
380
+
381
+ insert_value_clause : '(' insert_value_list ')'
382
+ {
383
+ [val[1]]
384
+ }
385
+ | insert_value_clause ',' '(' insert_value_list ')'
386
+ {
387
+ val[0] + [val[3]]
388
+ }
389
+
390
+ insert_value_list : value
391
+ {
392
+ [val[0]]
393
+ }
394
+ | insert_value_list ',' value
395
+ {
396
+ val[0] + [val[2]]
397
+ }
398
+
399
+ next_stmt : NEXT
400
+ {
401
+ struct(:NEXT)
402
+ }
403
+
404
+ value_or_null : value | NULL
405
+
406
+ value : single_value
407
+ | value_list
408
+
409
+ single_value : NUMBER_VALUE
410
+ | STRING_VALUE
411
+ | BINARY_VALUE
412
+
413
+ value_list : '(' number_list ')'
414
+ {
415
+ val[1]
416
+ }
417
+ | '(' string_list ')'
418
+ {
419
+ val[1]
420
+ }
421
+ | '(' binary_list ')'
422
+ {
423
+ val[1]
424
+ }
425
+
426
+ number_list : NUMBER_VALUE
427
+ {
428
+ [val[0]]
429
+ }
430
+ | number_list ',' NUMBER_VALUE
431
+ {
432
+ val[0] + [val[2]]
433
+ }
434
+
435
+ string_list : STRING_VALUE
436
+ {
437
+ [val[0]]
438
+ }
439
+ | string_list ',' STRING_VALUE
440
+ {
441
+ val[0] + [val[2]]
442
+ }
443
+
444
+ binary_list : BINARY_VALUE
445
+ {
446
+ [val[0]]
447
+ }
448
+ | binary_list ',' BINARY_VALUE
449
+ {
450
+ val[0] + [val[2]]
451
+ }
452
+
453
+ ---- header
454
+
455
+ require 'strscan'
456
+ require 'ddbcli/ddb-binary'
457
+
458
+ module DynamoDB
459
+
460
+ ---- inner
461
+
462
+ KEYWORDS = %w(
463
+ ADD
464
+ ALL
465
+ ALTER
466
+ AND
467
+ ASC
468
+ BEGINS_WITH
469
+ BETWEEN
470
+ BINARY
471
+ CREATE
472
+ CONTAINS
473
+ COUNT
474
+ DELETE
475
+ DESCRIBE
476
+ DESC
477
+ DROP
478
+ FROM
479
+ GET
480
+ HASH
481
+ INCLUDE
482
+ INDEX
483
+ INSERT
484
+ INTO
485
+ IN
486
+ IS
487
+ KEYS_ONLY
488
+ LIMIT
489
+ NEXT
490
+ NOT
491
+ NUMBER
492
+ ORDER
493
+ RANGE
494
+ READ
495
+ REGIONS
496
+ SELECT
497
+ SET
498
+ SHOW
499
+ STRING
500
+ TABLES
501
+ TABLE
502
+ UPDATE
503
+ VALUES
504
+ WHERE
505
+ WRITE
506
+ USE
507
+ )
508
+
509
+ KEYWORD_REGEXP = Regexp.compile("(?:#{KEYWORDS.join '|'})", Regexp::IGNORECASE)
510
+
511
+ def initialize(obj)
512
+ src = obj.is_a?(IO) ? obj.read : obj.to_s
513
+ @ss = StringScanner.new(src)
514
+ end
515
+
516
+ @@structs = {}
517
+
518
+ def struct(name, attrs = {})
519
+ unless (clazz = @@structs[name])
520
+ clazz = attrs.empty? ? Struct.new(name.to_s) : Struct.new(name.to_s, *attrs.keys)
521
+ @@structs[name] = clazz
522
+ end
523
+
524
+ obj = clazz.new
525
+
526
+ attrs.each do |key, val|
527
+ obj.send("#{key}=", val)
528
+ end
529
+
530
+ return obj
531
+ end
532
+ private :struct
533
+
534
+ def scan
535
+ tok = nil
536
+
537
+ until @ss.eos?
538
+ if (tok = @ss.scan /\s+/)
539
+ # nothing to do
540
+ elsif (tok = @ss.scan /(?:<>|!=|>=|<=|>|<|=)/)
541
+ sym = {
542
+ '<>' => :NE,
543
+ '!=' => :NE,
544
+ '>=' => :GE,
545
+ '<=' => :LE,
546
+ '>' => :GT,
547
+ '<' => :LT,
548
+ '=' => :EQ,
549
+ }.fetch(tok)
550
+ yield [sym, tok]
551
+ elsif (tok = @ss.scan KEYWORD_REGEXP)
552
+ yield [tok.upcase.to_sym, tok]
553
+ elsif (tok = @ss.scan /NULL/i)
554
+ yield [:NULL, nil]
555
+ elsif (tok = @ss.scan /`(?:[^`]|``)*`/)
556
+ yield [:IDENTIFIER, tok.slice(1...-1).gsub(/``/, '`')]
557
+ elsif (tok = @ss.scan /x'(?:[^']|'')*'/) #'
558
+ hex = tok.slice(2...-1).gsub(/''/, "'")
559
+ bin = DynamoDB::Binary.new([hex].pack('H*'))
560
+ yield [:BINARY_VALUE, bin]
561
+ elsif (tok = @ss.scan /x"(?:[^"]|"")*"/) #"
562
+ hex = tok.slice(2...-1).gsub(/""/, '"')
563
+ bin = DynamoDB::Binary.new([hex].pack('H*'))
564
+ yield [:BINARY_VALUE, bin]
565
+ elsif (tok = @ss.scan /'(?:[^']|'')*'/) #'
566
+ yield [:STRING_VALUE, tok.slice(1...-1).gsub(/''/, "'")]
567
+ elsif (tok = @ss.scan /"(?:[^"]|"")*"/) #"
568
+ yield [:STRING_VALUE, tok.slice(1...-1).gsub(/""/, '"')]
569
+ elsif (tok = @ss.scan /\d+(?:\.\d+)?/)
570
+ yield [:NUMBER_VALUE, (tok =~ /\./ ? tok.to_f : tok.to_i)]
571
+ elsif (tok = @ss.scan /[,\(\)\*]/)
572
+ yield [tok, tok]
573
+ elsif (tok = @ss.scan /\|(?:.*)/)
574
+ yield [:RUBY_SCRIPT, tok.slice(1..-1)]
575
+ elsif (tok = @ss.scan /\!(?:.*)/)
576
+ yield [:SHELL_SCRIPT, tok.slice(1..-1)]
577
+ elsif (tok = @ss.scan /[-.0-9a-z_]*/i)
578
+ yield [:IDENTIFIER, tok]
579
+ else
580
+ raise Racc::ParseError, ('parse error on value "%s"' % @ss.rest.inspect)
581
+ end
582
+ end
583
+
584
+ yield [false, 'EOF']
585
+ end
586
+ private :scan
587
+
588
+ def parse
589
+ yyparse self, :scan
590
+ end
591
+
592
+ def self.parse(obj)
593
+ self.new(obj).parse
594
+ end
595
+
596
+ ---- footer
597
+
598
+ end # DynamoDB