purepistos.net

M4DBI - Models (and more) for DBI

M4DBI is a Ruby library that provides ORM modelling and more to the Ruby DBI library.

 
 
_
_

Installation

gem install m4dbi
or
wget http://rome.purepistos.net/m4dbi/m4dbi-nightly.gem
gem install m4dbi-nightly.gem
 
 
_
_

Overview

In addition to the following overview, a full suite of examples is also available.

Queries

require 'm4dbi'

dbh = DBI.connect( "DBI:Pg:databasename", "username", "password" )

several_rows = dbh.s "SELECT col1, col2 FROM table WHERE some_date > '2008-03-31'"

one_row = dbh.s1( "SELECT col3, col4 FROM table WHERE id = ?", some_id )
one_row.col3  #=> 'the value of col3'

one_value = dbh.sc( "SELECT col5 FROM table WHERE id = ?", some_id )
one_value #=> 'the value of col5'

dbh.i( "INSERT INTO table ( col1, col2 ) VALUES ( ?, ? )", value1, value2 )
dbh.u( "UPDATE table SET col3 = ? WHERE id = ?", value3, some_id )
dbh.d( "DELETE FROM table WHERE id = ?", some_id )

Models

class Author < DBI::Model( :authors ); end
class Post < DBI::Model( :posts ); end

Author[ 1 ]  #=> author with primary key == 1
Author[ :name => 'author2' ]  #=> author with name 'author2'
Post.where( :author_id => 1 )  #=> posts by author 1
Post.one_where( :author_id => 2 )  #=> one of author2's posts
Author.create(
  :id => 9,
  :name => 'author9'
)
Post.s( "... generic SQL ..." )  #=> returns an array of Posts
Post.s1( "... generic SQL ..." )  #=> returns a Post
Post.each { |post| ... }   # Models are enumerable

a1 = Author[ 1 ]
a1.name  #=> 'author1'
a1.name = 'G. K. Chesterton'  # update a record

p = Post[ 1 ]
p.set(
  :author_id => 2,
  :text => 'Some new text.',
)  # multi-column update

Relationships

DBI::Model.one_to_many( Author, Post, :posts, :author, :author_id )
a = Author[ 1 ]
a.posts  #=> author1's posts
a.posts << { :text => 'A new post.' }  # add to a collection

class Fan < DBI::Model( :fans ); end

DBI::Model.many_to_many(
  Author, Fan, :authors_liked, :fans, :authors_fans, :author_id, :fan_id
)
a1 = Author[ 1 ]; f2 = Fan[ 2 ]

a1.fans  #=> author1's fans
f2.authors_liked  #=> authors liked by fan2
 
 
_
_

Rationale

I've worked in the past with DBI, ActiveRecord, Og, Kansas and Sequel. I also have some experience with ODBC and JDBC.

ActiveRecord is good, but it took up way too much RAM on a server where memory was not an abundant resource. I also ran into various annoying and frustrating problems. ActiveRecord didn't always play nicely outside the realm of Rails, and I was never sure how stable my application would be after upgrading ActiveRecord.

One thing that bothered me about these ORMs was the fact that they encouraged what I thought was overusage of Ruby or Ruby-ized syntax for things that could be just as (or maybe even more?) easily and cleanly done in SQL, namely: schema definition and basic queries. I am reasonably proficient in SQL, so I considered this Rubification somewhat unnecessary, and also thought that sometimes it only obscured things because one would sometimes wonder what the underlying raw SQL was for the DDL statements or queries. Why not state it explicitly?

I also had POLS violated. Now and then I wouldn't have a record set in memory when I thought I did (due to the maximally-delayed fetching design of Sequel); or a record which I operated on in Ruby didn't have its changes synced to the database because I forgot to #save() it.

A general impression I got from these ORMs was that the ORM was being used to mould, contort and manipulate the database. I always thought that this was backwards; rather, the DB is the reality, and the ORM should conform to it, and convey the truth about it. Otherwise, it would be like having a camera which would alter the physical things that it was taking a picture of, instead of the camera merely being a viewport on the reality.

I realized that all I really liked about ORMs are models and the relationships between them. Otherwise, I really just wanted the low-level power and intimacy of SQL, married to the beauty of my favourite language, Ruby, topped off with these pleasant extras, models and relationships. And so M4DBI was born, as an attempt to address all the above issues.

 
 
_
_

Powered by Ramaze.