0

I am using mysql2 in my ruby script. using this to test API responses against the mysql DB

this is a snippet of my script

test_job_by_id_5
 id = $data["jobs"]["id"][i] # example 5
 job = JobServices.job_by_id(id)
 response = @@con.query("select * from jobs where id = #{id}") #select * from jobs where id =5
 rs=response.collect #this fails
 assert_match(job[0]['title'],rs[0]['title'],"The title values are equal for #{$data["jobs"]["id"][i]}")
end

So when i use this with ruby 1.8.7 (2011-06-30 patchlevel 352) [i686-darwin10] it works like a charm

but when i use ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux] it does not work i get this error

NoMethodError: undefined method '[]' for 
#<Enumerator: #<Mysql2::Result:0x00000012d19f18>:collect>

Can some one please help me fix this?

Dave Newton
  • 158,873
  • 26
  • 254
  • 302
Amey
  • 8,470
  • 9
  • 44
  • 63

1 Answers1

1

When you call collect on an Enumerable (which Mysql2::Result is), you get an Enumerator instance back. Enumerators don't implement the array access operator so you can't say enumerator[0] and get anything useful to happen; however, Enumerator does include Enumerable so they do respond to first so you probably want to do this:

rs  = response.collect
row = rs.first
assert_match(job[0]['title'], row['title'], "The title values are equal for #{$data["jobs"]["id"][i]}")

Or just skip the Enumerator entirely and call first on the response:

row = response.first
assert_match(job[0]['title'], row['title'], "The title values are equal for #{$data["jobs"]["id"][i]}")

or even this:

row = @@con.query("select * from jobs where id = #{id}").first
assert_match(job[0]['title'], row['title'], "The title values are equal for #{$data["jobs"]["id"][i]}")

Keep in mind that row.nil? will be true if your query doesn't find anything so you might want to take that into account if you don't want an exception.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • thanks for the response, this will probably do it, but i need to iterate over all rows returned, and i do not know how many rows will be returned? Using `each`, but instead of doing `each` on the DB response I need to do it for each API response. So I am not sure if there is a `second` and `third` – Amey May 02 '12 at 03:33
  • @perlnewbie: I'm not sure what you mean but maybe you can turn it inside-out or fetch all the results into an array and then iterate `job` and that array concurrently. – mu is too short May 02 '12 at 03:48
  • I mean if i do `response[0]['title']` without using collect it does not work. So basically cannot iterate job and response in the same loop if I do `job.each do |i| assert_match(job[i]['title'],response[i]['title']) end` – Amey May 02 '12 at 04:06
  • But you can do `response.each { ... }` or `response.each_with_index { ... }` to iterate both at once. – mu is too short May 02 '12 at 04:10
  • yes, but I need to check for all values of `Job` and not all values of `response`. More like left join as compared to inner join in sql. – Amey May 02 '12 at 16:05
  • i think i also tried adding this `rs=response.collect { |a| a }` and now the collect works. but this seems like a very very bad way to do it. Marking your response as a solution as I see where u were trying to get at. Thanks for ur replies, much appreciated. Also if you can think of a better way other than attaching `{ |a| a }` after `collect' that would be super! – Amey May 02 '12 at 16:08
  • 1
    If you supply the block for `Enumerable#collect`, you get an array out the other side, this can be expensive if the result set is large but it might not be worth worrying about in a test suite. [`each_with_index`](http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-each_with_index) might be a good choice: `response.each_with_index { |r, i| assert_match(job[i]['title'], r[i], ...) }`. – mu is too short May 02 '12 at 17:30