rsql 0.2.11 → 0.3.1

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/bin/rsql CHANGED
@@ -63,11 +63,13 @@ ARGV.map!{|a| a.sub(/^--/,'-')}
63
63
  if i = ARGV.index('-rc')
64
64
  ARGV.delete_at(i)
65
65
  rc_fn = ARGV.delete_at(i)
66
- else
66
+ elsif ENV['HOME']
67
67
  rc_fn = File.join(ENV['HOME'], ".#{bn}rc")
68
68
  end
69
69
 
70
- eval_context.load(rc_fn, :skip_init_registrations) if File.exists?(rc_fn)
70
+ if rc_fn && File.exists?(rc_fn)
71
+ eval_context.load(rc_fn, :skip_init_registrations)
72
+ end
71
73
 
72
74
  def get_password(prompt)
73
75
  STDOUT.print(prompt)
@@ -160,10 +162,14 @@ if i = ARGV.index('-ssh')
160
162
  (opts.ssh_host, opts.ssh_user, opts.ssh_password, opts.ssh_port) =
161
163
  split_login(ARGV.delete_at(i))
162
164
 
163
- default_config = File.join(ENV['HOME'], '.ssh', 'config')
164
- if File.exists?(default_config)
165
- opts.ssh_config = default_config
166
- opts.ssh_cfghash = Net::SSH::Config.load(default_config, opts.ssh_host)
165
+ opts.ssh_cfghash = {}
166
+
167
+ if ENV['HOME']
168
+ default_config = File.join(ENV['HOME'], '.ssh', 'config')
169
+ if File.exists?(default_config)
170
+ opts.ssh_config = default_config
171
+ opts.ssh_cfghash = Net::SSH::Config.load(default_config, opts.ssh_host)
172
+ end
167
173
  end
168
174
 
169
175
  if opts.ssh_user.nil? || opts.ssh_user.empty?
@@ -237,7 +243,7 @@ MySQLResults.database_name = ARGV.shift
237
243
 
238
244
  if !$stdin.tty? && opts.batch_input.nil?
239
245
  # accept commands from stdin
240
- opts.batch_input = $stdin.read.gsub(/\r?\n/,';')
246
+ opts.batch_input = $stdin.read
241
247
  end
242
248
 
243
249
  # make sure we remove any duplicates when we add to the history to
@@ -381,7 +387,8 @@ if opts.ssh_host
381
387
  ipc_state = ''
382
388
  15.times do
383
389
  sleep(1)
384
- ipc_state = IO.read(ipc_fn).strip
390
+ # if the fork fails, it'll call our at_exit which removes the ipc file
391
+ ipc_state = File.exists?(ipc_fn) ? IO.read(ipc_fn).strip : 'fail'
385
392
  break if ipc_state == 'ready' || ipc_state == 'fail'
386
393
  end
387
394
 
@@ -428,9 +435,11 @@ rescue Exception => ex
428
435
  exit 1
429
436
  end
430
437
 
431
- history_fn = File.join(ENV['HOME'], ".#{bn}_history")
432
- if File.exists?(history_fn) && 0 < File.size(history_fn)
433
- YAML.load_file(history_fn).each {|i| Readline::HISTORY.push(i)}
438
+ if ENV['HOME']
439
+ history_fn = File.join(ENV['HOME'], ".#{bn}_history")
440
+ if File.exists?(history_fn) && 0 < File.size(history_fn)
441
+ YAML.load_file(history_fn).each {|i| Readline::HISTORY.push(i)}
442
+ end
434
443
  end
435
444
 
436
445
  Readline.completion_proc = eval_context.method(:complete)
@@ -515,6 +524,7 @@ end
515
524
 
516
525
  child_pids << kill_pid
517
526
  opts.delete_field(:mysql_password)
527
+ # fixme: consider emulating a shell prompt and have this cancel any current cmd line
518
528
  Signal.trap('INT', nil)
519
529
 
520
530
  Signal.trap('CHLD') do
@@ -544,7 +554,7 @@ end
544
554
 
545
555
  sleep(0.3)
546
556
 
547
- if Readline::HISTORY.any?
557
+ if Readline::HISTORY.any? && history_fn
548
558
  if 100 < Readline::HISTORY.size
549
559
  (Readline::HISTORY.size - 100).times do |i|
550
560
  Readline::HISTORY.delete_at(i)
@@ -5,7 +5,25 @@
5
5
  # information.
6
6
  #
7
7
  module RSQL
8
- VERSION = '0.2.11'
8
+ VERSION = [0,3,1]
9
+
10
+ def VERSION.to_s
11
+ self.join('.')
12
+ end
13
+
14
+ # Set up our version to be comparable to version strings.
15
+ #
16
+ VERSION.extend(Comparable)
17
+ def VERSION.eql?(version)
18
+ self.<=>(version) == 0
19
+ end
20
+ def VERSION.<=>(version)
21
+ version = version.split('.').map!{|v|v.to_i}
22
+ r = self[0] <=> version[0]
23
+ r = self[1] <=> version[1] if r == 0
24
+ r = self[2] <=> version[2] if r == 0
25
+ r
26
+ end
9
27
 
10
28
  require 'rsql/mysql_results'
11
29
  require 'rsql/eval_context'
@@ -21,6 +21,16 @@
21
21
 
22
22
  module RSQL
23
23
 
24
+ # FIXME:
25
+ #
26
+ # select Count(*) from BcheckResults where LastResult != 'Succeeded' and LastResultTime > DATE_SUB(UTC_TIMESTAMP, INTERVAL 1 DAY);
27
+ # NoMethodError: undefined method `+' for nil:NilClass
28
+ # /usr/lib/ruby/gems/1.8/gems/rsql-0.2.11/lib/rsql/commands.rb:82:in `initialize'
29
+ # /usr/lib/ruby/gems/1.8/gems/rsql-0.2.11/bin/rsql:535:in `join'
30
+ # /usr/lib/ruby/gems/1.8/gems/rsql-0.2.11/bin/rsql:535
31
+ # /bin/rsql:19:in `load'
32
+ # /bin/rsql:19
33
+
24
34
  require 'stringio'
25
35
 
26
36
  EvalResults = Struct.new(:value, :stdout)
@@ -125,7 +125,7 @@ module RSQL
125
125
  if Exception === ret
126
126
  @loaded_fns_state[fn] = :failed
127
127
  if @verbose
128
- $stderr.puts("#{ex.class}: #{ex.message}", ex.backtrace)
128
+ $stderr.puts("#{ret.class}: #{ret.message}", ex.backtrace)
129
129
  else
130
130
  bt = ret.backtrace.collect{|line| line.start_with?(fn) ? line : nil}.compact
131
131
  $stderr.puts("#{ret.class}: #{ret.message}", bt, '')
@@ -513,15 +513,57 @@ EOF
513
513
  nil
514
514
  end
515
515
 
516
- # Call MySQLResults#grep to remove (or show) only those lines that
517
- # have content matching the patterrn.
516
+ # Remove all rows that do NOT match the expression. Returns true if
517
+ # any matches were found.
518
518
  #
519
- def grep(*args) # :doc:
520
- if @results.grep(*args)
521
- @results
519
+ # Options:
520
+ # :fixed => indicates that the string should be escaped of any
521
+ # special characters
522
+ # :nocolor => will not add color escape codes to indicate the
523
+ # match
524
+ # :inverse => reverses the regular expression match
525
+ #
526
+ def grep(pattern, *gopts) # :doc:
527
+ nocolor = gopts.include?(:nocolor)
528
+
529
+ if inverted = gopts.include?(:inverse)
530
+ # there's no point in coloring matches we are removing
531
+ nocolor = true
532
+ end
533
+
534
+ if gopts.include?(:fixed)
535
+ regexp = Regexp.new(/#{Regexp.escape(pattern.to_str)}/)
536
+ elsif Regexp === pattern
537
+ regexp = pattern
522
538
  else
523
- $stderr.puts 'No matches found'
539
+ regexp = Regexp.new(/#{pattern.to_str}/)
540
+ end
541
+
542
+ rval = inverted
543
+
544
+ @results.delete_if do |row|
545
+ matched = false
546
+ row.each do |val|
547
+ val = val.to_s unless String === val
548
+ if nocolor
549
+ if matched = !val.match(regexp).nil?
550
+ rval = inverted ? false : true
551
+ break
552
+ end
553
+ else
554
+ # in the color case, we want to colorize all hits in
555
+ # all columns, so we can't early terminate our
556
+ # search
557
+ if val.gsub!(regexp){|m| "\e[31;1m#{m}\e[0m"}
558
+ matched = true
559
+ rval = inverted ? false : true
560
+ end
561
+ end
562
+ end
563
+ inverted ? matched : !matched
524
564
  end
565
+
566
+ return rval
525
567
  end
526
568
 
527
569
  # Register bangs to evaluate on all displayers as long as a column
@@ -63,8 +63,8 @@ module RSQL
63
63
  #
64
64
  def conn; @@conn; end
65
65
 
66
- # Set the underlying MySQL connection object to use which
67
- # implicitly resets the name cache.
66
+ # Set the underlying MySQL connection object to use which implicitly
67
+ # resets the name cache.
68
68
  #
69
69
  def conn=(conn)
70
70
  if @@conn = conn
@@ -73,23 +73,21 @@ module RSQL
73
73
  reset_cache
74
74
  end
75
75
 
76
- # Get the field separator to use when writing rows in
77
- # columns.
76
+ # Get the field separator to use when writing rows in columns.
78
77
  #
79
78
  def field_separator; @@field_separator; end
80
79
 
81
- # Set the field separator to use when writing rows in
82
- # columns.
80
+ # Set the field separator to use when writing rows in columns.
83
81
  #
84
82
  def field_separator=(sep); @@field_separator = sep; end
85
83
 
86
- # Get the maximum number of rows to process before
87
- # throwing a MaxRowsException.
84
+ # Get the maximum number of rows to process before throwing a
85
+ # MaxRowsException.
88
86
  #
89
87
  def max_rows; @@max_rows; end
90
88
 
91
- # Set the maximum number of rows to process before
92
- # throwing a MaxRowsException.
89
+ # Set the maximum number of rows to process before throwing a
90
+ # MaxRowsException.
93
91
  #
94
92
  def max_rows=(cnt); @@max_rows = cnt; end
95
93
 
@@ -131,8 +129,8 @@ module RSQL
131
129
  @@name_cache.keys.sort
132
130
  end
133
131
 
134
- # Get the list of tables available for the current
135
- # database or a specific one.
132
+ # Get the list of tables available for the current database or a
133
+ # specific one.
136
134
  #
137
135
  def tables(database=@@database_name)
138
136
  @@name_cache[database] || []
@@ -206,7 +204,7 @@ module RSQL
206
204
  @@conn.select_db(@@database_name) if @@database_name
207
205
  end
208
206
 
209
- @@history.shift if @@max_history <= @@history.size
207
+ @@history.shift if @@max_history <= @@history.size
210
208
  @@history << sql
211
209
 
212
210
  start = Time.now.to_f
@@ -215,80 +213,115 @@ module RSQL
215
213
 
216
214
  affected_rows = @@conn.affected_rows
217
215
  unless results && 0 < results.num_rows
218
- return new(sql, elapsed, affected_rows)
216
+ return new(nil, nil, affected_rows, sql, elapsed)
219
217
  end
220
218
 
221
219
  if max_rows < results.num_rows
222
220
  raise MaxRowsException.new(results.num_rows, max_rows)
223
221
  end
224
222
 
225
- # extract mysql results into our own table so we can predetermine the
226
- # lengths of columns and give users a chance to reformat column data
227
- # before it's displayed (via the bang maps)
223
+ # extract mysql results into our own table so we can
224
+ # predetermine the lengths of columns and give users a chance to
225
+ # reformat column data before it's displayed (via the bang maps)
228
226
 
229
227
  fields = results.fetch_fields
230
- fields.collect! do |field|
231
- def field.longest_length=(len); @longest_length = len; end
232
- def field.longest_length; @longest_length; end
233
- field.longest_length = field.name.length
234
- field
235
- end
228
+ extend_fields!(fields)
236
229
 
237
230
  results_table = []
238
231
  while vals = results.fetch_row
239
232
  row = []
240
233
  fields.each_with_index do |field, i|
241
- if raw
242
- val = vals[i]
243
- else
244
- val = eval_context.bang_eval(field.name, vals[i])
234
+ val = vals[i]
235
+ orig_vlen = val.respond_to?(:length) ? val.length : 0
236
+ if val && field.is_num?
237
+ val = field.decimals == 0 ? val.to_i : val.to_f
238
+ end
239
+ unless raw
240
+ val = eval_context.bang_eval(field.name, val)
245
241
  if val.nil?
246
242
  val = 'NULL'
247
243
  elsif HEX_RANGE.include?(field.type) && val =~ /[^[:print:]\s]/
248
244
  val = eval_context.to_hexstr(val)
249
245
  end
250
246
  end
251
- vlen = val.respond_to?(:length) ? val.length : 0
252
- if field.longest_length < vlen
253
- if String === val
254
- # consider only the longest line length since some
255
- # output contains multiple lines like "show create table"
256
- longest_line = val.split(/\r?\n/).collect{|l|l.length}.max
257
- if field.longest_length < longest_line
258
- field.longest_length = longest_line
259
- end
260
- else
261
- field.longest_length = val.length
262
- end
263
- end
247
+ update_longest!(field, val, orig_vlen)
264
248
  row << val
265
249
  end
266
250
  results_table << row
267
251
  end
268
252
 
269
- return new(sql, elapsed, affected_rows, fields, results_table)
253
+ return new(fields, results_table, affected_rows, sql, elapsed)
270
254
  end
271
255
 
256
+ ########################################
257
+ private
258
+
259
+ def extend_fields!(fields)
260
+ fields.collect! do |field|
261
+ def field.name; to_s; end unless field.respond_to?(:name)
262
+ def field.longest_length=(len); @longest_length = len; end
263
+ def field.longest_length; @longest_length; end
264
+ field.longest_length = field.name.length
265
+ field
266
+ end
267
+ end
268
+
269
+ def update_longest!(field, val, default_vlen=nil)
270
+ vlen = if val.respond_to?(:length)
271
+ val.length
272
+ elsif default_vlen
273
+ default_vlen
274
+ else
275
+ val.to_s.length
276
+ end
277
+
278
+ if field.longest_length < vlen
279
+ if String === val
280
+ # consider only the longest line length since some
281
+ # output contains multiple lines like "show create
282
+ # table"
283
+ longest_line = val.split(/\r?\n/).collect{|l|l.length}.max
284
+ if field.longest_length < longest_line
285
+ field.longest_length = longest_line
286
+ end
287
+ else
288
+ field.longest_length = vlen
289
+ end
290
+ end
291
+ end
292
+
272
293
  end # class << self
273
294
 
274
295
  ########################################
275
296
 
276
- def initialize(sql, elapsed, affected_rows,
277
- fields=nil, table=nil, field_separator=@@field_separator)
278
- @sql = sql;
279
- @elapsed = elapsed;
280
- @affected_rows = affected_rows;
297
+ def initialize(fields, table, affected_rows=nil, sql=nil, elapsed=nil,
298
+ field_separator=@@field_separator)
299
+
281
300
  @fields = fields
282
301
  @table = table
302
+ @affected_rows = affected_rows || table.size
303
+ @sql = sql
304
+ @elapsed = elapsed
283
305
  @field_separator = field_separator
284
306
 
285
- # we set this here so that (a) it occurs _after_ we are
286
- # successful and so we can show an appropriate messge in a
287
- # displayer
288
- if @sql.match(/use\s+(\S+)/i)
307
+ # we set this here so that it occurs _after_ we are successful and
308
+ # so we can show an appropriate messge in a displayer
309
+ if @sql && @sql.match(/use\s+(\S+)/i)
289
310
  @database_changed = true
290
311
  @@database_name = $1
291
312
  end
313
+
314
+ # if we're not given fields from a query we need to find the column
315
+ # widths
316
+ if @fields && @table && @fields.size > 0 &&
317
+ !@fields.first.respond_to?(:longest_length)
318
+ self.class.send(:extend_fields!, @fields)
319
+ @table.each do |row|
320
+ @fields.each_with_index do |field, i|
321
+ self.class.send(:update_longest!, field, row[i])
322
+ end
323
+ end
324
+ end
292
325
  end
293
326
 
294
327
  # Get the query associated with these results.
@@ -321,19 +354,33 @@ module RSQL
321
354
  @table ? @table.size : 0
322
355
  end
323
356
 
324
- # Get a row from the table hashed with the field names.
357
+ # Convenience helper to grab the value in the very first entry for those
358
+ # times when the query only has one expected value returned.
325
359
  #
326
- def [](index)
327
- if !@fields || !@table
328
- return nil
329
- end
330
- if row = @table[index]
331
- hash = {}
332
- @fields.each_with_index {|f,i| hash[f.name] = row[i]}
333
- return hash
334
- else
335
- return nil
360
+ def scalar
361
+ self[0,0]
362
+ end
363
+
364
+ # Get an entire row as a hash or a single value from the table of
365
+ # results. The value of row_j may be an integer index or a string column
366
+ # name.
367
+ #
368
+ def [](row_i, row_j=nil)
369
+ if @table
370
+ if row = @table[row_i]
371
+ if row_j
372
+ return row[row_j] if Integer === row_j
373
+ if row_j = @fields.index{|f| f.name == row_j}
374
+ return row[row_j]
375
+ end
376
+ else
377
+ hash = {}
378
+ @fields.each_with_index{|f,i| hash[f.name] = row[i]}
379
+ return hash
380
+ end
381
+ end
336
382
  end
383
+ return nil
337
384
  end
338
385
 
339
386
  # Iterate through each row of the table hashed with the field names.
@@ -348,59 +395,21 @@ module RSQL
348
395
  end
349
396
  end
350
397
 
351
- # Remove all rows that do NOT match the expression. Returns true if any
352
- # matches were found.
353
- #
354
- # Options:
355
- # :fixed => indicates that the string should be escaped of any special characters
356
- # :nocolor => will not add color escape codes to indicate the match
357
- # :inverse => reverses the regular expression match
398
+ # Conditionally delete rows from the results.
358
399
  #
359
- def grep(pattern, *gopts)
400
+ def delete_if(opts=nil, &block)
360
401
  if @table
361
- nocolor = gopts.include?(:nocolor)
362
-
363
- if inverted = gopts.include?(:inverse)
364
- # there's no point in coloring matches we are removing
365
- nocolor = true
366
- end
367
-
368
- if gopts.include?(:fixed)
369
- regexp = Regexp.new(/#{Regexp.escape(pattern.to_str)}/)
370
- elsif Regexp === pattern
371
- regexp = pattern
372
- else
373
- regexp = Regexp.new(/#{pattern.to_str}/)
374
- end
375
-
376
- rval = inverted
377
-
378
402
  @table.delete_if do |row|
379
- matched = false
380
- row.each do |val|
381
- val = val.to_str unless String === val
382
- if nocolor
383
- if matched = !val.match(regexp).nil?
384
- rval = inverted ? false : true
385
- break
386
- end
387
- else
388
- # in the color case, we want to colorize all hits in
389
- # all columns, so we can't early terminate our
390
- # search
391
- if val.gsub!(regexp){|m| "\e[31;1m#{m}\e[0m"}
392
- matched = true
393
- rval = inverted ? false : true
394
- end
395
- end
403
+ if opts == :row_hash
404
+ hash = {}
405
+ @fields.each_with_index{|f,i| hash[f.name] = row[i]}
406
+ yield(hash)
407
+ else
408
+ yield(row)
396
409
  end
397
- inverted ? matched : !matched
398
410
  end
399
-
400
- return rval
401
- else
402
- return false
403
411
  end
412
+ self
404
413
  end
405
414
 
406
415
  # Show a set of results in a decent fashion.
@@ -458,19 +467,20 @@ module RSQL
458
467
  # Show a summary line of the results.
459
468
  #
460
469
  def display_stats(io=$stdout, hdr='')
470
+ estr = @elapsed ? " (#{'%0.2f'%@elapsed} sec)" : ''
461
471
  if @table
462
472
  if @database_changed
463
473
  io.puts(hdr, "Database changed");
464
474
  hdr = ''
465
475
  end
466
476
  s = 1 == @table.size ? 'row' : 'rows'
467
- io.puts(hdr, "#{@table.size} #{s} in set (#{'%0.2f'%@elapsed} sec)")
477
+ io.puts(hdr, "#{@table.size} #{s} in set#{estr}")
468
478
  else
469
479
  if @database_changed
470
480
  io.puts(hdr, "Database changed");
471
481
  else
472
482
  s = 1 == @affected_rows ? 'row' : 'rows'
473
- io.puts(hdr, "Query OK, #{@affected_rows} #{s} affected (#{'%0.2f'%@elapsed} sec)")
483
+ io.puts(hdr, "Query OK, #{@affected_rows} #{s} affected#{estr}")
474
484
  end
475
485
  end
476
486
  end
@@ -179,4 +179,39 @@ class TestEvalContext < Test::Unit::TestCase
179
179
  File.unlink(tf+'~') if File.exists?(tf+'~')
180
180
  end
181
181
 
182
+ def test_grep
183
+ out = StringIO.new
184
+
185
+ res = [[11,'one$'],[12,'one and two'],[13,'four and none']]
186
+ @ctx.safe_eval('grep "two"', res, out)
187
+ assert(out.string.empty?)
188
+ assert_equal([[12,"one and \e[31;1mtwo\e[0m"]], res)
189
+
190
+ res = [[11,'one'],[12,'one and two'],[13,'four and none']]
191
+ out = StringIO.new
192
+ @ctx.safe_eval('grep /four/, :nocolor', res, out)
193
+ assert(out.string.empty?)
194
+ assert_equal([[13,'four and none']], res)
195
+
196
+ res = [[11,'one'],[12,'one and two'],[13,'four and none']]
197
+ out = StringIO.new
198
+ @ctx.safe_eval('grep "and", :inverse, :fixed', res, out)
199
+ assert(out.string.empty?)
200
+ assert_equal([[11,'one']], res)
201
+ end
202
+
203
+ def test_help
204
+ out = StringIO.new
205
+ @ctx.safe_eval('help', nil, out)
206
+ assert_match(/only rows/, out.string)
207
+ end
208
+
209
+ def test_exception
210
+ orig_err = $stderr
211
+ $stderr = err = StringIO.new
212
+ @ctx.safe_eval('this should fail', nil, nil)
213
+ $stderr = orig_err
214
+ assert_match(/test_eval_context.rb/, err.string)
215
+ end
216
+
182
217
  end # class TestEvalContext
@@ -76,9 +76,14 @@ class TestMySQLResults < Test::Unit::TestCase
76
76
  f1 = mock('f1')
77
77
  f1.expects(:name).returns('c1').times(12)
78
78
  f1.expects(:type).returns(1).times(2)
79
+ f1.stubs(:is_num?).returns(false)
80
+ f1.stubs(:longest_length)
81
+
79
82
  f2 = mock('f2')
80
83
  f2.expects(:name).returns('c2').times(11)
81
84
  f2.expects(:type).returns(1).times(2)
85
+ f2.stubs(:is_num?).returns(false)
86
+ f2.stubs(:longest_length)
82
87
 
83
88
  res = mock('results')
84
89
  res.expects(:num_rows).returns(2).times(2)
@@ -132,68 +137,31 @@ class TestMySQLResults < Test::Unit::TestCase
132
137
  dout.string.gsub(/\s+/,''))
133
138
  end
134
139
 
135
- def test_grep
136
- f1 = mock('f1')
137
- f1.stubs(:name).returns('c1')
138
- f1.stubs(:type).returns(1)
139
- f2 = mock('f2')
140
- f2.stubs(:name).returns('c2')
141
- f2.stubs(:type).returns(1)
142
-
143
- res = mock('results')
144
- res.stubs(:num_rows).returns(2)
145
- res.stubs(:fetch_fields).returns([f1,f2])
146
-
147
- rows = sequence(:rows)
148
- res.expects(:fetch_row).in_sequence(rows).returns(['v1.1','v1.2'])
149
- res.expects(:fetch_row).in_sequence(rows).returns(['v2.1','v2.2'])
150
- res.expects(:fetch_row).in_sequence(rows).returns(nil)
140
+ def test_init
141
+ mres = MySQLResults.new([], [])
142
+ assert_equal(0, mres.num_rows)
151
143
 
152
- conn = mock('Mysql')
153
- conn.expects(:reconnect=)
154
- conn.stubs(:list_dbs).returns([])
155
- conn.stubs(:query).with(instance_of(String)).returns(res)
156
- conn.stubs(:affected_rows).returns(1)
157
- conn.expects(:reconnected?).times(4)
158
- MySQLResults.reset_history
159
- MySQLResults.conn = conn
160
-
161
- mres = MySQLResults.query('ignored1', eval_context=nil, raw=true)
162
- assert_equal(false, mres.grep(/val/))
163
-
164
- rows = sequence(:rows)
165
- res.expects(:fetch_row).in_sequence(rows).returns(['v1.1','v1.2'])
166
- res.expects(:fetch_row).in_sequence(rows).returns(['v2.1','v2.2'])
167
- res.expects(:fetch_row).in_sequence(rows).returns(nil)
168
-
169
- mres = MySQLResults.query('ignored2', eval_context=nil, raw=true)
170
- assert_equal(true, mres.grep('v1', :fixed))
171
- assert_equal("\e[31;1mv1\e[0m.1", mres[0]['c1'])
172
- assert_equal("\e[31;1mv1\e[0m.2", mres[0]['c2'])
173
-
174
- rows = sequence(:rows)
175
- res.expects(:fetch_row).in_sequence(rows).returns(['v1.1','v1.2'])
176
- res.expects(:fetch_row).in_sequence(rows).returns(['v2.1','v2.2'])
177
- res.expects(:fetch_row).in_sequence(rows).returns(nil)
178
-
179
- mres = MySQLResults.query('ignored3', eval_context=nil, raw=true)
180
- assert_equal(false, mres.grep('v', :fixed, :inverse))
181
-
182
- rows = sequence(:rows)
183
- res.expects(:fetch_row).in_sequence(rows).returns(['v1.1','v1.2'])
184
- res.expects(:fetch_row).in_sequence(rows).returns(['v2.1','v2.2'])
185
- res.expects(:fetch_row).in_sequence(rows).returns(nil)
144
+ mres = MySQLResults.new(['col1', 'col2'], [[1,2], [3,4]])
145
+ assert_equal(2, mres.num_rows)
146
+ dout = StringIO.new
147
+ mres.display_by_column(dout)
148
+ assert_equal('col1col2----------1234----------2rowsinset',
149
+ dout.string.gsub(/\s+/,''))
150
+ end
186
151
 
187
- mres = MySQLResults.query('ignored4', eval_context=nil, raw=true)
188
- assert_equal(true, mres.grep('v1.1', :nocolor))
189
- assert_equal("v1.1", mres[0]['c1'])
152
+ def test_row_access
153
+ mres = MySQLResults.new(['col1', 'col2'], [[1,2], [3,4]])
154
+ assert_equal(3, mres[1,0])
155
+ assert_equal(4, mres[1,'col2'])
156
+ assert_equal({'col1'=>3,'col2'=>4}, mres[1])
157
+ end
190
158
 
191
- # fixme: technically should be in it's only test...
192
- cmds = []
193
- 4.times{|i| cmds << "ignored#{i+1}"}
194
- assert_equal(cmds, MySQLResults.history)
195
- assert_equal([cmds.last], MySQLResults.history(1))
196
- assert_equal(cmds, MySQLResults.history(15))
159
+ def test_delete
160
+ mres = MySQLResults.new(['col1', 'col2'], [[1,2], [3,4]])
161
+ mres.delete_if{|r| r[1] == 4}
162
+ assert_equal(nil, mres[1])
163
+ mres.delete_if(:row_hash){|r| r['col1'] == 1}
164
+ assert_equal(nil, mres[0])
197
165
  end
198
166
 
199
167
  end # class TestMySQLResults
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsql
3
3
  version: !ruby/object:Gem::Version
4
- hash: 1
4
+ hash: 17
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 2
9
- - 11
10
- version: 0.2.11
8
+ - 3
9
+ - 1
10
+ version: 0.3.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Brad Robel-Forrest
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-02-24 00:00:00 Z
18
+ date: 2012-04-12 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: net-ssh
@@ -165,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
165
  requirements: []
166
166
 
167
167
  rubyforge_project:
168
- rubygems_version: 1.8.17
168
+ rubygems_version: 1.8.21
169
169
  signing_key:
170
170
  specification_version: 3
171
171
  summary: Ruby-based MySQL command line with recipes.