# ANN: Sequel 2.2.0 Released

**URL:** <https://www.ruby-forum.com/t/ann-sequel-2-2-0-released/142285>\
**Category:** Ruby\
**Created:** [July 6, 2008, 12:59am UTC](https://www.ruby-forum.com/t/ann-sequel-2-2-0-released/142285 "2008-07-06T00:59:05Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![nerdmaster](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/c68b51/32.png) [@nerdmaster](https://www.ruby-forum.com/u/nerdmaster)\
**Post date:** [July 6, 2008, 12:59am UTC](https://www.ruby-forum.com/t/ann-sequel-2-2-0-released/142285/1 "2008-07-06T00:59:05Z")

</div>

Sequel is a lightweight database access toolkit for Ruby.

- Sequel provides thread safety, connection pooling and a concise DSL  
for constructing database queries and table schemas.
- Sequel also includes a lightweight but comprehensive ORM layer for  
mapping records to Ruby objects and handling associated records.
- Sequel makes it easy to deal with multiple records without having  
to break your teeth on SQL.
- Sequel currently has adapters for ADO, DB2, DBI, Informix, JDBC,  
MySQL, ODBC, OpenBase, Oracle, PostgreSQL and SQLite3.

Sequel 2.2.0 has been released and should be available on the gem  
mirrors. 2.2.0 has the following exciting new features:

## The Most Powerful and Flexible Associations of Any Ruby ORM

Sequel can now support any association type supported by  
ActiveRecord, and many association types ActiveRecord doesn’t  
support.

Association callbacks (:before\_add, :after\_add, :before\_remove,  
:after\_remove) have been added, and work for all association  
types. Each of the callback options can be a Symbol specifying an  
instance method that takes one argument (the associated object), or a  
Proc that takes two arguments (the current object and the associated  
object), or an array of Symbols and Procs. Additionally, an  
:after\_load callback is available, which is running after loading the  
associated record(s) from the database.

Association extensions are now supported:

class FindOrCreate  
def find\_or\_create(vals)  
first(vals) || create(vals)  
end  
end  
class Author \< Sequel::Model  
one\_to\_many :authorships, :extend=\>FindOrCreate  
end  
Author.first.authorships\_dataset.find\_or\_create(:name=\>‘Bob’)

Sequel has been able to support most has\_many :through style  
associations since 1.3, via many\_to\_many (since it doesn’t break on  
join tables that are also model tables, unlike ActiveRecord’s  
has\_and\_belongs\_to\_many). Now it can also support has\_many :through  
style associations where it goes through a has\_many association.

Sequel can now support polymorphic associations. Polymorphic  
associations are really a design flaw, so Sequel doesn’t support them  
directly, but the tools that Sequel gives you make them pretty easy  
to implement.

Sequel can also support associations that ActiveRecord does not. For  
example, a belongs\_to association where the column referenced in the  
associated table is not the primary key, an association that depends  
on multiple columns in each table, or even situations where the  
association has a column in the primary table that can be referenced  
by any of multiple columns in a second table that has a has\_one style  
association with the table you want to associate with.

Some of those associations can be supported for a single object using  
custom SQL in ActiveRecord, but none are supported when eager  
loading or allow further filtering.

Not only can all of these cases be supported with Sequel::Model, all  
can be supported with eager loading, and can allow for further  
filtering. See  
[http://sequel.rubyforge.org/files/sequel/doc/advanced\_associations\_rdoc.html](http://sequel.rubyforge.org/files/sequel/doc/advanced_associations_rdoc.html)  
for details and example code for all association types covered above.

There have also been many additional options added for controlling  
eager loading via eager\_graph. Every part of the SQL JOINs can now  
be controlled via one of the options, so you can use JOIN USING,  
NATURAL JOIN, or arbitrary JOIN ON conditions.

Finally, just to show off the power that Sequel gives you when eager  
loading, here is example code that will eagerly load all descendants  
and ancestors in a tree structure, without knowing the depth of the  
tree:

class Node \< Sequel::Model  
set\_schema do  
primary\_key :id  
foreign\_key :parent\_id, :nodes  
end  
create\_table

```
many_to_one :parent
one_to_many :children, :key=>:parent_id

# Only useful when eager loading
many_to_one :ancestors, :eager_loader=>(proc do |key_hash, nodes,

```

associations|  
# Handle cases where the root node has the same parent\_id as  
primary\_key  
# and also when it is NULL  
non\_root\_nodes = nodes.reject do |n|  
if [nil, n.pk].include?(n.parent\_id)  
# Make sure root nodes have their parent association set to  
nil  
n.associations[:parent] = nil  
true  
else  
false  
end  
end  
unless non\_root\_nodes.empty?  
id\_map = {}  
# Create an map of parent\_ids to nodes that have that parent id  
non\_root\_nodes.each{|n| (id\_map[n.parent\_id] ||= []) \<\< n}  
# Doesn’t cause an infinte loop, because when only the root node  
# is left, this is not called.  
Node.filter(Node.primary\_key=\>id\_map.keys).eager(:ancestors).all  
do |node|  
# Populate the parent association for each node  
id\_map[node.pk].each{|n| n.associations[:parent] = node}  
end  
end  
end)  
many\_to\_one :descendants, :eager\_loader=\>(proc do |key\_hash, nodes,  
associations|  
id\_map = {}  
nodes.each do |n|  
# Initialize an empty array of child associations for each  
parent node  
n.associations[:children] = []  
# Populate identity map of nodes  
id\_map[n.pk] = n  
end  
# Doesn’t cause an infinite loop, because the :eager\_loader is not  
called  
# if no records are returned. Exclude id = parent\_id to avoid  
infinite loop  
# if the root note is one of the returned records and it has  
parent\_id = id  
# instead of parent\_id = NULL.  
Node.filter(:parent\_id=\>id\_map.keys).exclude(:id=\>:parent\_id).eager(:descendants).all  
do |node|  
# Get the parent from the identity map  
parent = id\_map[node.parent\_id]  
# Set the child’s parent association to the parent  
node.associations[:parent] = parent  
# Add the child association to the array of children in the  
parent  
parent.associations[:children] \<\< node  
end  
end)  
end

nodes = Node.filter(:id \< 10).eager(:ancestors, :descendants).all

## New Adapter Features

- PostgreSQL bytea fields are now fully supported.

- The PostgreSQL adapter now uses the safer connection-specific  
string escaping if you are using ruby-pg.

- The SQLite adapter supports drop\_column and add\_index.

- You can now use URL parameters in the connection string, enabling  
you to connect to PostgreSQL via a socket using  
postgres://user:password@blah/database?host=/tmp

## Other New Features

- Dataset#graph now takes a block which it passes to join\_table.

- Symbol#identifier has been added, which can be used if another  
library defines the same operator(s) on Symbol that Sequel defines.

- Filter blocks now yield a VirtualRow instance, which can yield  
Identifiers, QualifiedIdentifiers, or Functions. Like  
Symbol#identifier, this is useful if another library defines the  
same operator(s) on Symbol that Sequel defines.

- You can now call Model.to\_hash to get an identity map for all  
rows (before this required Model.dataset.to\_hash).

- A model that can get it’s column information from the schema will  
set it in the dataset, potentially saving many queries.

- Model.validates\_presence\_of now works correctly for boolean  
columns.

## Notable Bug Fixes

- Caching now works with Model subclasses.

- Model validation methods now work with source reloading.

- The PostgreSQL adapter no longer raises an Error if you try to  
insert a record with the primary key already specified.

- Sequel no longer messes with the native MySQL adapter, so you can  
use Sequel and ActiveRecord with MySQL in the same process.

- Dataset#count now works correctly for limited dataset.

- PostgreSQL Database#transaction method yields a connection, similar  
to the other adapters.

- Using a hash argument in #distinct, #order, or #group is treated  
as an expression instead of a column alias.

- Cloned datasets no longer ignore the existing columns unless it is  
necessary.

- The :quote\_identifiers and :single\_threaded Database options now  
work correctly.

## Backwards Incompatible Changes

- ParseTree support, deprecated in 2.1.0, has been removed in 2.2.0.  
You should use the expression filter syntax instead, perferably  
without the block (though it can be used inside a block as well).  
This usually involves the following types of changes:

- Attempts to save an invalid Model instance will raise an error by  
default. To revert to returning a nil value, use:

- Dataset#update no longer takes a block, as it’s use of the block  
depended on ParseTree. With the introduction of the expression  
syntax in 2.0.0, it’s no longer necessary. You should use a hash  
with an expression as the value instead:

- validates\_presence of now considers false as present instead of  
absent. This is so it works with boolean columns.

- Dataset#graph ignores any previously selected columns when it is  
called for the first time.

- Dataset#columns ignores any filtering, ordering, or distinct  
clauses. This shouldn’t cause issues unless you were using  
SQL functions with side effects and expecting them to be called  
when columns was called (unlikely at best).

One significant point of note is that the 2.2.0 release will be the  
last release with both a sequel\_core and sequel gem. Starting  
with 2.3.0 they will be combined into one sequel gem. You will still  
be able to get just the sequel\_core part by requiring ‘sequel\_core’,  
but they will be packaged together.

If you have any questions, please post on the Google Group.

Thanks,  
Jeremy

- {Source code}[[GitHub - jeremyevans/sequel: Sequel: The Database Toolkit for Ruby](http://github.com/jeremyevans/sequel)]
- {Bug tracking}[[Google Code Archive - Long-term storage for Google Code Project Hosting.](http://code.google.com/p/ruby-sequel/issues/list)]
- {Google group}[[http://groups.google.com/group/sequel-talk](http://groups.google.com/group/sequel-talk)]
- {RDoc}[[http://sequel.rubyforge.org](http://sequel.rubyforge.org)]
