Chapter 1. Introduction

Table of Contents

1. Why?

1. Why?

There are many different database libraries for Ruby. But there are many problems as well. On the one hand, you might have a very stable library, but has a very C-ish (as in not at all Rubyish) API. On the other hand, you might have a very Rubyish library and it's not very stable. Or you might have a stable library that is Rubyish, but it doesn't support the database you want to use. Or you have a stable, Rubyish library that supports the database you want to use, but it's got a lot overheard and is doing crazy things in the background that you don't need it doing.

That's why this library exists. This is a simple extension the provides a stable library that is Rubish and supports all major databases. The way it accomplishes this is that it is built on top of Qt's QSql library. By doing so, the library has several things going for it:

  • Stability. All the complex, painful database API boilerplate is passed off to Qt. It does the hard work. And it's proven.

  • Unicode. Qt has excellent Unicode support, so using UTF-8 and/or UTF-16 just works.

  • Simplicity. The only code in the extension is essentially simply a Rubyish API that passes off all the work to the QtSql layer below it. This means the codebase is small and therefore less likely to be buggy. The focus then is all on a clean, intiutive API. And it is very easy to adapt and change this API.

That said, here is an example of typical usage:


require 'jw/dbi'

db = JW::DBI::Database.new()

db.open(db: 'foods.db', driver: 'QSQLITE')

query = db.query()

query.exec('select * from foods').each do | row |
  row.each do |key, value|
    puts "#{key}: #{value}"
  end
end

Here are some slight variations:


sql = 'select * from foods'

db.query.exec(sql).each do |row|
  row.each do |key, value|
    puts "#{key}: #{value}"
  end
end

# Get the first row the result set
row = db.query.single(sql)

# Index and name based lookup:
assert(row['name'] == 'JujyFruit')
assert(row[0]      == 'JujyFruit')

# Get the 100th row:
query = db.query
query.exec(sql)
row = query[100]

# Get rows affected for an update
query.exec 'begin'
query.exec 'update foods set id=1'
puts query.rowsAffected()
query.exec 'rollback'

All in all, a database library should be simple and intuitive. There is really not much to it: you execute a query and get the results. If it is a SELECT, oftentimes you iterate over the results, so iteration should be built in. If it's an UPDATE, then you want to know what rows are affected. That's about it, as everything mainly is done within the context of SQL, and therefore query.exec().

So without further adieu, lets dive in and get this over with.