Technical Documentation: jeremyevans/sequel
โน๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference
Doc Release Notes 1.0 (`doc/release_notes/1.0.txt`)
=== New code organization
Sequel is now divided into two parts: sequel_core and sequel_model.
These two parts are distributed as two separate gems. The sequel gem
bundles sequel_core and sequel_model together. If you don't use
Sequel::Model in your code, you can just install and use sequel_core.
=== New model hooks implementation
The hooks implementation have been rewritten from scratch, is much
more robust and offers a few new features:
More ways to define hooks: hooks can now be defined by supplying a
block or a method name, or by overriding the hook instance method.Inheritable hooks: Hooks can now be inherited, which means that you
can define general hooks in a model superclass, and use them in
subclasses. You can also define global hooks on Sequel::Model that
will be invoked for all model classes.Hook chains can be broken by returning false from within the hook.
New after_initialize hook, invoked after instance initialization.
The hook invocation order can no longer be changed. Hooks are
invoked in order of definition, from the top of the class hierarchy
(that is, from Sequel::Model) down to the specific class.
=== Miscellanea
Removed deprecated adapter stubs, and all other deprecations in both
sequel_core and sequel_model.Fixed String#to_time to raise error correctly for invalid time
stamps.Fixed error behavior when parse_tree or ruby2ruby are not available.
Doc Release Notes 1.1 (`doc/release_notes/1.1.txt`)
=== DRY Sequel models
With the new Sequel release you no longer need to explicitly specify
the table
name for each model class, assuming your model name is the singular of
the
table name (just like in ActiveRecord or DataMapper):
class UglyBug < Sequel::Model
end
UglyBug.table_name #=> :ugly_bugs
=== New model validations and support for virtual attributes
Sequel model now include validation functionality which largly follows
the
validations offered in ActiveRecord. Validations can be checked
anytime by
calling Model#valid?, with validation errors accessible through
Model#errors:
class Item < Sequel::Model
validates_presence_of :name
end
my_item = Item.new
my_item.valid? #=> false
my_item.errors.full_messages #=> ["name is not present"]
The Model#save method has been changed to check for validity before
saving. If
the model instance is not valid, the #save method returns false
without saving
the instance. You can also bypass the validity test by calling
Model#save!
instead.
Model classes also now support virtual attributes, letting you assign
values to
any attribute (virtual or persistent) at initialization time:
class User < Sequel::Model
attr_accessor :password
end
u = User.new(:password => 'blah', ...)
u.password #=> 'blah'
Also, virtual attributes can be validated just like persistent
attributes.
=== Other changes (long list!)
Added Model#reload as alias to Model#refresh.
Changed Model.create to accept a block (#126).
Fixed Model#initialize to accept nil values (#115).
Added Model#update_with_params method with support for virtual
attributes and auto-filtering of unrelated parameters, and changed
Model.create_with_params to support virtual attributes (#128).Fixed Model.dataset to correctly set the dataset if using implicit
naming or inheriting the superclass dataset (thanks celldee).Finalized support for virtual attributes.
Fixed Model#set to work with string keys (#143).
Fixed Model.create to correctly initialize instances marked as new
(#135).Fixed Model#initialize to convert string keys into symbol keys. This
also fixes problem with validating objects initialized with string
keys (#136).Added Dataset#table_exists? convenience method.
Changed Dataset#group_and_count to accept multiple columns (#134).
Added Dataset#select_all method.
Added Dataset#select_more, Dataset#order_more methods (#129).
Fixed Dataset#count to work correctly for grouped datasets (#144).
Fixed joining datasets using aliased tables (#140).
Added support for UNSIGNED constraint, used in MySQL? (#127).
Implemented constraint definitions inside Database#create_table.
Enhanced Database.connect to accept options with string keys, so it
can now accept options loaded from YAML files. Database.connect also
automatically converts :username option into :user for compatibility
with existing YAML configuration files for AR and DataMapper.Changed ODBC::Database to support connection using driver and
database name, also added support for untitled columns in
ODBC::Dataset (thanks Leonid Borisenko).Changed MySQL adapter to support specifying socket option.
Fixed MySQL adapter to correctly format foreign key definitions
(#123).Changed MySQL::Dataset to allow HAVING clause on ungrouped datasets,
and put HAVING clause before ORDER BY clause (#133).Changed mysql adapter to default to localhost if :host option is not
specified (#114).Added String#to_date. Updated mysql adapter to use String#to_date
for mysql date types (thanks drfreeze).Fixed postgres adapter to define PGconn#async_exec as alias to #exec
if not defined (for pure-ruby postgres driver).Changed postgres adapter to quote column references using double
quotes.Applied patch for oracle adapter: fix behavior of limit and offset,
transactions, #table_exists?, #tables and additional specs (thanks
Liming Lian #122).Added support additional field types in postgresql adapter (#146).
Added support for date field types in postgresql adapter (#145).
Added support for limiting and paginating datasets with fixed SQL,
e.g. using Database#fetch.Added new Dataset#from_self method that returns a dataset selecting
from the original dataset.Allow for additional filters on a grouped dataset (#119 and #120)
Refactored Sequelizer to use Proc#to_sexp (method provided by r2r).
Fixed bin/sequel to require sequel_model if available.
Doc Release Notes 1.3 (`doc/release_notes/1.3.txt`)
=== Better model associations
The latest release of sequel_model includes a new associations
functionality written by Jeremy Evans which replaces the old relations
code in previous versions. Please note that this version is not
completely backward-compatible and you should therefore upgrade with
caution.
The new implementation supports three kinds of relations: one_to_many,
many_to_one and many_to_many, which correspond to has_many, belongs_to
and has_and_belongs_to_many relations in ActiveRecord. In fact, the
new implementation includes aliases for ActiveRecord association macros
and is basically compatible with ActiveRecord conventions. It also
supports DRY implicit class name references. Here's a simple example:
class Author < Sequel::Model
has_many :books # equivalent to one_to_many
end
class Book < Sequel::Model
belongs_to :author # equivalent to many_to_one
has_and_belongs_to_many :categories # equivalent to many_to_many
end
class Category < Sequel::Model
has_and_belongs_to_many :books
end
These macros will create the following methods:
- Author#books, Author#add_book, Author#remove_book
- Book#author, Book#categories, Book#add_category,
Book#remove_category - Category#books, Category#add_book, Category#remove_book
Unlike ActiveRecord, one_to_many and many_to_many association methods
return a dataset:
a = Author[1234]
a.books.sql #=> 'SELECT * FROM books WHERE (author_id = 1234)'
You can also tell Sequel to cache the association result set and
return it as an array:
class Author < Sequel::Model
has_many :books, :cache => true
end
Author[1234].books.class #=> Array
You can of course bypass the defaults and specify class names and key
names:
class Node < Sequel::Model
belongs_to :parent, :class => Node
belongs_to :session, :key => :producer_id
end
Another useful option is :order, which sets the order for the
association dataset:
class Author < Sequel::Model
has_many :books, :order => :title
end
Author[1234].books.sql #=> 'SELECT * FROM books WHERE (author_id =
1234) ORDER BY title'
More information about associations can be found in the Sequel
documentation.
=== Other changes
Added configuration file for running specs (#186).
Changed Database#drop_index to accept fixed arity (#173).
Changed column definition sql to put UNSIGNED constraint before
unique in order to satisfy MySQL (#171).Enhanced MySQL adapter to support load data local infile_, added
compress option for mysql connection by default (#172).Fixed bug when inserting hashes in array tuples mode.
Changed SQLite adapter to catch RuntimeError raised when executing a
statement and raise Error::InvalidStatement with the offending SQL and
error message (#188).Fixed Dataset#reverse to not raise for unordered dataset (#189).
Added Dataset#unordered method and changed #order to remove order if
nil is specified (#190).Fixed reversing order of ASC expression (#164).
Added support for :null => true option when defining table columns
(#192).Fixed Symbol#method_missing to accept variable arity (#185).
Doc Release Notes 1.4.0 (`doc/release_notes/1.4.0.txt`)
Eager loading for all types of associations:
Artist.eager(:albums).all
Album.eager(:artist, :genre, :tracks).all
Album.eager(:artist).eager(:genre).eager(:tracks).all
Album.filter(:year=>2008).eager(:artist).all
Eager loading supports cascading to an unlimited depth, and doesn't have
any aliasing issues:
Artist.eager(:albums=>:tracks).all
Artist.eager(:albums=>{:tracks=>:genre}).all
Unfortunately, eager loading comes at the expense of a small amount of
backward compatibility. If you were using uncached associations (the
default in sequel_model 0.5), they no longer work the same way. Now,
all associations act as if :cache=>true (which is now set for all
associations, so if you wrote a tool that worked with both cached and
uncached associations, it should still work).
One to many associations now populate the corresponding many to one
instance variable (even when eagerly loaded):
Assuming: Album.one_to_many :tracks
album = Album.first
This following code is only one query,
not a query for the album and one for each track
album.tracks.each{|t| puts t.album.name}
ActiveRecord style has_many :through associations are now supported via
many_to_many. many_to_many will no longer select the entire result set,
just the columns of the associated table (and not the join table), so it
works for both has_and_belongs_to_many (simple join table) and has_many
:through (join table model) scenarios. If you want to include all or
part of the join table attributes, see the :select option for
many_to_many associations.
We reduced the number of gems from three (sequel, sequel_core,
sequel_model) to two (sequel, sequel_core). Basically, sequel_model is
now just sequel, and the old sequel gem metapackage is no longer. There
isn't a reason to have a gem metapackage for two gems when one
(sequel_model) depends on the other (sequel_core). This required a
version bump for the model part of sequel from 0.5.0.2 to 1.4.0 (since
the previous sequel gem version was 1.3).
Sequel 1.4.0 has fixes for 11 trackers issues, including fixes to the
MySQL and PostgreSQL adapters.
We have switched the source control repository for Sequel from Google
Code (which uses subversion) to github (which uses git). If you would
like to contribute to Sequel, please fork the github repository, make
your changes, and send a pull request. As before, posting patches on
the Google Code issue tracker is fine as well.
Doc Release Notes 1.5.0 (`doc/release_notes/1.5.0.txt`)
You can now graph a dataset and have the result split into component
tables:
DB[:artists].graph(:albums, :artist_id=>:id).first
=> {:artists=>{:id=>artists.id, :name=>artists.name}, \
:albums=>{:id=>albums.id, :name=>albums.name,
:artist_id=>albums.artist_id}}
This aliases columns if necessary so they don't stomp on each other,
which
is what usually happens if you just join the tables:
DB[:artists].left_outer_join(:albums, :artist_id=>:id).first
=> {:id=>(albums.id||artists.id),
:name=>(albums.name||artist.names),
:artist_id=>albums.artist_id}
Models can use graph as well, in which case the values will be model
objects:
Artist.graph(Album, :artist_id=>:id)
=> {:artists=>#, :albums=>#}
Models can now eager load via .eager_graph, which will load all the
results
and all associations in a single query. This is necessary if you want
to
filter on columns in associated tables. It works exactly the same way
as
.eager, and supports cascading of associations as well:
Artist.one_to_many :albums
Album.one_to_many :tracks
Track.many_to_one :genre
Artist.eager_graph(:albums=>{:tracks=>:genre}).filter(
:tracks_name=>"Firewire").all
This will give you all artists have have an album with a track named
"Firewire", and calling .albums on one of those artists will only return
albums that have a track named "Firewire", and calling .tracks on one of
those albums will return only the track(s) named "Firewire".
You can use set_graph_aliases to select specific columns:
DB[:artists].graph(:albums, :artist_id=>:id).set_graph_aliases(
:artist_name=>[:artists, :name], :album_name=>[:albums,
:name]).first
=> {:artists=>{:name=>artists.name}, :albums=>{:name=>albums.name}}
You can use eager_graph with set_graph_aliases to have eager loading
with
control over the SELECT clause.
All associations now update their reciprocal associations whenever the
association methods are used, so you don't need to refresh the
association or model to have the reciprocal association updated:
Album.many_to_one :band
Band.one_to_many :albums
Note that all of these associations are cached,
so after the first access there are no additional
database queries to fetch associated records.
many_to_one setter adds to reciprocal association
band1.albums # => []
album1.band = band1
band1.albums # => [album1]
band2.albums # => []
album1.band = band2
band1.albums # => []
band2.albums # => [album1]
album1.band = band2
band2.albums # => [album1]
album1.band = nil
band2.albums # => []
one_to_many add_* method sets reciprocal association
one_to_many remove_* method removes reciprocal association
album1.band # => nil
band1.add_album(album1)
album1.band # => band1
band2.add_album(album1)
album1.band # => band2
band2.remove_album(album1)
album1.band # => nil
Post.many_to_many :tags
Tag.many_to_many :posts
many_to_many add_* method adds to reciprocal association
many_to_many remove_* method removes from reciprocal association
post1.tags # => []
tag1.posts # => []
tag1.add_post(post1)
post1.tags # => [tag1]
tag1.posts # => [post1]
tag1.remove_post(post1)
post1.tags # => []
tag1.posts # => []
post1.add_tag(tag1)
post1.tags # => [tag1]
tag1.posts # => [post1]
post1.remove_tag(tag1)
post1.tags # => []
tag1.posts # => []
The MySQL and PostgreSQL adapters now support index types:
index :some_column, :type => :hash # or :spatial, :full_text, :rtree,
etc.
Starting in Sequel 1.5.0, some methods are deprecated. These methods
will be
removed in Sequel 2.0.0. The deprecation framework is fairly flexible.
You
can choose where the messages get sent:
Sequel::Deprecation.deprecation_message_stream = STDERR # the default
Sequel::Deprecation.deprecation_message_stream =
File.new('deprecation.txt', 'wb') # A file
Sequel::Deprecation.deprecation_message_stream = nil # ignore the
messages
You can even have all deprecation messages accompanied by a traceback,
so you
can see exactly where in your code you are using a deprecated method:
Sequel::Deprecation.print_tracebacks = true
All deprecation methods come with an message telling you what
alternative code
will work.
In addition to deprecating some methods, we removed the ability to have
arrays returned instead of hashes. The array code still had debugging
messages
left it in, and we are not aware of anyone using it. Hashes have been
returned
by default since Sequel 0.3.
We have also removed the Numeric date/time extensions (e.g. 3.days.ago).
The
existing extensions were incomplete, better ones are provided elsewhere,
and the extensions were not really related to Sequel's purpose.
Sequel no longer depends on ParseTree, RubyInline, or ruby2ruby. They
are
still required to use the block filters. Sequel's only gem dependency
is on
the tiny metaid.
Sequel 1.5.0 has fixes for 12 tracker issues, including fixes to the
Informix,
MySQL, ODBC, ADO, JDBC, Postgres, and SQLite adapters.
Doc Release Notes 2.0.0 (`doc/release_notes/2.0.0.txt`)
Blockless Filter Expressions
Before 2.0.0, in order to specify complex SQL expressions, you
either had to resort to writing the SQL yourself in a string or
using an expression inside a block that was parsed by ParseTree.
Because ParseTree was required, only ruby 1.8.* was supported, and
supporting other ruby versions (ruby 1.9, JRuby, Rubinius) would
never be possible.
With 2.0.0, you no longer need to use a block to write complex SQL
expressions. The basics of the blockless filters are the usual
arithmetic, inequality, and binary operators:
- = addition
- = subtraction
- = multiplication
/ = division
= greater than
< = less than
= = greater than or equal to
<= = less than or equal to
~ = negation
& = AND
| = OR
You can use these operators on Symbols, LiteralStrings, and other
Sequel::SQL::Expressions. Note that there is no equal operator or
not equal operator, to specify those, you use a Hash.
Here are some examples:
Ruby code => SQL WHERE clause
:active => active
~:active => NOT active
~~:active => active
:is_true[] => is_true()
~:is_true[] => NOT is_true()
:x > 100 => (x > 100)
:x < 100.01 => (x < 100.01)
:x <= 0 => (x <= 0)
:x >= 1 => (x >= 1)
~(:x > 100) => (x <= 100)
{:x => 100} => (x = 100)
{:x => 'a'} => (x = 'a')
{:x => nil} => (x IS NULL)
~{:x => 100} => (x != 100)
~{:x => 'a'} => (x != 'a')
~{:x => nil} => (x IS NOT NULL)
{:x => /a/} => (x ~ 'blah') # Default, MySQL different
~{:x => /a/} => (x !~ 'blah') # Default, MySQL different
:x.like('a') => (x LIKE 'a')
~:x.like('a') => (x NOT LIKE 'a')
:x.like(/a/) => (x ~ 'a') # Default, MySQL different
~:x.like('a', /b/) => ((x NOT LIKE 'a') AND (x !~ 'b')) # Default
~{:x => 1..5} => ((x < 1) OR (x > 5))
~{:x => DB[:items].select(:i)} => (x NOT IN (SELECT i FROM items))
~{:x => [1,2,3]} => (x NOT IN (1, 2, 3))
:x + 1 > 100 => ((x + 1) > 100)
(:x * :y) < 100.01 => ((x * y) < 100.01)
(:x - :y/2) >= 100 => ((x - (y / 2)) >= 100)
(((:x - :y)/(:x + :y))*:z) <= 100 => ((((x - y) / (x + y)) * z) <=
100)
~((((:x - :y)/(:x + :y))*:z) <= 100) => ((((x - y) / (x + y)) * z) >
100)
:x & :y => (x AND y)
:x & :y & :z => ((x AND y) AND z)
:x & {:y => :z} => (x AND (y = z))
{:y => :z} & :x => ((y = z) AND x)
{:x => :a} & {:y => :z} => ((x = a) AND (y = z))
(:x > 200) & (:y < 200) => ((x > 200) AND (y < 200))
:x | :y => (x OR y)
:x | :y | :z => ((x OR y) OR z)
:x | {:y => :z} => (x OR (y = z))
{:y => :z} | :x => ((y = z) OR x)
{:x => :a} | {:y => :z} => ((x = a) OR (y = z))
(:x > 200) | (:y < 200) => ((x > 200) OR (y < 200))
(:x | :y) & :z => ((x OR y) AND z)
:x | (:y & :z) => (x OR (y AND z))
(:x & :w) | (:y & :z) => ((x AND w) OR (y AND z))
~((:x | :y) & :z) => ((NOT x AND NOT y) OR NOT z)
~((:x & :w) | (:y & :z)) => ((NOT x OR NOT w) AND (NOT y OR NOT z))
~((:x > 200) | (:y & :z)) => ((x <= 200) AND (NOT y OR NOT z))
~('x'.lit + 1 > 100) => ((x + 1) <= 100)
'x'.lit.like(/a/) => (x ~ 'a') # (x ~ \'a\')
None of these require blocks, you can use any directly in a call to
filter:
DB[:items].filter((:price * :tax) - :discount > 100)
# => SELECT * FROM items WHERE (((price * tax) - discount) > 100)
DB[:items].filter(:active & ~:archived)
# => SELECT * FROM items WHERE (active AND NOT archived)
SQL String Concatenation
------------------------
Sequel now has support for expressing SQL string concatenation in an
easy way:
[:name, :title].sql_string_join(" - ")
# SQL: name || ' - ' || title
You can use this in selecting columns, creating filters, ordering
datasets, and possibly elsewhere.
Schema Reflection Support/Typecasting on Assignment
---------------------------------------------------
When used with PostgreSQL, MySQL, or SQLite, Sequel now has the
ability to get information from the database's schema in regards
to column types:
DB.schema(:artist)
=> [[:id, {:type=>:integer, :db_type=>"integer", :max_chars=>0
:numeric_precision=>32, :allow_null=>false,
:default=>"nextval('artist_id_seq'::regclass)"}], [:name,
{:type=>:string, :default=>nil, :db_type=>"text",
:numeric_precision=>0, :allow_null=>true, :max_chars=>0}]]
Models now use this information to typecast values on attribute
assignment. For example, if you have an integer column named number
and a text (e.g. varchar) column named title:
1.5.1:
model.number = '1'
model.number # => '1'
model.title = 1
model.title # => 1
2.0.0:
model.number = '1'
model.number # => 1
model.title = 1
model.title # => '1'
Typecasting can be turned off on a global, per class, and per object
basis:
Sequel::Model.typecast_on_assignment = false # Global
Album.typecast_on_assignment = false # Per Class
Album.new.typecast_on_assignment = false # Per Object
Typecasting is somewhat strict, it does not allow obviously bogus
data to be used:
model.number = 'a' # Raises error
This is in contrast to how some other ORMs handle the situation:
model.number = 'a'
model.number # => 0
If Sequel is being used with a web framework and you want to display
friendly error messages to the user, you should probably turn
typecasting off and set up the necessary validations in your models.
Model Association Improvements
------------------------------
Associations can now be eagerly loaded even if they have a block,
though the block should not rely on being evaluated in the context
of an instance. This allows you filter on associations when eagerly
loading:
Artist.one_to_many :albums_with_10_tracks, :class=>:Album do |ds|
ds.filter(:num_tracks => 10)
end
Artist.filter(:name.like('A%)).eager(:albums_with_10_tracks).all
# SELECT * FROM artists WHERE (name LIKE 'A%')
# SELECT albums.* FROM albums WHERE ((artist_id IN (...)) AND
# (num_tracks = 10))
Associations now have a remove_all_ method for removing all
associated objects in a single query:
Artist.many_to_many :albums
Artist[1].remove_all_albums
# DELETE FROM albums_artists WHERE artist_id = 1
Artist.one_to_many :albums
Artist[1].remove_all_albums
# UPDATE albums SET artist_id = NULL WHERE artist_id = 1
All associations can specify a :select option to change which columns
are selected. Previously only many to many associations supported
this.
The SQL used when eagerly loading through eager_graph can be
modified via the :graph_join_type, :graph_conditions, and
:graph_join_conditions options.
:graph_join_type changes the join type from the default of
:left_outer. This can be useful if you do not want any
albums that don't have an artist in the result set:
Album.many_to_one :artist, :graph_join_type=>:inner
Album.eager_graph(:artist).sql
# SELECT ... FROM albums INNER JOIN artists ...
:graph_conditions adds conditions on the join to the table you are
joining, the eager_graph equivalent of an association block argument
in eager. It takes either a hash or an array where all elements
are arrays of length two, similar to join_table, where key symbols
specify columns in the joined table and value symbols specify
columns in the last joined or primary table:
Album.many_to_one :artist, :graph_conditions=>{:active=>true}
Album.eager_graph(:artist).sql
# SELECT ... FROM albums LEFT OUTER JOIN artists ON ((artists.id =
# albums.artist_id) AND (artists.active = 't'))
:graph_join_table_conditions exists for many to many associations only,
and operates the same as :graph_conditions, except it specifies a
condition on the many to many join table instead of the associated
model's table. This is necessary if the join table is also model
table with other columns on which you may want to filter:
Album.many_to_many :genres, :join_table=>:ag, \
:graph_join_table_conditions=>{:active=>true}
Album.eager_graph(:genres).sql
# SELECT ... FROM albums LEFT OUTER JOIN ag ON ((ag.album_id =
albums.id) AND (ag.active = 't')) LEFT OUTER JOIN genres ON
(genres.id = ag.genre_id)
Other Small Improvements
------------------------
* Dataset#invert returns a dataset that matches all records not
matching the current filter.
* Dataset#unfiltered returns a dataset that has any filters removed.
* Dataset#last_page? and Dataset#first_page? for paginated datasets.
* The sequel command line tool now support an -E or --echo argument
that logs all SQL to the standard output. It also can take a path
to a yaml file with database connection options, in addition to a
database URL.
* Databases can now have multiple SQL loggers, so you can log to the
standard output as well as a file.
* SQL identifiers (columns and tables) are now quoted by default (you
can turn this off via Sequel.quote_identifiers = false if need be).
* Sequel.connect now takes an optional block that will disconnect the
database when the block finishes.
* AlterTableGenerator now has add_primary_key and add_foreign_key
methods.
* Running the specs without ParseTree installed skips the specs that
require ParseTree.
* You can use an array of arrays instead of a hash when specifying
conditions, which may be necessary in certain situations where
you would be using the same hash key more than once.
* Almost all documentation for Sequel was updated for 2.0.0, so if you
found Sequel documentation lacking before, check out the new RDoc
pages.
* There have been many minor refactoring improvements, the code
should now be easier to read and follow.
* Sequel now has no external dependencies.
* Sequel::Models now have before_validation and after_validation
hooks.
* Sequel::Model hooks that return false cause the methods that call
them (such as save) to return false.
* Sequel::Models can now load their schema on first instantiation,
instead of when they are created, via
Sequel::Model.lazy_load_schema=. This is helpful for certain
web frameworks that reload all models on every request.
* Hook methods that use blocks can now include an optional tag,
which allows them to work well with web frameworks that load source
files every time they are modified.
The PostgreSQL adapter has been rewritten and now supports ruby-pg.
There have also been improvements in the following adapters: DBI,
MySQL, SQLite, Oracle, and MSSQL.
All of the methods that have been deprecated in 1.5.0 have now been
removed. If you are want to upgrade to Sequel 2.0.0 from version 1.4.0
or previous, upgrade to 1.5.1 first, fix all of the deprecation
warnings that show up, and then upgrade to 2.0.0.
There were some backwards incompatible changes made in 2.0.0 beyond the
removal of deprecated methods. These are:
* Inflector is no longer used, the inflection methods were moved
directly into String (where they belong because inflections only
make sense for strings). So to override singularization
or pluralization rules, use String.inflections instead of
Inflector.inflections.
* MySQL tinyints are now returned as boolean values instead of
integers. MySQL doesn't have a boolean type, and usually it
is recommended to use tinyint for a boolean column.
* You can no longer pass an array to Dataset#order or Dataset#select,
you need to pass each argument separately (the * operator is your
friend).
* You must use '?' instead of '(?)' when interpolating an array
argument into a string (e.g. filter('x IN ?', [1,2,3]))
* You must pass an explicit table alias argument to join_table and
related methods, you can no longer include the table alias
inside the table argument.
* sqlite:// URLs now operate the same as file:// URLs (2 slashes
for a relative path, 3 for an absolute path).
---
### Doc Release Notes 2.1.0 (`doc/release_notes/2.1.0.txt`)
Model Improvements
------------------
* one_to_many/many_to_many associations now support a :limit option,
adding a limit/offset to the records returned. This was possible
before using a block, so it is just added for convenience.
* Associations now support a :read_only option, which doesn't create
methods that modify the database.
* Associations now support a :graph_select option, which allows
specifying the columns of associated models to include when using
eager_graph.
* one_to_many associations now have a :one_to_one option. When used
it creates a getter and setter method similar to many_to_one. This
fills the same role as ActiveRecord's has_one, but it is
implemented as a couple of convenience methods over one_to_many, so
it still requires that you specify the association name as a
plural.
* Model datasets now have to_hash augmented so that it can be called
without any arguments, in which case it yields an identity map (a
hash with keys being primary key values and values being model
instances).
* The Model.set_sti_key method was added, for easily setting up
single table inheritance. It should be called only in the parent
class.
* Calls to def_dataset_method with a block are now cached and
reapplied to the new dataset if set_dataset is called afterward,
or in a subclass.
* All validation methods can now be made conditional via an :if
option, which takes either a symbol (which specifies an instance
method) or a proc (which is instance_evaled).
* Model#set and Model#update have been added back, they are now
aliases of #set_with_params and #update_with_params.
* Models now have set_only/set_except/update_only/update_except
instance methods that take a hash (like you would provide to
set or update) and additional arguments specifying which columns
to allow or disallow.
* Models now have a set_allowed_columns and set_restricted_columns
methods, which operate similarly to ActiveRecord's attr_accessible
and attr_protected. It is recommend that you use the set_only or
update_only instead of these methods, though. You can ignore the
allowed or restricted columns by using #set_all or #update_all.
* The primary key column(s) is restricted by default. To allow it to
be set via new/set/update, use:
Sequel::Model.unrestrict_primary_key # Global
Artist.unrestrict_primary_key # Per Class
* It is now easy to override the one_to_many/many_to_many association
methods that modify the database (add_/remove_/remove_all_), as
they have been broken into two methods, one that handles the
caching features and a private one (prepended with an _) that
handles the database changes (and which you can easily override
without worrying about the caching).
Table Joining
-------------
Dataset#join_table got a nice overhaul. You can now use any join
type your database allows:
DB[:artist].join_table(:natural, :albums)
DB[:numbers].join_table(:cross, :numbers)
You can now specify the conditions as
* String: "a.b = c.d" # ON a.b = c.d
* Expression :x < :y # ON x < y
* Array of Symbols: [:x, :y, :z] # USING (x, y, z)
* nil # no conditions, used for NATURAL or CROSS joins
Dataset#join_table also takes a block that yields three arguments:
* join_table_alias - The alias/name of the table currently being
joined
* last_join_table_alias - The alias name of the last table joined
(if there was one) or the first FROM table (if not).
* joins - An array of JoinClause objects for all previous joins in
the query.
Using the block you can specify conditions for complex joins without
needing to know in advance what table aliases will be used.
Expanded SQL Syntax Support
---------------------------
SQL Case statements are now supported directly using hashes or
arrays:
{:x > 1 => 1}.case(0)
# CASE WHEN x > 1 THEN 1 ELSE 0 END
[[{:x=>1}, 0], [:x < 1, 1], [:x > 1, 2]].case(-1)
# CASE WHEN x = 1 THEN 0 WHEN x < 1 THEN 1 WHEN x > 1 THEN 2
ELSE -1 END
You should use an array instead of a hash for multiple conditions
unless all conditions are orthogonal.
The SQL extract function has special syntax:
EXTRACT(day FROM date)
This syntax is now supported via the following ruby code:
:date.extract(:day)
Other Notable Changes
---------------------
* The sequel command line tool can now run migrations. The -m
option specifies the directory holding the migration files,
and the -M options specifies the version to which to migrate.
* The PostgreSQL adapter supports nested transactions/savepoints.
* The schema parser now understands decimal fields, and will
typecast to BigDecimal.
* PostgreSQL's numeric type is now recognized and returned as
BigDecimal.
* HAVING now comes before ORDER BY, which most databases seem to
prefer. If your database wants HAVING after ORDER BY, please
let us know.
* Symbol#qualify now exists, to specify the table name for a given
symbol, similar to the use of #as to specify an alias. This is
mainly helpful in conjunction with the #join_table block, as that
provides the table aliases to use to qualify the columns inside
the block.
* BitwiseMethods (&, |, ^, ~, <<, >>) have been added to the
NumericExpression class, so you can do the following:
(x + 1) ^ 10 # SQL: (x + 1) ^ 10
~(x + 1) # SQL: ~(x + 1)
Usually, &, |, and ~ operate in a logical manner, but for
NumericExpressions, they take on their usual bitwise meaning,
since logical operations only make sense for booleans.
* #cast_numeric and #cast_string exist for Symbols, Strings, and
other Sequel Expressions, which return the results casted and
wrapped in either NumericExpression or StringExpression, so you
can use the BitwiseMethods (&, |, ^, ~, <<, >>) or
StringConcatenationMethods (+) directly.
# Dataset#to_hash can take only one argument, in which case it uses
that argument to specify the key, and uses the entire hash for the
value.
# Dataset#graph can now take an array of columns to select from the
joined table via the :select option.
# Dataset#filter and similar methods now combine the block and
regular argument conditions if both are given, instead of ignoring
the regular argument conditions.
# Dataset#filter(false) can now be used to make sure that no records
are returned. Dataset#filter(true) also works, but it's a no-op.
Before, these raised errors.
# Dataset#count does a subquery for a dataset using DISTINCT, since
the otherwise it would yield a count for the query without
DISTINCT.
ParseTree Support Officially Deprecated
---------------------------------------
The support for ParseTree-based block filters has officially been
deprecated and will be removed in Sequel 2.2. To use the
expression filters (which don't require ParseTree) inside blocks,
use:
SEQUEL_NO_PARSE_TREE = true
require 'sequel'
# OR
require 'sequel'
Sequel.use_parse_tree = false
This is the default if ParseTree cannot be loaded. If ParseTree
can be loaded, it remains the default, in order not to immediately
break existing code.
With this set, you can use the expression filters inside of blocks:
dataset.filter{((:x + 1) & 10 < :y) & :z}
That doesn't gain you all that much, but there are some methods
that feed block arguments into filter, such as the following:
dataset.first(5){((:x + 1) & 10 < :y) & :z}
Which will get you the first 5 records matching the condition.
Backwards Incompatible Changes
------------------------------
* To change the datetime class used from Time to DateTime, you
now use:
Sequel.datetime_class = DateTime # instead of Sequel.time_class
* Models now raise errors if you try to access a missing or
restricted method via new/set/update, instead of just silently
skipping that parameter. To get the old behavior:
Sequel::Model.strict_param_setting = false
* The association_dataset method now takes into account the :eager
option and the block argument, where it didn't before. It also
takes into account the new :limit option.
* Association methods now raise errors in most cases if the model
doesn't have a valid primary key.
* Dataset#join_table used to allow a symbol as a conditions argument
as a shortcut for a hash:
DB[:artist].join(:albums, :artist_id)
# ON albums.artist_id = artists.id
With the changes to #join_table, this no longer works. It would
now be interpreted as a boolean column:
DB[:artist].join(:albums, :artist_id)
# ON artists.id
Use the following slightly longer version for the old behavior:
DB[:artist].join(:albums, :artist_id=>:id)
# ON albums.artist_id = artists.id
* MySQL users need to be careful when upgrading, the following code
will once again cause an error:
DB[:artists].each{|artist| DB[:albums].each{|album| ...}}
To fix it, change the code to:
DB[:artists].all{|artist| DB[:albums].each{|album| ...}}
The issue is the MySQL adapter doesn't release the database
connection while running each, and the second call to each gets the
same database connection (while the other query is still running),
because it is in the same thread. Using #all for the outside query
ensures that the database connection is released before the block is
called.
The reason for this change was that the workaround provided for
MySQL could potentially cause issues with transactions for all
adapters.
* String#asc and String#desc are no longer defined, as ordering on a
plain string column should be a no-op. They are still defined
on LiteralStrings.
* You can no longer abuse the SQL::Function syntax to use a table
alias with specified columns (e.g. :table[:col1, :col2, :col3])
or to cast to types (e.g. :x.cast_as(:varchar[20])). Use a
LiteralString in both cases.
---
### Doc Release Notes 2.10.0 (`doc/release_notes/2.10.0.txt`)
New Supported Adapters and Databases
------------------------------------
* A DataObjects adapter was added that supports PostgreSQL,
MySQL, and SQLite. DataObjects is the underlying database
library used by DataMapper, and has potential performance
advantages by doing all typecasting in C.
* A Firebird Adapter was added, it requires the modified Ruby
Fb adapter found at http://github.com/wishdev/fb.
* An H2 JDBC subadapter was added, based on the code used in JotBot.
H2 is an embeddable Java database, and may be preferable to using
SQLite on JDBC because SQLite requires native code.
New Core Features
-----------------
* Sequel now has database independent migrations. Before, column
types in migrations were not translated per database, so it was
difficult to set up a migration that worked on multiple databases.
Sequel now accepts ruby classes as database types, in addition to
symbols and strings. If a ruby class is used, it is translated
to the most appropriate database type. Here is an example using
all supported classes (with Sequel's default database type):
DB.create_table(:cats) do
primary_key :id, :type=>Integer # integer
String :a # varchar(255)
column :b, File # blob
Fixnum :c # integer
foreign_key :d, :other_table, :type=>Bignum # bigint
Float :e # double precision
BigDecimal :f # numeric
Date :g # date
DateTime :h # timestamp
Time :i # timestamp
Numeric :j # numeric
TrueClass :k # boolean
FalseClass :l # boolean
end
Type translations were tested on the PostgreSQL, MySQL, SQLite,
and H2 databases. The default translations should work OK for
most databases, but there will probably be a type or two that
doesn't work. Please send in a patch if Sequel uses a column type
that doesn't work on your database.
Note that existing migrations still work fine, in most cases. If
you were using strings or symbols for types before, they should
still work. See the Backwards Compatibility section below for
details.
Also note that this doesn't relate solely to migrations, as any
database schema modification method that accepts types will
accept one of the above classes.
* A ton of internal work was done to better support databases that
fold unquoted identifiers to uppercase (which is the SQL standard).
Sequel now allows you to set a method to call on identifiers going
both into and out of the database. The default is to downcase
identifiers coming out, and upcase identifiers going in, though
this is overridden by the PostgreSQL, MySQL, and SQLite adapters
to not do anything (since they fold to lowercase by default).
The settings are called identifier_input_method and
identifier_output_method, and like most Sequel settings, they can
be set globally, per database, or per dataset:
# Global (use uppercase in ruby and lowercase in the database)
Sequel.identifier_input_method = :downcase
Sequel.identifier_output_method = :upcase
# Per Database (use camelized names in the database, and
# underscored names in ruby)
DB.identifier_input_method = :camelize
DB.identifier_output_method = :underscore
# Per Dataset (obfuscate your database columns!)
class String; def rot_13; tr('A-Za-z', 'N-ZA-Mn-za-m') end end
ds = DB[:table]
ds.identifier_input_method = :rot_13
ds.identifier_output_method = :rot_13
* Schema parsing support was added to the JDBC adapter, using the
JDBC metadata methods. This means that models that use the
JDBC adapter will typecast data in their column setters and
automatically select the correct primary key column(s). This is
currently the only adapter that supports schema parsing when using
an MSSQL or Oracle database.
* Database#create_table now takes options, which you can use to
specify a MySQL engine, charset, and/or collation. You can also
set a default engine, charset, and collation for MySQL to use:
Sequel::MySQL.default_engine = 'InnoDB'
Sequel::MySQL.default_charset = 'utf8'
Sequel::MySQL.default_collate = 'utf8'
The defaults will be used if the options are not provided. If a
default engine is set, you can specify :engine=>nil to not use it
(same goes for charset and collate).
* The Sequel::DatabaseConnectionError exception class was added. It
is raised by the connection pool if there is an error attempting
to instantiate a database connection. Also, if the adapter returns
nil instead of raising an error for faulty connection parameters,
DatabaseConnectionError will be raised immediately, instead of the
connection pool busy waiting until if gives up with a
PoolTimeoutError.
* Database#tables is now supported on the JDBC adapter, returning
an Array of table name symbols.
* Sequel now converts the following Java types returned by the JDBC
adapter into ruby types: Java::JavaSQL::Timestamp,
Java::JavaSQL::Time, Java::JavaSQL::Date,
Java::JavaMath::BigDecimal, and Java::JavaIo::BufferedReader.
* When using the PostgreSQL adapter with the postgres-pr driver,
Sequel will use a custom string escaping routine unless
force_standard_strings = false. This means that using Sequel's
defaults, postgres-pr will correctly escape strings now.
* The SQLite adapter now returns float, real, and double precision
columns as Floats.
* The SQLite adapter logs beginning, committing, and rolling back
transactions.
* Sequel now has an internal version (before, the only way to tell
the version was to look at the gem being used). It is accessible
at Sequel.version.
New Model Features
------------------
* A new validates_not_string validation was added for Sequel Models.
It is intended to be used with the raise_on_typecast_failure =
false setting. In this case, for a non-string database column,
if there is a string value when the record is going to be
saved, it is due to the fact that Sequel was not able to typecast
the given data correctly (so it is almost certainly not valid).
This should make Sequel easier to use with web applications.
* An :allow_missing validation option was added to all standard
validations. This option skips the validation if the attribute
is not in the object's values. It is different from :allow_nil,
which will skip the value if it is present but nil in the values.
The intended use case for this option is when the database provides
a good default. If the attribute is not present in values, the
database will use its default. If the attribute is present in
the values but equals nil, Sequel will attempt to insert it into
the database as a NULL value, instead of using the database's
default. If you don't want Sequel to insert a NULL value in the
database, but you want the database to provide the default, this
is the option to use.
* validates_each now accepts :allow_nil and :allow_blank options,
so it is easier to create custom validations with the same options
as the standard validations.
* Before_* hooks now run in the reverse order that they were added.
The purpose of hooks is to wrap existing functionality, and making
later before_* hooks run before previous before_* hooks is the
correct behavior.
* You can now add you own hook types, via Model.add_hook_type. This
is intended for plugin use. All of the standard hooks are now
implemented using this method.
* The value of new? in a after_save hook now reflects the
previous state of the model (so true for a create and false for an
update), instead of always being false. This makes it easier
to have a complex after_save hook that still needs to
differentiate between a newly created record and an updated record,
without having to add separate after_create and after_update
hooks.
* The value of changed_columns in an after_update hook now reflects
the value before the update occurred, instead of usually being
empty. Previously, to have this functionality, you generally had
to save the value to an instance variable in a before_update hook
so you could reference it in the after_update hook.
Other Improvements
------------------
* Sequel now longer overwrites the following Symbol instance methods
when running on ruby 1.9: [], <, <=, >, and >=. One of Sequel's
principals is that it does not override methods defined by ruby,
and now that ruby 1.9 defines the above methods on Symbol, Sequel
shouldn't be overwriting them.
Sequel already provides a way to work around this issue when
another library adds the same methods to Symbol that Sequel does.
For example, you need to change the following:
dataset.filter(:number > 1)
dataset.filter(:number >= 2)
dataset.filter(:name < 'M')
dataset.filter(:name <= 'I')
dataset.filter(:is_bool[:x])
To:
dataset.filter{|o| o.number > 1}
dataset.filter{|o| o.number >= 2}
dataset.filter{|o| o.name < 'M'}
dataset.filter{|o| o.name <= 'I'}
dataset.filter{|o| o.is_bool(:x)}
The argument provided to the block is a Sequel::SQL::VirtualRow.
This class uses method_missing so that any methods called on it
return Sequel::SQL::Identifiers (if no arguments are provided)
or Sequel::SQL::Function (if arguments are provided).
If you were using one of the above symbol methods outside of a
filter, you can to call sql_string, sql_number, or sql_function
on the symbol. So the following would also work:
dataset.filter(:number.sql_number > 1)
dataset.filter(:number.sql_number >= 2)
dataset.filter(:name.sql_string < 'M')
dataset.filter(:name.sql_number <= 'I')
dataset.filter(:is_bool.sql_function(:x))
Using the block argument makes for a nicer API, though, so I
recommend using it when possible.
Note that if you are running ruby 1.8 or jruby without the --1.9
flag, you don't need to worry. If you are running ruby 1.9 or
jruby --1.9, or you plan to at some point in the future, you
should inspect your code for existing uses of these methods.
Here are a couple command lines that should find most uses:
# Find :symbol[]
egrep -nr ':['\''"]?[a-zA-Z_0-9]*['\''"]?\[' *
# Find :symbol (<|>|<=|>=)
egrep -nr '[^:]:['\''"]?[a-zA-Z_0-9]*['\''"]? *[<>]=?' *
* Database#quote_identifiers now affects future schema modifications
when using the database. Previous, it only affected future
schema modifications if a schema modification method had not yet
been called.
* Literalization of Times and DateTimes is now correct when using the
MySQL JDBC subadapter.
* Literalization of Blobs is now correct when using the PostgreSQL
JDBC subadapter.
* Index and table names are quoted when creating indices in the
PostgreSQL adapter.
* Dataset#delete was changed in the SQLite adapter to add a
where clause that is always true, instead of doing an explicit
count first and the deleting. This is simpler, though it
could potentially have performance implications.
* The sequel command line tool now supports symbol keys and unnested
hashes in YAML files, so it should work with Merb's database.yml.
It also includes the error class in the case of an error.
* The integration type tests were greatly expanded. Generally,
running the integration tests is a good way to determine how well
your database is supported.
* Dataset#quote_identifier now returns LiteralStrings as-is, instead
of treating them as regular strings.
* Sequel no longer modifies the MySQL::Result class when using the
MySQL adapter.
Backwards Compatibility
----------------------
* If you were previously using a database that returned uppercase
identifiers, it will probably return lowercase identifiers by
default now. To get back the old behavior:
DB.identifier_output_method = nil
* The module hierarchy under Sequel::SQL has changed. Now,
modules do not include other modules, and the following modules
were removed since they would have been empty after removing
the modules they included: Sequel::SQL::SpecificExpressionMethods
and Sequel::SQL::GenericExpressionMethods.
* Sequel no longer assumes the public schema by default when
connecting to PostgreSQL. You can still set the default
schema to use (even to public).
* The ability to load schema information for all tables at once
was removed from the PostgreSQL adapter. While it worked, it had
some issues, and it was difficult to keep it working when some
new features were used. This ability wasn't exposed to the user,
and was purely an optimization. If you have any code like:
DB.schema
by itself after the Database object was instantiated, you should
remove it.
* The Database#primary_key API changed in the PostgreSQL shared
adapter, it now accepts an options hash with :server and :conn keys
instead of a server symbol. Also, quite a few private Database
instance methods changed, as well as some constants in the
AdapterMethods.
* It is possible that some migrations will break, though it is
unlikely. If you were using any of the classes mentioned above
as a method inside a migration, it might be broken. However,
since String, Float, and Integer wouldn't have worked as methods
before, it is unlikely that anyone used this.
* The meaning of #String, #Integer, and #Float inside
Sequel::SQL::Generator (i.e. inside a Database#create_table
block) has changed. Before, these used to call private Kernel
methods, now, they set up columns with the appropriate database
type.
* The Database#lowercase method in the DBI adapter was removed,
as its use case is now met by the identifier_output_method support.
* Database#uri is now aliased explicitly via a real method, to
allow for easier subclassing.
* You can no longer pass nil as the second argument to
Database#create_table.
---
### Doc Release Notes 2.11.0 (`doc/release_notes/2.11.0.txt`)
Optimizations
-------------
* Model.[] was optimized to use static SQL in cases where doing so
should result in the same output. This should result in a 30-40%
performance increase. Since this can be the most significant or
only method call in a web application action, this has potential
to significantly enhance the performance of web application code.
In order for this optimization to have an effect, you need to
make sure that you are calling set_dataset with a Symbol and
not a Dataset object:
# Optimized:
class Foo < Sequel::Model; end
class Foo < Sequel::Model(:foos); end
class Foo < Sequel::Model
set_dataset :foos
end
# Not Optimized, but otherwise equivalent:
class Foo < Sequel::Model(Model.db[:foos]); end
class Foo < Sequel::Model
set_dataset db[:foos]
end
* Dataset#literal was refactored for performance reasons to make
overriding it in subclasses unnecessary. The changes made result
in a 20-25% performance increase. Sequel can spend about 10% of
it's time in Dataset#literal, so this may be only a 2% overall
performance improvement.
New Features
------------
* Association datasets now know about the model objects that created
them, as well as the related association reflection. This makes
association extensions much more powerful. For example, you can
now create generic association extensions such as:
module FindOrCreate
def find_or_create(vals)
first(vals) || association_reflection.associated_class. \
create(vals.merge(association_reflection[:key]=> \
model_object.id))
end
end
The above will work for any standard one_to_many association:
Artist.one_to_many :albums, :extend=>FindOrCreate
# Create an album named Foo related to this artist,
# unless such an album already exists
Artist.first.albums_dataset.find_or_create(:name=>'Foo')
Before, the only way to do the above was to use a closure inside
the :dataset option proc, which couldn't be done generically
for multiple associations.
* A :conditions association option was added, which allows simple
filters to be set up without defining :graph_conditions and
an association block:
# 2.10.0
one_to_many(:japanese_verses, :class=>:Verse, \
:graph_conditions=>{:languageid=>3})do |ds|
ds.filter(:languageid=>3)
end
# 2.11.0
one_to_many(:japanese_verses, :class=>:Verse, \
:conditions=>{:languageid=>3})
* A :clone association option was added, which allows you to clone
an existing association. This is most useful when you are dealing
with a legacy schema and had to define the same options redundantly
for each type of association. You can now do:
many_to_many :deputies, :class=>:Employee, \
:join_table=>:employeecurrentaudits, :left_key=>:currentauditid, \
:right_key=>:employeeid, :order=>[:firstname, :lastname] do |ds|
ds.filter(:active).filter(:capacity=>1)
end
many_to_many :project_managers, :clone=>:deputies do |ds|
ds.filter(:active).filter(:capacity=>2)
end
many_to_many :team_leaders, :clone=>:deputies do |ds|
ds.filter(:active).filter(:capacity=>3)
end
All of the above would use the same :class, :join_table, :left_key,
:right_key, and :order options. If you don't provide an
association block, but you are cloning an association that has one,
the cloned association's block is used. You can use the
:block=>nil option to not use a block even if the cloned
association has a block.
* Dataset#select, #select_more, #order, #order_more, and #get all
take a block that yields a Sequel::SQL::VirtualRow instance,
similar to the behavior of filter. This allows for the easier
use of SQL functions on Ruby 1.9:
# 2.10.0
dataset.select(:prettify.sql_function(:name))
# 2.11.0
dataset.select{|o| o.prettify(:name)}
* String#lit can now accept arguments and return an SQL literal
string. This allows you to do things that were previously hard
or at least unnecessarily verbose. For example, you can now
easily use the SQL standard SUBSTRING function:
column = :user
pattern = params[:pattern]
dataset.select{|o| o.substring('? from ?'.lit(column, pattern))}
* A validates_inclusion_of validation method was added to Model. You
can provide a Range or an Array in the :in option to specify the
allowed values:
validates_inclusion_of :value, :in=>1..5
validates_inclusion_of :weekday, :in=>%w'Monday Tuesday ...'
* Dataset#with_sql was added, which returns a copy of the dataset
with static SQL. This is useful if you want to keep the same
row_proc/graph/transform/etc., but want to use your own custom
SQL.
Other Improvements
------------------
* You can now use Sequel's database independent types when casting:
dataset.select(:number.cast(String))
Among other things, the default cast types for cast_string and
cast_numeric now work in the MySQL adapter.
* Model#set_associated_object was added. The many_to_one association
setter method calls it. This allows you to easily override the
association setters for all many_to_one associations of a class
by modifying a single method.
* Typecasting invalid date strings now raises a
Sequel::Error::InvalidValue instead of an argument error, which
means that you can use raise_on_typecast_failure = false and not
have an error raised when an invalid date format is used.
* String#to_sequel_blob was added and should now be used instead
of String#to_blob. sqlite3-ruby defines String#to_blob
differently, which could cause problems.
* Blob columns are now fully supported in the SQLite adapter, with
the hex escape syntax being used for input, and returning columns
of type Sequel::SQL::Blob on output.
* The SQLite adapter drop_column support is now significantly more
robust.
* The SQLite adapter now supports rename_column.
* The MySQL adapter now supports stored procedures with multiple
arguments.
* The MySQL adapter can now not use a compressed connection to the
server via the :compress=>false option.
* The MySQL adapter now sets a default timeout of 30 days to the
database connection, you can change it via the :timeout option,
which accepts a number of seconds.
* The MySQL adapter now sets SQL_AUTO_IS_NULL to false by default,
you can use the :auto_is_null=>true option to not do this.
* The MySQL adapter now sets the encoding option on the database
connection itself, so it works across reconnects.
* Sequel itself no longer uses String#lit or Symbol#* internally, so
it shouldn't break if another library defines them.
* The default index name is now generated correctly if a non-String
or Symbol column is used.
* Some ruby -w warnings have been fixed.
* INSERTs are now sent to the master database instead of the slave
database(s) if using a master/slave database configuration and
PostgreSQL 8.2+ or Firebird.
* DateTime literalization has been fixed in the Firebird adapter.
* Date literalization has been fixed in the H2 JDBC subadapter.
* Release notes for versions from 1.0 to the present are now included
in the Sequel repository and the RDoc documentation, see
http://sequel.rubyforge.org/rdoc/files/doc/release_notes/
Backwards Compatibility
----------------------
* The optimization of Model.[] may break if you modify the model's
dataset behind its back. Always use Model.set_dataset if you
want to change a Model's dataset.
* Sequel::Dataset::UnsupportedExceptIntersect and
Sequel::Dataset::UnsupportedExceptIntersectAll will now only be
defined if you are using an adapter that requires them.
* The private Model#cache_delete_unless_new method has been removed.
* Sequel::SQL::IrregularFunction was removed, as it was a bad hack
that is not used by Sequel anymore. Unless you were instantiating
it directly or using a plugin/extension that did, this shouldn't
affect you. Using a Sequel::SQL::Function with a
Sequel::SQL::PlaceholderLiteralString is recommended instead, see
the substring example above.
---
### Doc Release Notes 2.12.0 (`doc/release_notes/2.12.0.txt`)
Overview
--------
Sequel 2.12 is really just a stepping stone to Sequel 3.0, which will
be released next month. All major changes currently planned for 3.0
have been made in 2.12, but 2.12 contains many features that have
been deprecated and will be removed or moved into extensions or
plugins in 3.0.
Deprecation Logging
-------------------
If you use a deprecated method or feature, Sequel will by default
print a deprecation message and 10 lines of backtrace to standard
error to easily allow you to figure out which code needs to be
updated. You can change where the deprecation messages go and how
many lines of backtrace are given using the following:
# Log deprecation information to a file
Sequel::Deprecation.output = File.open('deprecated.txt', 'wb')
# Use 5 lines of backtrace when logging deprecation messages
Sequel::Deprecation.backtraces = 5
# Use all backtrace lines when logging deprecation messages
Sequel::Deprecation.backtraces = true
# Don't include backtraces in the deprecation logging
Sequel.Deprecation.backtraces = false
# Turn off all deprecation logging
Sequel::Deprecation.output = nil
Deprecated Features Moving to Extensions
----------------------------------------
* Migrations are being moved into sequel/extensions/migration. There
isn't any reason that they should be loaded in normal use since
they are used so rarely. The sequel command line tool uses this
extension to run the migrations.
* Adding the blank? method to all objects has been moved into
sequel/extensions/blank.
* Dataset#print and Sequel::PrettyTable have been moved into
sequel/extensions/pretty_table.
* Dataset#query and related methods have been moved into
sequel/extensions/query.
* Dataset#paginate and related methods have been moved into
sequel/extensions/pagination.
* String inflection methods (e.g. "people".singularize) have been
moved into sequel/extensions/inflector.
* String date/time conversion methods (e.g. '2000-01-01'.to_date)
have been moved into sequel/extensions/string_date_time.
Deprecated Model Features Moving to Plugins
-------------------------------------------
* Model validation class methods have been moved to a plugin. Sequel
users are encouraged to write their own validate instance method
instead. A new validation_helpers plugin has been added to make
this easier, it's explained in the New Features section. If you
want to continue using the validation class methods:
Sequel::Model.plugin :validation_class_methods
* Model hook class methods have been moved to a plugin. Sequel users
are encouraged to write their own hook instance methods, and call
super to get hooks specified in superclasses or plugins. If you
want to continue using the hook class methods:
Sequel::Model.plugin :hook_class_methods
* Model schema methods (e.g. Model.set_schema, Model.create_table,
Model.drop_table) have been moved to a plugin. The use of these
methods has been discouraged for a long time. If you want to use
them:
Sequel::Model.plugin :schema
* Model.set_sti_key has been moved to a plugin. So you should
change:
MyModel.set_sti_key :key_column
to:
MyModel.plugin :single_table_inheritance, :key_column
* Model.set_cache has been moved to a plugin. So you should change:
MyModel.set_cache cache_store, opts
to:
MyModel.plugin :caching, cache_store, opts
* Model.serialize has been moved to a plugin. So you should change:
MyModel.serialize :column, :format=>:yaml
to:
MyModel.plugin :serialization, :yaml, :column
Because the previous serialization support depended on dataset
transforms, the new serialization support is implemented
differently, and behavior may not be identical in all cases.
However, this should be a drop in replacement for most users.
Deprecated Features To Be Removed in Sequel 3.0
-----------------------------------------------
* Dataset#transform is deprecated without any replacement planned.
It was announced on the Sequel mailing list that transforms would
be removed unless someone said they needed them, and nobody said
that they did.
* Dataset#multi_insert and Dataset#import are no longer aliases
of each other. Dataset#multi_insert now takes an array of hashes,
and Dataset#import now takes an array of columns and an array
of arrays of values. Using multi_insert with import's API or
vice-versa is deprecated.
* Calling Dataset#[] with no arguments or an integer argument is
deprecated.
* Calling Dataset#map with both an argument and a block is
deprecated.
* Database#multi_threaded? and Database#logger are both deprecated.
* Calling Database#transaction with a symbol to specify which server
to use is deprecated. You should now call it with an option hash
with a :server key.
* Array#extract_options! and Object#is_one_of? are both deprecated.
* The metaprogramming methods taken from metaid are deprecated and
have been moved into Sequel::Metaprogramming. If you want them
available to specific objects/classes, just include or extend with
Sequel::Metaprogramming. If you want all objects to have access to
the metaprogramming methods, install metaid. Note that the
class_def method from metaid doesn't exist in
Sequel::Metaprogramming, since it really isn't different from
define_method (except it is public instead of private).
* Module#class_attr_overridable, #class_attr_reader, and
#metaalias are deprecated.
* Using Model#set or #update when the columns for the model are not
set and you provide a hash with symbol keys is deprecated.
Basically, you must have setter methods now for any columns used in
#set or #update.
* Model#set_with_params and #update_with_params are deprecated, use
#set and #update instead.
* Model#save! is deprecated, use #save(:validate=>false).
* Model.is and Model.is_a are deprecated, use Model.plugin.
* Model.str_columns, Model#str_columns, #set_values, and
#update_values are deprecated. You should use #set and
#update instead of #set_values and #update_values, though they
operate differently.
* Model.delete_all, Model.destroy_all, Model.size, and Model.uniq
are deprecated, use .delete, .destroy, .count, and .distinct.
* Model.belongs_to, Model.has_many, and Model.has_and_belongs_to_many
are deprecated, use .many_to_one, .one_to_many, and .many_to_many.
* Model#dataset is deprecated, use Model.dataset.
* SQL::CastMethods#cast_as is deprecated, use #cast.
* Calling Database#schema without a table argument is deprecated.
* Dataset#uniq is deprecated, use Dataset#distinct.
* Dataset#symbol_to_column_ref is deprecated, use #literal.
* Dataset#quote_column_ref is deprecated, use #quote_identifier.
* Dataset#size is deprecated, use #count.
* Passing options to Dataset#each, #all, #single_record,
#single_value, #sql, #select_sql, #update, #update_sql, #delete,
#delete_sql, and #exists is deprecated. Modify the options first
using clone or a related method, then call one of the above
methods.
* Dataset#create_view and #create_or_replace_view are deprecated,
use the database methods instead.
* Dataset.dataset_classes, #model_classes, #polymorphic_key, and
#set_model are deprecated.
* Database#>> is deprecated.
* String#to_blob and SQL::Blob#to_blob are deprecated, use
#to_sequel_blob.
* The use of Symbol#| to create array subscripts is deprecated,
use Symbol#sql_subscript.
* Symbol#to_column_ref is deprecated, use Dataset#literal.
* String#expr is deprecated, use String#lit.
* Array#to_sql, String#to_sql, and String#split_sql are deprecated.
* Passing an array to Database#<< is deprecated.
* Range#interval is deprecated.
* Enumerable#send_each is deprecated.
* When using ruby 1.8, Hash#key is deprecated.
* Sequel.open is deprecated, use Sequel.connect.
* Sequel.use_parse_tree and Sequel.use_parse_tree= are deprecated.
* All upcase_identifier methods and the :upcase_identifiers database
option are deprecated, use identifier_input_method = :upcase
instead.
* Using a virtual row block without an argument is deprecated, see
Sequel.virtual_row_instance_eval= under New Features.
* When using the JDBC adapter, Java::JavaSQL::Timestamp#usec is
deprecated. Sequel has returned Java::JavaSQL::Timestamp as
DateTime or Time for a few versions, so this shouldn't affect most
people.
* Sequel will no longer require bigdecimal/util, enumerator, or yaml
in 3.0. If you need them in your code, make sure you require
them yourself. Using features added by requiring these standard
libraries will not bring up a deprecation warning, for obvious
reasons.
* Sequel::Error::InvalidTransform, Sequel::Error::NoExistingFilter,
and Sequel::Error::InvalidStatement exceptions will be removed in
Sequel 3.0. You will not get a deprecation message if you reference
them in 2.12.
* Sequel::Model::Validation::Errors is deprecated, use
Sequel::Model::Errors instead. Referencing the old name will not
bring up a deprecation message.
New Features
------------
* Sequel.virtual_row_instance_eval= was added, which lets you give
Sequel 2.12 the behavior that will be the standard in 3.0.
It changes blocks passed to Dataset#filter, #select, or #order that
don't accept arguments (or accept any number of arguments) to
instance eval the block in the context of a new VirtualRow
instance instead of passing a new VirtualRow instance to the block.
It allows you to change code that looks like this:
dataset.filter{|o| (o.number > 10) & (o.name > 'M')}
to:
dataset.filter{(number > 10) & (name > 'M')}
When instance_eval is used, only local variables are available
to the block. Any calls to instance methods will be interpreted
as calling VirtualRow#method_missing, which generates identifiers
or functions. When virtual_row_instance_eval is enabled, the
following type of code will break:
# amount is a instance method
dataset.filter{:number + amount > 0}
Just like this example, the only type of code that should break is
when a virtual row block was used when it wasn't necessary (since
it doesn't use the VirtualRow argument).
When Sequel.virtual_row_instance_eval = false, using a virtual row
block that doesn't accept an argument will cause a deprecation
message.
Here's a regular expression that should catch most places where you
are using a virtual row block without an argument.
egrep -nr '[^A-Za-z0-9_](filter|select|select_more|order|order_more|get|where|having|from|first|and|or|exclude|find|subset|constraint|check)( *(\([^)]*\) *)?){*[^|]' *
An RDoc page explaining virtual row blocks was added as well.
* A validation_helpers model plugin was added that allows you to do
validations similar to the old class level validations inside
the Model#validate instance method. The API has changed, but it's
capable of most of the same validations. It doesn't handle
acceptance_of or confirmation_of validations, as those shouldn't be
handled in the model.
# Old class level validations
validates_format_of :col, :with=>/.../
validates_length_of :col, :maximum=>5
validates_length_of :col, :minimum=>3
validates_length_of :col, :is=>4
validates_length_of :col, :within=>3..5
validates_not_string :col
validates_numericality_of :col
validates_numericality_of :col, :only_integer=>true
validates_presence_of :col
validates_inclusion_of :col, :in=>[3, 4, 5]
validates_uniqueness_of :col, :col2
validates_uniqueness_of([:col, :col2])
# New instance level validations
def validate
validates_format /.../, :col
validates_max_length 5, :col
validates_min_length 3, :col
validates_exact_length 4, :col
validates_length_range 3..5, :col
validates_not_string :col
validates_numeric :col
validates_integer :col
validates_presence :col
validates_includes([3,4,5], :col)
validates_unique :col, :col2
validates_unique([:col, :col2])
end
Another change made is to specify the same type of validation on
multiple attributes, you must use an array:
# Old
validates_length_of :name, :password, :within=>3..5
# New
def validate
validates_length_range 3..5, [:name, :password]
end
The :message, :allow_blank, :allow_missing, and :allow_nil options
are still respected. The :tag option is not needed as instance level
validations work with code reloading without workarounds. The :if
option is also not needed for instance level validations:
# Old
validates_presence_of :name, :if=>:new?
validates_presence_of :pass, :if=>{flag > 3}
# New
def validate
validates_presence(:name) if new?
validates_presence(:pass) if flag > 3
end
The validates_each also doesn't have an equivalent instance method,
since it is much easier to just write your own validation:
# Old
validates_each(:date) do |o,a,v|
o.errors.add(a, '...') unless v > Date.today
end
# New
def validate
errors.add(:date, '...') unless date > Date.today
end
* MySQL adapter datasets now have on_duplicate_key_update and
insert_ignore methods which modify the SQL used to support
ON DUPLICATE KEY UPDATE and INSERT IGNORE syntax in multi_insert
and import.
* If you use the MySQL native adapter, you can set:
Sequel::MySQL.convert_invalid_date_time = nil
to return dates like "0000-00-00" and times like "25:00:00" as
nil values instead of raising an error. You can also set it
to :string to return the values as strings.
* You can now use Sequel without modifying any core classes, by
defining a SEQUEL_NO_CORE_EXTENSIONS constant or environment
variable. In 2.12, this may still add some deprecated methods to
the core classes, but in 3.0 no methods will be added to the core
classes if you use this.
* You can now use Sequel::Model without the associations
implementation by defining a SEQUEL_NO_ASSOCIATIONS constant or
environment variable.
Other Improvements
------------------
* Model column accessors have been made faster and the overhead of
creating them has been reduced significantly.
* ~{:bool_col=>true} now generates an bool_col IS NOT TRUE filter
instead of bool_col != TRUE. This makes it return records with
NULL values. If you only want to have false records, you should
use {:bool_col=>false}. This works better with SQL's 3 valued
boolean logic.
It is slightly inconsistent with ~{:col=>1}, since that won't
return values where col is NULL, but it gives the user the ability
to create an IS [NOT] (TRUE|FALSE) filter, which Sequel previously
did not support.
If you really want the old behavior, you can change it to
~{true=>:bool_col}.
* Model.use_transactions was added for setting whether model objects
should use transactions when destroying or saving records. Like
most Sequel options, it's settable on a global, per model, and
per object basis:
Sequel::Model.use_transactions = false
MyModel.use_transactions = true
my_model.use_transactions = false
You can also turn it on or off for specific save calls:
my_model.save(:transaction=>true)
* The Oracle adapter now supports schema parsing.
* When using Model.db=, all current dataset options are copied to
a new dataset created with the new db.
* Model::Errors#count was refactored to improve performance.
* Most exception classes that were located under Sequel::Error are
now located directly under Sequel. The old names are not
deprecated (unless mentioned above), but their use is now
discouraged. The exceptions have the same name except that
Sequel::Error::PoolTimeoutError changed to Sequel::PoolTimeout.
* Dataset#where now always affects the WHERE clause. Before, it
was just an alias of filter, so it modified the HAVING clause
if the dataset already had a HAVING clause.
* The optimization of Model.[] introduced in 2.11.0 broke on
databases that didn't support LIMIT. The optimization now works
on those databases.
* All of the the RDoc documentation was reviewed and many updates
were made, resulting in significantly improved documentation
quality.
* Model.def_dataset_method now works when the model doesn't have an
associated dataset, as it will add the method to a dataset
given to set_dataset in the future.
* Database#get and #select now take a block that is passed to
the dataset they create.
* You can disable the use of INSERT RETURNING in the shared
PostgreSQL adapter using disable_insert_returning. This is mostly
useful if you are inserting a large number of records.
* A bug relating to aliasing columns in the JDBC adapter has been
fixed.
* Sequel can now create and drop schema-qualified views.
* Performance of Dataset#destroy for model datasets was improved.
* The specs now run on Rspec 1.2.
* Internal dependence on the methods that Sequel adds to core
classes has been eliminated, any internal use of methods that
Sequel adds to the core classes is now considered a bug.
* A possible bug where Database#rename_table would not remove a
cached schema entry has been fixed.
* The Oracle and MySQL adapters now raise an error as soon as you
call distinct on a dataset, instead of waiting until the SQL is
generated.
Backwards Compatibility
----------------------
* Saving a newly inserted record in an after_create or after_save
hook is no longer broken. It broke in 2.10 as a side effect of
allowing the hook to check whether or not the record was a new
record. The code has been changed so that a @was_new instance
variable will be defined to true if the record was just created.
Similarly, instead of not modifying changed_columns until after
the after hooks run, a @columns_updated instance variable will
be available in the after hooks that is a hash of exactly what
attribute keys and values were used in the update.
These changes break compatibility with 2.11.0 and 2.10.0, but
restore compatibility with 2.9.0 and previous versions.
* PostgreSQL no longer uses savepoints for nested transactions by
default. If you want to use a savepoint, you have to pass the
:savepoint option to the transaction method. Using savepoints
by default broke expectations when a method raised Rollback to
rollback the transaction, and it only rolled back to the last
savepoint.
* The anonymous model classes created by Sequel::Model() are now
stored in Model::ANONYMOUS_MODEL_CLASSES instead of the @models
class instance variable of the main module.
* The mappings of adapter schemes to classes are now stored in
Sequel::ADAPTER_MAP instead of the Database @@adapters class
variable.
* Model instances no longer contain a reference to their class's
@db_schema.
* Database schema sql methods (e.g. alter_table_sql) are now private.
* Database#[] no longer accepts a block. It's not possible to call
it with a block in general usage, anyway.
* The Sequel::Schema::SQL module no longer exists, the methods it
included were placed directly in the Sequel::Database class.
* The Sequel::SQL::SpecificExpression class has been removed,
subclasses now inherit from Sequel::SQL::Expression.
* Sequel now requires its own files with an absolute path.
* The file hierarchy of the sequel library changed significantly.
---
### Doc Release Notes 2.2.0 (`doc/release_notes/2.2.0.txt`)
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
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 infinite 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, preferably
without the block (though it can be used inside a block as well).
This usually involves the following types of changes:
filter{:x == :y} => filter(:x => :y)
filter{:x << :y} => filter(:x => :y)
filter{:x && :y} => filter(:x & :y) # Don't forget about change
filter{:x || :y} => filter(:x | :y) # in operator precedence
filter{:x.like?('%blah%')} => filter(:x.like('%blah%'))
filter do => filter((:x > 1) & (:y < 2))
:x > 1
:y < 2
end
* Attempts to save an invalid Model instance will raise an error by
default. To revert to returning a nil value, use:
Sequel::Model.raise_on_save_failure = false # Global
Album.raise_on_save_failure = false # Class
album = Album.new
album.raise_on_save_failure = false # Instance
Note that before, save would return false where now it returns nil
if you disable raising on save failure.
* 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:
DB[:table].update(:column=>:column + 1)
* 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.
---
### Doc Release Notes 2.3.0 (`doc/release_notes/2.3.0.txt`)
JRuby and Ruby 1.9 Officially Supported
---------------------------------------
Sequel now officially supports JRuby 1.1.3 and Ruby 1.9 (svn revision
18194 at least). Using JRuby with the JDBC adapter, PostgreSQL,
MySQL, and SQLite now enjoy almost full support, though not
everything works the same as using the native adapter. Depending on
what you are doing, it may make sense to use postgres-pr on JRuby
instead of PostgreSQL-JDBC.
To use the new JDBC support, the database connection string you give
Sequel is now passed directly to JDBC, here are a few examples:
Sequel.connect('jdbc:postgresql://host/database?user=*&password=*')
Sequel.connect('jdbc:mysql://host/database?user=*&password=*')
Sequel.connect('jdbc:sqlite::memory:')
Sequel.connect('jdbc:sqlite:relative/path.db')
Sequel.connect('jdbc:sqlite:/absolute/path.db')
Single Gem
----------
Sequel is now distributed as a single gem named sequel, by combining
the previous sequel_core and sequel gems. You can still just
"require 'sequel_core'" if you don't want the model functionality.
Database Adapter Improvements
-----------------------------
* Dataset#empty? now works using the MySQL adapter.
* The Oracle adapter now works with a nonstandard database port.
* The JDBC adapter should load JDBC drivers automatically for
PostgreSQL, MySQL, SQLite, Oracle, and MSSQL. For PostgreSQL,
MySQL, and SQLite, the jdbc-* gem can be used, for the others, you
must have the correct .jar in your CLASSPATH.
* The PostgreSQL adapter no longer raises an error when inserting
records into a table without a primary key.
* Database#disconnect now works for the ADO adapter.
* The ADO adapter no longer raises an error if the dataset contains
no records.
* The ODBC adapter no longer errors when converting ::ODBC::Time
values.
Backwards Incompatible Changes
------------------------------
* Sequel::Worker has been removed. There are no known users, and the
specs caused problems on JRuby.
* Assigning an empty string to a non-string, non-blob model attribute
converts it to nil by default. You can use
"Model.typecast_empty_string_to_nil = false" to get the old
behavior. This should make web development with Sequel
significantly easier, hopefully at no expense to other uses.
* Database.uri_to_options is now a private class method.
* Model.create_table! now acts the same as Database.create_table!,
dropping the table unconditionally and then creating it. This was
done for consistency. If you are using Model.create_table! in
production code, you should change it to
"Model.create_table unless Model.table_exists?", otherwise you risk
wiping out your production data. I recommended you use the
migration feature instead of Model.set_schema, as that handles
altering existing tables.
Other Notable Changes
---------------------
* Using validates_length_of more than once on the same attribute with
different options without a tag no longer causes the first use to
be ignored. This was a side effect of the validation tags added
in 2.2.0.
* Other than the adapters, Sequel now has 100% code coverage (line
coverage).
* Model#set* methods now return self.
* An integration test suite was added, testing Sequel against a live
database with nothing mocked, which helped greatly when testing the
new support for JDBC adapters.
---
### Doc Release Notes 2.4.0 (`doc/release_notes/2.4.0.txt`)
Prepared Statements/Bound Variables
===================================
Sequel now supports prepared statements and bound variables. No
matter which database you are using, Sequel uses exactly the same API.
To specify placeholders, you use the :$placeholder syntax:
ds = DB[:items].filter(:name=>:$n)
To use a bound variable:
ds.call(:select, :n=>'Jim')
This will do the equivalent of selecting records that have the name
'Jim'. In addition to :select, you can use :first or :delete. There
is also support for bound variables when inserting or updating
records:
ds.call(:update, {:n=>'Jim', :new_n=>'Bob'}, :name=>:$new_n)
Which will update all records that have the name 'Jim' to have the
name 'Bob'.
Prepared statement support is very similar to bound variable support,
except that the statement is first prepared with a name:
ps = ds.prepare(:select, :select_by_name)
It is then called later with the bound arguments to use:
ps.call(:n=>'Jim')
DB.call(:select_by_name, :n=>'Jim') # same as above
For inserting or updating, the hash to use when inserting or updating
is given to prepare:
ps2 = ds.prepare(:update, :update_name, :name=>:$new_n)
ps2.call(:n=>'Jim', :new_n=>'Bob')
There is some level of native support for these features in the
PostgreSQL, MySQL, SQLite, and JDBC adapters. For other adapters,
support is emulated, but it shouldn't be too difficult to add native
support for them.
For more details see:
http://sequel.rubyforge.org/rdoc/files/doc/prepared_statements_rdoc.html
Read-Only Slave/Writable Master and Database Sharding
=====================================================
Sequel now has built in support for master/slave database
configurations, just by setting an option in Sequel.connect:
DB=Sequel.connect('postgres://master_server/database', \
:servers=>{:read_only=>{:host=>'slave_server'}})
That will use slave_server for SELECT queries and master_server for
other queries. It's fairly easy to use multiple slaves or even
multiple masters, examples are included in the link below.
Sharding support requires some code other than the database
configuration, but is still fairly simple. For example, to set up
a 16 shard configuration based on a hex character:
servers = {}
(('0'..'9').to_a + ('a'..'f').to_a).each do |hex|
servers[hex.to_sym] = {:host=>"hash_host_#{hex}"}
end
DB=Sequel.connect('postgres://hash_host/hashes', :servers=>servers)
To set which shard to use for a query, use the Dataset#server method:
DB[:hashes].server(:a).filter(:hash=>/31337/)
For more details see:
http://sequel.rubyforge.org/rdoc/files/doc/sharding_rdoc.html
Other Changes
=============
* The sequel.rubyforge.org website has a new design thanks to boof.
The online RDoc is now located at http://sequel.rubyforge.org/rdoc.
* Support was added for anonymous column names in the ADO adapter.
* Better MSSQL support in the ADO, ODBC, and JDBC adapters. The
odbc_mssql adapter has been removed. If you use MSSQL with ODBC,
please use the odbc adapter with a :db_type=>'mssql' option.
* The following Sequel::Error exception subclasses were removed:
InvalidExpression, InvalidFilter, InvalidJoinType, and WorkerStop.
* Documentation was added for the PostgreSQL, MySQL, SQLite, and
JDBC adapters.
* Various internal interfaces were refactored. For example, if you
use an adapter not included with Sequel, it probably won't work
until you update it to the new internal API.
* Many low level methods (such as Database#transaction), now take
an optional server argument to indicate which server to use.
* Model plugins that have a DatasetMethods module with non-public
methods no longer have Model methods created that call those
methods.
---
### Doc Release Notes 2.5.0 (`doc/release_notes/2.5.0.txt`)
New Features
------------
* The values that are used to insert/update records can now be
scoped similar to how filter expressions can be scoped.
set_defaults is used to set defaults which can be overridden,
and set_overrides is used to set defaults which cannot be
overridden:
DB[:t].set_defaults(:x=>1).insert_sql
# => INSERT INTO t (x) VALUES (1)
DB[:t].set_defaults(:x=>1).insert_sql(:x=>2)
# => INSERT INTO t (x) VALUES (2)
DB[:t].set_defaults(:x=>1).insert_sql(:y=>2)
# => INSERT INTO t (x, y) VALUES (1, 2)
DB[:t].set_overrides(:x=>1).insert_sql(:x=>2)
# => INSERT INTO t (x) VALUES (1)
The difference between set_defaults and set_overrides is that
with set_defaults, the last value takes precedence, while with
set_overrides, the first value takes precedence.
* The schema generators now support creating and altering tables
with composite primary and/or foreign keys:
DB.create_table(:items) do
integer :id
text :name
primary_key [:id, :name]
foreign_key [:id, :name], :other_table, \
:key=>[:item_id, :item_name]
end
DB.alter_table(:items) do
add_primary_key [:id, :name]
add_foreign_key [:id, :name], :other_table, \
:key=>[:item_id, :item_name]
end
* The AlterTableGenerator now supports unique constraints:
DB.alter_table(:items) do
add_unique_constraint [:aaa, :bbb, :ccc], :name => :con3
end
* The schema generators now support ON UPDATE (previously, they only
supported ON DELETE):
DB.create_table(:items) do
foreign_key :project_id, :projects, :on_update => :cascade
end
* When connecting to a PostgreSQL server version 8.2 and higher,
Sequel now uses the INSERT ... RETURNING ... syntax, which should
speed up row inserts on PostgreSQL. In addition, Sequel Models
use RETURNING * to speed up model object creation.
* You can now validate multiple attributes at once. This is useful
if the combination of two or more attribute values is important,
such as checking the uniqueness of multiple columns.
validates_uniqueness_of now supports this directly:
validates_uniqueness_of [:column1, :column2]
This protects against the database having multiple rows with the
same values for both :column1 and :column2. This is different
from:
validates_uniqueness_of :column1, :column2
Which checks that the value of column1 is unique in the table, and
that the value of column2 is unique in the table (which is much
more restrictive).
Other Improvements
------------------
* Dataset methods insert_sql, delete_sql, and update_sql respect the
:sql option, allowing you to do things such as:
ds = DB['INSERT INTO t (time) VALUES (CURRENT_TIMESTAMP)']
ds.insert
ds.insert
* The database adapters (at least MySQL, PostgreSQL, SQLite, and
JDBC) generally raise Sequel::DatabaseError for database problems,
making it easier to tell what is a true database error versus an
error raised by Sequel itself.
* Sequel uses the async features of ruby-pg so that the entire
interpreter is not blocked while waiting for the results of
queries.
* Sequel now supports the 2008.08.17 version of ruby-pg.
* MSSQL support has been improved when using the ODBC and ADO
adapters.
* Index names are quoted and creating or dropping indexes.
* Automatically generated column accessor methods no longer override
instance methods specified by plugins.
* Inserting a row with an already specified primary key inside a
transaction now works correctly when using PostgreSQL.
* before_save and before_update hooks now work as expected when using
save_changes.
* count and paginate now work correctly on graphed datasets.
Backwards Compatibility
-----------------------
* The SQLite adapter now raises Sequel::DatabaseError instead of
Sequel::Error::InvalidStatement whenever an SQLite3::Exception is
raised by the SQLite3 driver.
* Date and DateTime conversions now convert 2 digit years. To revert
to the previous behavior:
Sequel.convert_two_digit_years = false
Note that Ruby 1.8 and 1.9 handle Date parsing differently, so
there is no backwards compatibility change for Ruby 1.9. However,
this also means that the MM/DD/YY date syntax commonly used in the
United States is not always parsed correctly on Ruby 1.9, greatly
limiting the use of 2 digit year conversion.
* You can no longer abuse the SQL function syntax for specifying
database types. For example, you must change:
:type=>:varchar[255]
to:
:type=>:varchar, :size=>255
---
### Doc Release Notes 2.6.0 (`doc/release_notes/2.6.0.txt`)
New Features
------------
* Schema parsing was refactored, resulting in a huge speedup when
using MySQL. MySQL now uses the DESCRIBE statement instead of the
INFORMATION_SCHEMA. PostgreSQL now uses the pg_* system catalogs
instead of the INFORMATION schema.
* The schema information now includes the :primary_key field. Models
now use this field to automatically determine the primary key for
a table, so it no longer needs to be specified explicitly. Models
even handle the composite primary key case.
* The raise_on_typecast_failure switch was added, with it being true
by default (so no change in behavior). This allows the user to
silently ignore errors when typecasting fails, at the global, class,
and instance levels.
Sequel::Model.raise_on_typecast_failure = false # Global
Artist.raise_on_typecast_failure = true # Class
artist = Artist.new
artist.raise_on_typecast_failure = false # Instance
Album.raise_on_typecast_failure = true
Album.new(:numtracks=>'a') # => raises Sequel::Error::InvalidValue
Album.raise_on_typecast_failure = false
Album.new(:numtracks=>'a') # => #<Album @values={:numtracks=>"a"}>
* Associations' orders are now respected when eager loading via
eager_graph. Sequel will qualify the columns in the order with
the alias being used, so you can have overlapping columns when
eager loading multiple associations.
Artist.one_to_many :albums, :order=>:name
Album.one_to_many :tracks, :order=>:number
Artist.order(:artists__name).eager_graph(:albums=>:tracks).sql
# => ... ORDER BY artists.name, albums.name, tracks.number
* The support for CASE expressions has been enhanced by allowing the
use of an optional expression:
{1=>2}.case(0, :x)
# => CASE x WHEN 1 THEN 2 ELSE 0 END
[[:a, 1], [:b, 2], [:c, 3]].case(4, :y)
# => CASE y WHEN a THEN 1 WHEN b THEN 2 WHEN c THEN 3 ELSE 4 END
Previously, to get something equivalent to this, you had to do:
{{:x=>1}=>2}.case(0)
# => CASE WHEN (x = 1) THEN 2 ELSE 0 END
[[{:y=>:a}, 1], [{:y=>:b}, 2], [{:y=>:c}, 3]].case(4)
# => CASE WHEN (y = a) THEN 1 WHEN (y = b) THEN 2 WHEN (y = c)
THEN 3 ELSE 4 END
* You can now change the NULL/NOT NULL value of an existing column
using the set_column_allow_null method.
# Set NOT NULL
DB.alter_table(:artists){set_column_allow_null :name, false}
# Set NULL
DB.alter_table(:artists){set_column_allow_null :name, true}
* You can now get the schema information for a table in a non-public
schema in PostgreSQL using the implicit :schema__table syntax.
Before, the :schema option had to be given explicitly to
Database#schema. This allows models to get schema information for
tables outside the public schema.
* Transactions are now supported on MSSQL.
* Dataset#tables now returns all tables in the database for MySQL
databases accessed via JDBC.
* Database#drop_view can now drop multiple views at once.
Other Improvements
------------------
* The SQLite adapter now respects the Sequel.datetime_class option
for timestamp and datetime columns.
* Adding a unique constraint no longer explicitly creates a unique
index. If you want a unique index, use index :unique=>true.
* If no language is specified when creating a full text index on
PostgreSQL, the simple language is assumed.
* Errors when typecasting fails are now Sequel::Error::InvalidValue
instead of the more generic Sequel::Error.
* Specifying constraints now works correctly for all types of
arguments. Previously, it did not work unless a block or
interpolated string were used.
* Loading an association with the same name as a table in the FROM
clause no longer causes an error.
* When eagerly loading many_to_one associations where no objects have
an associated object, the negative lookup is now cached.
* String keys can now be used with Dataset#multi_insert, just like
they can be used for Dataset#insert.
* Dataset#join_table now generates the correct SQL when doing the
first join to a dataset where the first source is a dataset, when
an unqualified column is used in the conditions.
* Cascading associations after *_to_many associations can now be
eagerly loaded via eager_graph.
* Eagerly loading *_to_many associations that are cascaded behind a
many_to_one association now have their duplicates removed if a
cartesian product join is done.
* The SQLite adapter now uses string literals in all of the AS
clauses. While the SQL standard specifies that identifiers should
be used, SQLite documentation explicitly states that string
literals are expected (though it generally works with identifiers
by converting them implicitly).
* Database methods that modify the schema now remove the cached
schema entry.
* The hash keys that Database#schema returns when no table is
requested are now always supposed to be symbols.
* The generation of SQL for composite foreign keys on MySQL has been
fixed.
* A schema.rdoc file was added to the documentation explaining the
various parts of Sequel related to schema generation and
modification and how they interact
(http://sequel.rubyforge.org/rdoc/files/doc/schema_rdoc.html).
* The RDoc template for the website was changed from the default
template to the hanna template.
Backwards Compatibility
-----------------------
* The :numeric_precision and :max_chars schema entries have been
removed. Use the :db_type entry to determine this information,
if available.
* The SQLite adapter used to always return Time instances for
timestamp types, even if Sequel.datetime_class was DateTime. For
datetime types it always returned a DateTime instance. It
now returns an instance of Sequel.datetime_class in both cases.
* It's possible that the including of associations' orders when eager
loading via eager_graph could cause problems. You can use the
:order_eager_graph=>false option to not use the :order option when
eager loading via :eager_graph.
* There were small changes in SQL creation where the AS keyword is
now used explicitly. These should have no effect, but could break
tests for explicit SQL.
---
### Doc Release Notes 2.7.0 (`doc/release_notes/2.7.0.txt`)
Performance Optimizations
-------------------------
* Fetching a large number of records with the PostgreSQL adapter is
significantly faster (up to 3-4 times faster than before).
* Instantiating model objects has been made much faster, as many
options (such as raise_on_save_failure) are now lazily loaded, and
hook methods are now much faster if no hooks have been defined for
that type of hook.
New Association Options
-----------------------
* The :eager_grapher option has been added allowing you to supply
your own block to implement eager loading via eager_graph.
* many_to_one and one_to_many associations now have a :primary_key
option, specifying the name of the column that the :key option
references.
* many_to_many associations now have :left_primary_key and
:right_primary_key options, specifying the columns that :left_key
and :right_key reference, respectively.
* many_to_many associations now have a :uniq option, that adds an
:after_load callback that makes the returned array of objects
unique.
Other New Features
------------------
* Dataset#set_graph_aliases now allows you to supply a third argument
for each column you want graph into the dataset, allowing you to use
arbitrary SQL expressions that are graphed into the correct table:
ds.set_graph_aliases!(:a=>[:b, :c], :d=>[:e, :f, 42])
# SELECT b.c AS a, 42 AS d FROM ...
ds.first # => {:b=>{:c=>?}, :e=>{:f=>42}}
* Dataset#add_graph_aliases was added, that adds additional graph
aliases instead of replacing the existing ones (as
#set_graph_aliases does). It's basically the equivalent of
select_more for graphs.
* Dataset#join_table changed it's final argument from a symbol
specifying a table name to an option hash (with backwards
compatibility kept), and adds support for a :implicit_qualifier
option, which it uses instead of the last joined table to
qualify columns.
* Association's :after_load callbacks are now called when eager
loading via eager (but not when eager loading via eager_graph).
* Any expression can now be used as the argument to Symbol#like,
which means that you can pattern match columns to other columns.
Before, it always transformed the argument to a string.
:a.like(:b)
# 2.6.0: a LIKE 'b'
# 2.7.0: a LIKE b
* Array#sql_array was added, allowing you to specify that an array
in ruby be treated like an array in SQL. This is true anyway,
except for arrays of all two pairs, which are treated like hashes,
for specifying multiple conditions with the same key:
DB[:foo].filter([:a,:b] => [[1,2],[3,4]].sql_array)
# => SELECT * FROM foo WHERE ((a, b) IN ((1, 2), (3, 4)))
* ComplexExpression#== and #sql? were added, allowing for easier
testing.
* Full text searching on PostgreSQL now joins multiple columns with
a space, to prevent joining border words, and it works when there
is a match in one column but the other column is NULL.
Other Improvements
------------------
* Instance methods added by creating associations are added to an
anonymous module included by the class, so they can be overridden
in the class while still allowing the use of super to get the
default behavior (this is similar to column accessor methods).
* Many improvements were added to support using multiple schemas in
PostgreSQL.
* Model::Validation::Errors objects are now more compatible with
Rails, by adding a #count method and making #on return nil if there
are no error messages for that attribute.
* Serialized columns in models are no longer typecast.
* Associations are now inherited when a model class is subclassed.
* Many improvements were made that should make adding custom
association types easier.
* A corner case in eager_graph where the wrong table name would be
used to qualify a column name has been fixed.
* Dataset's cached column information is no longer modified if #each
is called with an option that modifies the columns.
* You should now be able to connect to Oracle via the JDBC adapter,
and with the same support it has when using the oracle adapter.
* Model.association_reflections is now a public methods, so you can
grab a hash of all association reflections at once (keyed by
association name symbol).
* The :encoding/:charset option now works in the PostgreSQL adapter
if the postgres-pr driver is used.
* The numeric(x,y) type is now interpreted as decimal.
Backwards Compatibility
----------------------
* The first argument to Model#initialize must be a hash, you can no
longer use nil. For example, the following code will break if
:album is not in params:
Album.new(params[:album])
Additionally, Model#initialize does not call the block if the
second argument is true.
* The Sequel::Model.lazy_load_schema setting was removed. It should
no longer be necessary now that schema loading is relatively speedy,
and schemas can be loaded at startup and cached.
* The PostgreSQL adapter will default to using a unix socket in /tmp
if no host is specified. Before, a TCP/IP socket to localhost was
used if no host was specified. This change makes Sequel operate
similarly to the PostgreSQL command line tools.
* The ASSOCIATION_TYPES constant has changed from an array to a hash
and it has been moved. The RECIPROCAL_ASSOCIATIONS constant has
been removed. This is unlikely to matter unless you were using
custom association types.
* The PostgreSQL adapter now sets the PostgreSQL DateStyle, in order
to implement an optimization. To turn this off, set
Sequel::Postgres.use_iso_date_format = false.
* When using the PostgreSQL adapter, in many places the schema is
specified explicitly. If you do not specify a schema, a default
one is used (public by default). If you use a schema other than
public for your work, use Database#default_schema= to set it. For
any table outside of the default schema, you should specify the
schema explicitly, even if it is in the PostgreSQL search_path.
* Model::Validation::Errors#on now returns nil instead of [] if there
are no errors for an attribute.
* Hooks added to a superclass after a subclass has been created no
longer have an effect on the subclass.
* The Postgres.string_to_bool method has been removed.
* PostgreSQL full text searching now always defaults to using the
simple dictionary. If you want to use another dictionary, it must
be specified explicitly, both when searching and when creating a
full text index.
---
### Doc Release Notes 2.8.0 (`doc/release_notes/2.8.0.txt`)
New Features
------------
* Sequel now supports database stored procedures similar to its
support for prepared statements. The API is as follows:
DB[:table].call_sproc(:select, :mysp, 'param1', 'param2')
# or
sp = DB[:table].prepare_sproc(:select, :mysp)
sp.call('param1', 'param2')
sp.call('param3', 'param4')
This works with Model datasets as well, allowing them to return
model objects:
Album.call_sproc(:select, :new_albums)
#=> [#<Album ...>, #<Album ...>]
You can call a stored procedure directly on the Database object
if you want to, but the results and API are adapter dependent,
and you definitely shouldn't do it if the stored procedure returns
rows:
DB.call_sproc(:mysp, :args=>['param1', 'param2'])
Currently, the MySQL and JDBC adapters support stored procedures.
Other adapters may support them in a future version.
* The connection pool code can now remove connections if the
adapter raises a Sequel::DatabaseDisconnectError indicating that
the connection has been lost. When a query is attempted and
the adapter raises this error, the connection pool removes the
connection from the pool, and reraises the error. The Oracle and
PostgreSQL adapters currently support this, and other adapters may
support it in a future version.
* Whether to upcase or quote identifiers can now be set separately.
Previously, upcasing was done when quoting except when using SQLite,
PostgreSQL, or MySQL. Now, you can turn upcasing off while still
quoting. This may be necessary if you are using a MSSQL database
that has lower case table names that conflict with reserved words.
It also allows you to uppercase identifiers when using SQLite,
PostgreSQL, or MySQL, which may be beneficial in certain cases.
To turn upcasing on or off:
# Global
Sequel.upcase_identifiers = true
# Database
DB = Sequel.connect("postgres://...", :upcase_identifiers=>true)
DB.upcase_identifiers = false
# Dataset
ds = DB[:items]
ds.upcase_identifiers = true
* Options are now supported when altering a columns type:
DB.alter_table(:items) do
set_column_type :score, :integer, :unsigned=>true
set_column_type :score, :varchar, :size=>30
set_column_type :score, :enum, :elements=>['a', 'b']
end
* Standard conforming strings are now turned on by default in the
PostgreSQL adapter. This makes PostgreSQL not interpret backslash
escapes. This is the PostgreSQL recommended setting, which will be
the default setting in a future version of PostgreSQL. If you
don't want for force the use of standard strings, use:
Sequel::Postgres.force_standard_strings = false
You need to do that after you call Sequel.connect but before you
use the database for anything, since that setting is set on
initial connection.
* Sequel now raises an error if you attempt to use EXCEPT [ALL] or
INTERSECT [ALL] on a database that doesn't support it.
* Sequel now raises an error if you attempt to use DISTINCT ON with
MySQL or Oracle, which don't support it.
* A subadapter for the Progress RDBMS was added to the ODBC adapter.
To connect to a Progress database, use the :db_type=>'progress'
option. This adapter targets Progress 9.
* The ODBC adapter now supports transactions.
* The MSSQL shared adapter now supports multi_insert (for inserting
multiple rows at once), and unicode string literals.
Other Improvements
------------------
* There were many improvements related to using schemas in databases.
Using schema-qualified tables should work in most if not all cases
now. Model associations, getting the schema, joins, and many other
parts of Sequel were modified to allow the use of schema-qualifed
tables.
* You can now use literal strings with placeholders as well as
subselects when using prepared statements. For example, the
following all work now:
DB[:items].filter("id = ?", :$i).call(:select, :i=>1)
DB[:items].filter(:id=>DB[:items].select(:id)\
.filter(:id=>:$i)).call(:select, :i=>1)
DB["SELECT * FROM items WHERE id = ?", :$i].call(:select, :i=>1)
* Model#initialize received a few more micro-optimizations.
* Model#refresh now clears the changed columns as well as the
associations.
* You can now drop columns inside a transaction when using SQLite.
* You can now submit multiple SQL queries at once in the MySQL
adapter:
DB['SELECT 1; SELECT 2'].all
#=> [{:"1"=>1, :"2"=>2}]
This may fix issues if you've seen a MySQL "commands out of sync"
message. Note that this doesn't work if you are connecting to
MySQL via JDBC.
* You can now use AliasedExpressions directly in table names given
to join_table:
DB.from(:i.as(:j)).join(:k.as(:l), :a=>:b)
#=> ... FROM i AS j INNER JOIN k AS l ON (l.a = j.b)
* Database#rename_table once again works on PostgreSQL. It was
broken in 2.7.0.
* The interval type is now treated as it's own type. It was
previously treated as an integer type.
* Subselects are now aliased correctly when using Oracle.
* UNION, INTERSECT, and EXCEPT statements now appear before ORDER
and LIMIT on most databases. If you use these constructs, please
test and make sure that they work correctly with your database.
* SQL EXCEPT clause now works on Oracle, which uses MINUS instead.
* Dataset#exists now returns a LiteralString, to make it easier to
use.
* The Sequel.odbc_mssql method was removed, as the odbc_mssql adapter
was removed in a previous version. Instead, use:
Sequel.odbc(..., :db_type=>'mssql')
Backwards Compatibility
----------------------
* The hash returned by Database#schema when no table name is provided
uses quoted strings instead of symbols as keys. The hash has a
default proc, so using the symbol will return the same value as
before, but if you use each to iterate through the hash, the keys
will be different. This was necessary to handle schema-qualified
tables.
* Database#table_exists? no longer checks the output of
Database#tables. If the table exists in the schema, it returns
true, otherwise, it does a query. This was necessary because
table_exists? accepts multiple formats for table names and
Database#tables is an array of symbols.
* When getting the schema on PostgreSQL, the default schema is now
used even if the :schema=>nil option is used.
---
### Doc Release Notes 2.9.0 (`doc/release_notes/2.9.0.txt`)
New Features
------------
* Compound SQL statement (i.e. UNION, EXCEPT, and INTERSECT) support
is much improved. Chaining compound statement calls now longer
wipes out previous compound statements calls of the same type.
Also, the ordering of the compound statements is no longer fixed
per adapter, it now reflects the order they were called on the
object. For example, the following now work as expected:
ds1.union(ds2).union(ds3)
ds1.except(ds2).except(ds3)
ds1.intersect(ds2).intersect(ds3)
ds1.union(ds2).except(ds3)
ds1.except(ds2).intersect(ds3)
ds1.intersect(ds2).union(ds3)
* Exception classes ValidationFailure and BeforeHookFailure were
added so it is easier to catch a failed validation. These are
both subclasses of Sequel::Error, so there shouldn't be any
backwards compatibility issues. Error messages are also improved,
as the ValidationFailure message is a string containing all
validation failures and the BeforeHookFailure message contains
which hook type caused the failure (i.e. before_save,
before_create, or before_validation).
* The sequel command line tool now has a -L option to load
all files in the given directory. This is mainly useful for
loading a directory of model files. The files are loaded
after the database connection is set up.
* Methods to create and drop database functions, triggers, and
procedural languages were added to the PostgreSQL adapter.
Other Improvements
------------------
* Database#schema now raises an error if you pass a table that
doesn't exist. Before, some adapters would return an empty schema.
The bigger problem with this is that it made table_exists? return
the wrong value, since it looks at the Database's schema.
Generally, this bug would show up in the following code:
class Blah < Sequel::Model
end
Blah.table_exists? # True even if blahs is not a table
* AlterTableGenerator#add_foreign_key now works for MySQL.
* Error messages in model association methods that add/remove an
associated object are now more descriptive.
* Dataset#destroy for model datasets now works with databases that
can't handle nested queries. However, it now loads all model
objects being destroyed before attempting to destroy any of them.
* Dataset#count now works correctly for compound SQL statements
(i.e. UNION, EXCEPT, and INTERSECT).
* BigDecimal NaN and (+/-)Infinity values are now literalized
correctly. Database support for this is hit or miss. Sqlite will
work correctly, PostgreSQL raises an error if you try to store an
infinite value in a numeric column (though it works for float
columns), and MySQL converts all three to 0.
* The SQLite adapter no longer loses primary key information when
dropping columns.
* The SQLite adapter now supports dropping indices.
* A bug in the MSSQL adapter's literalization of LiteralStrings has
been fixed.
* The literalization of blobs on PostgreSQL (bytea columns) has been
fixed.
* Sequel now raises an error if you attempt to subclass Sequel::Model
before setting up a database connection.
* The native postgresql adapter has been changed to only log client
messages of level WARNING by default. You can modify this via:
Sequel::Postgres.client_min_messages = nil # Use Server Default
Sequel::Postgres.client_min_messages = :notice # Use NOTICE level
* Model#inspect now calls Model#inspect_values for easier
overloading.
Backwards Compatibility
----------------------
* The API to Model#save_failure (a private method) was changed to
remove the second argument.
* SQLite columns with type numeric, decimal, or money are now
returned as BigDecimal values. Before, they were probably returned
as strings.
---
### Doc Release Notes 3.0.0 (`doc/release_notes/3.0.0.txt`)
Deprecated Methods/Features Removed
-----------------------------------
Methods and features that were deprecated in 2.12.0 have been removed
in 3.0.0. Many features were moved into plugins or extensions, so in
many cases you just need to require an extension or use Model.plugin
and not make any changes to your code. See the 2.12.0 release notes
for the list of methods/features deprecated in 2.12.0.
If you are upgrading from a previous 2.x release, please upgrade to
2.12.0 first, fix your code to remove all deprecation warnings, and
then upgrade to 3.0.0.
New Adapter
-----------
* Sequel now has an Amalgalite adapter. Amalgalite is a ruby
extension that embeds SQLite without requiring a separate SQLite
installation. The adapter is functionality complete but
significantly slower than the native SQLite adapter.
New Features
------------
* The JDBC, PostgreSQL, MySQL, and SQLite adapters all now have a
Database#indexes method that returns indexes for a given table:
DB.indexes(:songs)
=> {:songs_name_index=>{:unique=>true, :columns=>[:name]},
:songs_lyricid_index=>{:unique=>false, :columns=>[:lyricid]}}
* A schema_dumper extension was added to Sequel. It supports dumping
the schema of a table (including indexes) as a string that can be
evaluated in the context of a Database object to create the table.
It also supports dumping all tables in the database as a string
containing a Migration subclass that will rebuild the database.
require 'sequel/extensions/schema_dumper'
DB.dump_table_schema(:table)
DB.dump_schema_migration
DB.dump_schema_migration(:same_db=>true)
DB.dump_schema_migration(:indexes=>false)
DB.dump_indexes_migration
The :same_db option causes Sequel to not translate column types
to generic column types. By default, the migration created will
use generic types so it will run on other databases. However, if
you only want to support a single database, using the :same_db
option will make the migration use the exact database type parsed
from the database.
The :indexes=>false option causes indexes not be included in the
migration. The dump_indexes_migration can be used to create a
separate migration with the indexes. This can be useful if you
plan on loading a lot of data right after creating the tables,
since it is faster to add indexes after the data has been added.
* Using options with the generic database types is now supported to
a limited extent. For example, the following code now works:
DB.create_table(:table) do
String :a, :size=>50 # varchar(50)
String :b, :text=>true # text
String :c, :fixed=>true, :size=>30 # char(30)
Time :ts # timestamp
Time :t, :only_time=>true # time
end
* Using Dataset#filter and related methods with multiple arguments
now works much more intuitively:
# 2.12.0
dataset.filter(:a, :b=>1) # a IS NULL AND (b = 1) IS NULL
# 3.0.0
dataset.filter(:a, :b=>1) # a AND b = 1
* You can now create temporary tables by passing the :temp=>true
option to Database#create_table.
* The Oracle shared adapter now supports emulation of
autoincrementing primary keys by creating a sequence and a trigger,
similar to how the Firebird adapter works.
* The Database#database_type method was added that returns a symbol
specifying the database type being used. This can be different
than Database.adapter_scheme if you are using an adapter like
JDBC that allows connecting to multiple different types of
databases.
* Database#drop_index and related methods now support an options
hash that respects the :name option, so they can now be used to
drop an index that doesn't use the default index name.
* The PostgreSQL shared adapter now supports a
Database#reset_primary_key_sequence method to reset the
primary key sequence for a given table, based on code from
ActiveRecord.
* SQL::QualifiedIdentifiers can now be qualified, allowing you to do:
:column.qualify(:table).qualify(:schema)
* Using the :db_type=>'mssql' option with the DBI adapter will now
load the MSSQL support.
* The MySQL shared adapter now supports Dataset#full_text_sql, which
you can use in queries like the following:
ds.select(:table.*, ds.full_text_sql(:column, 'value').as(:ft))
Other Improvements
------------------
* Sequel will now release connections from the connection pool
automatically if they are held by a dead thread. This can happen
if you are using MRI 1.8 and you are heavily multithreaded or
you call Thread#exit! or similar method explicitly. Those methods
skip the execution of ensure blocks which normally release the
connections when the threads exit.
* Model#save will now always use the same server when refreshing data
after an insert. This fixes an issue when Sequel's master/slave
database support is used with models.
* SQL Array references are now quoted correctly, so code like this
now works:
:table__column.sql_subscript(1)
* The PostgreSQL shared adapter now handles sequences that need to be
quoted correctly (previously these were quoted twice).
* String quoting on Oracle no longer doubles backslashes.
* Database#count now works correctly when used on MSSQL when using
an adapter that doesn't handle unnamed columns.
* Full text searching in the MySQL adapter now works correctly when
multiple search terms are used.
* Altering a column's name, type, default, or NULL/NOT NULL status
on MySQL now keeps other relevant column information. For example,
if you alter a column's type, it'll keep an existing default. This
functionality isn't complete, there may be other column information
that is lost.
* Fix creation of an index with a given type on MySQL, since MySQL's
documentation lies.
* The schema parser now handles decimal types with size specifiers,
fixing use on MySQL.
* Dataset#quote_identifier now works correctly when given an
SQL::Identifier. This allows you to do:
dataset.select{sum(hours).as(hours)}
Backwards Compatibility
-----------------------
* Sequel will now use instance_eval on all virtual row blocks without
an argument. This can lead to much nicer code:
dataset.filter{(number > 10) & (name > 'M')}
# WHERE number > 10 AND name > 'M'
2.12.0 raised a deprecation warning if you used a virtual row block
without an argument and you hadn't set
Sequel.virtual_row_instance_eval = true.
* Dataset#exclude now inverts the given argument, instead of negating
it. This only changes its behavior if it is called with a hash or
array of all two pairs that have more than one element.
# 2.12.0
dataset.exclude(:a=>1, :b=>1) # a != 1 AND b != 1
# 3.0.0
dataset.exclude(:a=>1, :b=>1) # a != 1 OR b != 1
This was done for consistency, since exclude would only negate a
hash if it was given an argument, it would invert the same hash
if you used a block:
# 2.12.0
dataset.exclude{{:a=>1, :b=>1}} # a != 1 OR b != 1
If you want the previous behavior,
change the code to the following:
dataset.filter({:a=>1, :b=>1}.sql_negate)
* As noted above, the methods/features deprecated in 2.12.0 were
removed.
* The private Dataset#select_*_sql methods now only take a single
argument, the SQL string being built.
* Dataset#from when called without arguments would previously cause an
error to be raised when the SQL string is generated. Now it causes
no FROM clause to be used, similar to how Dataset#select with no
arguments causes SELECT * to be used.
* The internals of the generic type support and the schema generators
were changed significantly, which could have some fallout in terms
of old migrations breaking if they used the generic types and were
relying on some undocumented behavior (such as using Integer as a
type with the :unsigned option).
* The Firebird adapter no longer translates the text database
specific type. Use the following instead:
String :column, :text=>true
* The MySQL shared adapter used to use the timestamp type for Time,
now it uses datetime. This is because the timestamp type cannot
represent everything that the ruby Time class can represent.
* Metaprogramming#metaattr_accessor and #metaattr_reader methods were
removed.
* Dataset#irregular_function_sql was removed.
---
### Doc Release Notes 3.1.0 (`doc/release_notes/3.1.0.txt`)
New Plugins
-----------
3 new plugins were added that implement features supported by
DataMapper: identity_map, tactical_eager_loading, and
lazy_attributes. These plugins don't add any real new features,
since you can do most of what they allow before simply by being
a little more explicit in your Sequel code. However, some people
prefer a less explicit approach that uses a bit more magic, and
now Sequel can accommodate them.
* The identity_map plugin allows you to create a 1-1
correspondence of model objects to database rows via a temporary
thread-local identity map. It makes the following statement true:
Sequel::Model.with_identity_map do
Album.filter{(id > 0) & (id < 2)}.first.object_id == \
Album.first(:id=>1).object_id
end
As the code above implies, you need to use the with_identity_map
method with a block to use the identity mapping feature.
By itself, identity maps don't offer much, but Sequel uses them
as a cache when looking up objects by primary key or looking up
many_to_one associated objects. Basically, it can be used as a
performance enhancer, and it also allows the support of the
lazy_attributes plugin.
The identity_map plugin is expected to be most useful in web
applications. With that in mind, here's a Rack middleware that
wraps each request in a with_identity_map call, so the
identity_map features are available inside the web app:
Sequel::Model.plugin :identity_map
class SequelIdentityMap
def initialize(app)
@app = app
end
def call(env)
Sequel::Model.with_identity_map{@app.call(env)}
end
end
* The tactical_eager_loading plugin allows you to eagerly load an
association for all models retrieved in the same group whenever
one of the models accesses the association:
# 2 queries total
Album.filter{id<100}.all do |a|
a.artists
end
In order for this correctly, you must use Dataset#all to load the
records, you cannot iterate over them via Dataset#each. This is
because eager loading requires that you have all records in
advance, and when using Dataset#each you cannot know about later
records in the dataset.
Before, you could just be explicit about the associations you
needed and make sure to eagerly load them using eager before
calling Dataset#all.
* The lazy_attributes plugin builds on the identity_map and
tactical_eager_loading plugins and allows you to create
attributes that are lazily loaded from the database:
Album.plugin :lazy_attributes, :review
This will remove the :review attribute from being selected by
default. If you try to access the attribute after it is selected,
it'll retrieve the value from the database. If the object was
retrieved with a group of other objects and an identity map is in
use, it'll retrieve the lazy attribute for the entire group of
objects at once, similar to the tactical_eager_loading plugin:
# 2 queries total
Sequel::Model.with_identity_map do
Album.filter{id<100}.all do |a|
a.review
end
end
Before, you could just set the default selected columns for a model
to not include the lazy attributes, and just use select_more to
add them to any query where the resulting model objects will
need the attributes.
* A many_through_many plugin was also added. This very powerful
plugin allows you to create associations to multiple objects through
multiple join tables. Here are some examples:
# Assume the following many to many associations:
Artist.many_to_many :albums
Album.many_to_many :tags
# Same as Artist.many_to_many :albums
Artist.many_through_many :albums,
[[:albums_artists, :artist_id, :album_id]]
# All tags associated to any album this artist is associated to
Artist.many_through_many :tags,
[[:albums_artists, :artist_id, :album_id],
[:albums, :id, :id],
[:albums_tags, :album_id, :tag_id]]
# All artists associated to any album this artist is associated to
Artist.many_through_many :artists,
[[:albums_artists, :artist_id, :album_id],
[:albums, :id, :id],
[:albums_artists, :album_id, :artist_id]]
# All albums by artists that are associated to any album this
# artist is associated to
Artist.many_through_many :artist_albums,
[[:albums_artists, :artist_id, :album_id],
[:albums, :id, :id],
[:albums_artists, :album_id, :artist_id],
[:artists, :id, :id],
[:albums_artists, :artist_id, :album_id]]
Basically, for each join table between this model and the
associated model, you use an array with a join table name, left key
name (key closer to this model), and right key name (key closer to
the associated model).
In usual Sequel fashion, this association type works not just
for single objects, but it can also be eagerly loaded via eager or
eager_graph. There are numerous additional configuration options,
please see the RDoc for details.
New bin/sequel Features
-----------------------
The bin/sequel command line tool now supports the following options:
* -C: Copies one database to another. You must specify two database
arguments. Works similar to Taps, copying the table schema, then
the table data, then creating the indexes.
* -d: Dump the schema of the database in the database-independent
migration format.
* -D: Dump the schema of the database in the database-specific
migration format.
* -h: Display the help
* -t: Output the full backtrace if an exception is raised
The bin/sequel tool is now better about checking which options can
be used together. It also now supports using the -L option multiple
times and having it load model files from multiple directory trees.
New Features
------------
* Dataset#qualify_to and #qualify_to_first_source were added. They
allow you to qualify unqualified columns in the current dataset
to the given table or the first source. This can be used to join
a dataset that has unqualified columns to a new table which has
columns with the same name.
For example, take this dataset:
ds = DB[:albums].select(:name).order(:name).filter(:id=>1)
# SELECT name FROM albums WHERE (id = 1) ORDER BY name
Let's say you want to join it to the artists table:
ds2 = ds.join(:artists, :id=>:artist_id)
# SELECT name FROM albums
# INNER JOIN artists ON (artists.id = albums.artist_id)
# WHERE (id = 1) ORDER BY name
That's going to give you an error, as the artists table already has
columns named id and name. This new feature allows you to do the
following:
ds2 = ds.qualify_to_first_source.join(:artists, :id=>:artist_id)
# SELECT albums.name FROM albums
# INNER JOIN artists ON (artists.id = albums.artist_id)
# WHERE (albums.id = 1) ORDER BY albums.name
By doing this, all unqualified columns are qualified, so you get
a usable query. This is expected to be most useful for users that
have a default order or filter on their models and want to join
the model to another table. Before you had to replace the filters,
selection, etc. manually, or use qualified columns by default even
though the weren't needed in most cases.
* Savepoints are now supported using SQLite and MySQL, assuming you
are using a database version that supports them. You need to
pass the :savepoint option to Database#transaction to use a
savepoint.
* Model plugins can now depend on other plugins, simply by calling
the Model.plugin method inside the plugin's apply method:
module LazyAttributes
def self.apply(model)
model.plugin :tactical_eager_loading
end
* Model.plugin now takes a block with is passed to the plugin's
apply and configure method (see Backwards Compatibility section for
more information on the configure method).
* You can see which plugins are loaded for a model by using
Model.plugins.
* You can use Sequel.extension method to load extensions:
Sequel.extension :pagination, :query
This will only load extensions that ship with Sequel, unlike the
Model.plugin method which will also load external plugins.
* You can now use Database#create_table? to create the table if it
doesn't already exist (a very common need, it seems). The schema
plugin now supports Model.create_table? as well.
* #sql_subscript is now an allowed method on most SQL expression
objects that Sequel generates. Also, arguments to #sql_subscript
can now be other expressions instead of just integers.
* Associations can now take a :cartesian_product_number option, which
can be used to tell Sequel whether to turn on duplicate object
detection when eagerly loading objects through eager_graph. This
number should be 0 if the association can never create multiple
rows for each row in the current table, 1 if it can create multiple
rows in the each row in the current table, and 2 if the association
itself causes a cartesian product.
* On MySQL, Dataset#insert_ignore now affects #insert as well as
multi_insert and import.
* Database#create_table now supports an :ignore_index_errors option,
and Database#add_index now supports an :ignore_errors option.
These are used by the schema_dumper when dumping an database
schema to be restored on another database type, since indexes
aren't usually required for proper operation and some indexes
can't be transferred.
* The ADO adapter now takes a :provider option, which can be used
to set the provider.
* The ADO adapter now takes a :command_timeout option, which tells
the connection how long to wait before giving up and raising an
exception.
* The Sequel.amalgalite adapter method was added. Like the
Sequel.sqlite method, you can call it with no arguments to get
an in memory database.
Other Improvements
------------------
* MySQL "commands out of sync" errors should no longer occur unless
you are nesting queries (calling Dataset#each inside Dataset#each).
A bug dating at least to 2007 and possibly since the initial
creation of the Sequel MySQL adapter was the cause. Before, SQL
that caused a result set that was sent using a method where Sequel
doesn't yield a result set would cause the "commands out of sync"
error on the following query. For example, the following code
would cause the error:
DB << "SHOW DATABASES"
If for some reason a "commands out of sync" error does occur,
Sequel will disconnect the connection from the connection pool,
so it won't continually stay in the pool and raise errors every
time it is used.
* The schema_dumper extension is much better about parsing defaults
from the database. It can now correctly parse most defaults on
MySQL, SQLite, and PostgreSQL databases. It no longer includes
defaults that it can't parse to a ruby object unless a database-
specific dump is requested.
* The schema_dumper extension now dumps tables in alphabetical order.
* Ordered and limited datasets are now handled correctly when using
union, intersect, and except. Also, union, intersect, and except
now always return a from_self dataset, so further limiting,
filtering, and ordering of them now works as expected.
* Dataset#graph now works correctly with a complex dataset without
having to use from_self. Before, code like the following didn't
do what was expected:
DB[:albums].
graph(DB[:artists].filter{name > 'M'}, :id=>:artist_id)
Before, the filter on DB[:artists] would be dropped. Now, Sequel
correctly uses a subselect.
* You can now specify serialization formats per column in the
serialization plugin, either by calling the plugin multiple
times or by using the new serialize_attributes method:
Album.plugin :serialization
Album.serialize_attributes :marshal, :review
Album.serialize_attributes :yaml, :name
Album.serialization_map #{:name=>:yaml, :review=>:marshal}
The public API for the serialization plugin is still backwards
compatible, but the internals have changed slightly to support
this new feature.
* You can now use eager_graph to eagerly load associations for models
that lack primary keys.
* The :eager_graph association option now works when lazily-loading
many_to_many associations.
* Dataset#add_graph_aliases now works correctly even if
set_graph_aliases hasn't been used.
* The PostgreSQL Database#tables method now assumes the public schema
if a schema is not given and there is no default_schema.
* The PostgreSQL Database#indexes method no longer returns partial
indexes or functional indexes.
* The MySQL Database#indexes method no longer returns indexes on
partial columns (prefix indexes).
* Default values for String :text=>true and File columns on MySQL
are ignored, since MySQL doesn't support them. They are not
ignored if you use text and blob, since then you are using the
database-specific syntax and Sequel doesn't do translation when
the database-specific syntax is used.
* On PostgreSQL, attempting the reset the primary key sequence for a
table without a primary key no longer causes an error.
* Using a placeholder string in an association's :condition option
now works correctly (e.g. :conditions=>['n = ?', 1])
* An error is no longer raised if you attempt to load a plugin that
has a DatasetMethods module but no public dataset methods.
* The check for dataset[n] where n is an integer was fixed. It now
raises an error inside of returning a limited dataset.
* On PostgreSQL, Dataset#insert with static SQL now works correctly.
* A reflection.rdoc file was added giving an overview of Sequel's
reflection support.
* The Migrator now works correctly with file names like
001_12312412_file_name.rb.
* The association code now requires the classes match when looking
for a reciprocal association.
* An unlikely threading bug (race condition) was possible when using
the validation_class_methods plugin. The plugin was refactored and
now uses a mutex to avoid the issue. One of the refactoring changes
makes it so that you can no longer use a class level validation
inside a Class.new block (since inherited isn't called until the
block finishes).
* The exception messages when Sequel.string_to_* fail have been fixed.
* The String :text=>true generic database type has been fixed when
using the Firebird adapter.
Backwards Compatibility
-----------------------
* A plugin's apply method is now only called the first time a plugin
is loaded. Plugins can now have a configure method that is called
every time the plugin is loaded, and is always called after the
instance methods, class methods, and dataset method submodules have
been added to the model. This is different from apply, which is
called before the submodules are loaded.
If you are a plugin author, please check your implementation to
make sure this doesn't cause problems for you. If you have
questions, please post on the Sequel mailing list.
This new plugin feature will make certain things a lot easier, and
it should be mostly backwards compatible. However, if a plugin
was previously expected to be loaded multiple times with the apply
method called each time, it will no longer work correctly.
* The plugin_opts methods defined now include multiple args in an
array if multiple args are given. Before, the plugin_opts methods
just returned the first argument.
* Database#table_exists? no longer checks the cached schema
information. By default, it will always do a database query
(unless overridden in an adapter). This shouldn't affect the
results, but if were using the method a lot and expecting it to
use cached information, it doesn't have the same performance
characteristics.
* The internal storage of the :select option for datasets have
changed. You can no longer use a hash as a way of aliasing
columns. Dataset#select now does the translation from the hash to
SQL::AliasedExpression instances. Basically, if you were using
Dataset#clone directly with a :select option with hashes for
aliasing, you should switch to using Dataset#select or changing
the hashes to AliasedExpressions yourself.
---
### Doc Release Notes 3.10.0 (`doc/release_notes/3.10.0.txt`)
New Features
------------
* A real one_to_one association was added to Sequel, replacing the
previous :one_to_one option of the one_to_many association.
This is a fully backwards incompatible change, any code that uses
the :one_to_one option of one_to_many will be broken in Sequel
3.10.0, as that option now raises an exception. Keeping backwards
compatibility was not possible, as even the name of the association
needs to be changed. Here are the code changes you need to make:
* The association definition needs to change from one_to_many to
one_to_one, with no :one_to_one option, and with the association
name changed from the plural form to the singular form:
# Before
Lyric.one_to_many :songs, :one_to_one=>true
# After
Lyric.one_to_one :song
* All usage of the association when eager loading or when getting
reflections need to use the new singular association name:
# Before
Lyric.eager(:songs).all
Lyric.eager_graph(:songs).all
Lyric.association_reflection(:songs)
# After
Lyric.eager(:song).all
Lyric.eager_graph(:song).all
Lyric.association_reflection(:song)
Any Sequel plugins or extensions that deal with the internals of
associations need to be made aware of the one_to_one association,
and how it is different than one_to_many's previous :one_to_one
option. Here are some internal changes that may affect you:
* one_to_one associations are now cached like many_to_one
associations instead of like one_to_many associations. So the
cache includes the associated object or nil, instead of an array.
Note that this change means that all custom :eager_loader options
for one_to_one associations need to change to use this new
caching scheme.
* The one_to_one association setter method is now handled similarly
to the many_to_one setter method, instead of using the internal
one_to_many association add method.
* Instead of raising an error when multiple rows are returned,
one_to_one associations now use limit(1) to only return a single
row.
There were some other fixes made during these changes:
* The one_to_one setter now accepts nil to disassociate the record.
Previously, this raised an error.
* If the one_to_one association already had a separate object
associated, and you assigned a different object in the setter
method, Sequel now disassociates the old object before
associating the new object, fixing some potential issues if there
is a UNIQUE constraint on the foreign key column.
* Using the many_to_one association setter where the reciprocal
association is a one_to_one association with a currently
different cached associated object no longer raises an exception.
* The nested_attributes and association_dependencies plugins
both now correctly handle one_to_one associations.
If you need any help migrating, please post on the Sequel Google
Group or ask in the #sequel IRC channel.
* Both many_to_one and one_to_one associations now use before_set
and after_set callbacks instead of trying to make the one_to_many
and many_to_many associations' (before|after)_(add|remove)
callbacks work.
This change makes the code simpler, makes writing callbacks easier,
and no longer requires Sequel to send a query to the database to
get the currently associated object in the many_to_one association
setter method (you can still do so manually in a before_set
callback if you want to).
* Dataset#for_update was added as a default dataset method.
Previously, it was only supported on PostgreSQL. It has been
tested to work on PostgreSQL, MySQL, SQLite (where it is ignored),
H2, and MSSQL.
* Dataset#lock_style was added as a backbone for Dataset#for_update,
but allowing you to specify custom lock styles. These can either
be symbols recognized by the adapters, or strings which are treated
as literal SQL.
* Model#lock! was added, which uses Dataset#for_update to lock model
rows for specific instances. Combined with the Dataset#for_update,
Sequel now has an equivalent to ActiveRecord's pessimistic locking
support.
* A composition plugin was added, given similar functionality as
ActiveRecord's composed_of.
The composition plugin allows you to easily define getter and
setter instance methods for a class where the backing data is
composed of other getters and decomposed to other setters.
A simple example of this is when you have a database table with
separate columns for year, month, and day, but where you want to
deal with Date objects in your ruby code. This can be handled
with:
Model.composition :date, :mapping=>[:year, :month, :day]
The :mapping option is optional, but if not used, you need define
custom composition and decomposition procs via the :composer and
:decomposer options.
Note that when using the composition object, you should not modify
the underlying columns if you are also instantiating the
composition, as otherwise the composition object values will
override any underlying columns when the object is saved.
* An rcte_tree plugin was added, which uses recursive common table
expressions to load all ancestors and descendants in a single
query. If your database supports recursive common table
expressions (PostgreSQL 8.4+, MSSQL 2005+, newer versions of
Firebird), using recursive common table expressions to load
all ancestors and descendants is significantly faster than storing
trees as nested sets and using nested set queries. Usage:
Model.plugin :rcte_tree
# Lazy loading
model = Model.first
model.parent
model.children
model.ancestors # Populates :parent association as well
model.descendants # Populates :children association as well
# Eager loading - also populates the :parent and children
# associations for all ancestors and descendants
Model.filter(:id=>[1, 2]).eager(:ancestors, :descendants).all
# Eager loading children and grandchildren
Model.filter(:id=>[1, 2]).eager(:descendants=>2).all
# Eager loading children, grandchildren, and great grandchildren
Model.filter(:id=>[1, 2]).eager(:descendants=>3).all
* Dataset#first_source_table was added, giving you the unaliased
version of the table for the first source.
* Add Sequel::BasicObject.remove_methods!, useful on ruby 1.8 if you
require other libraries after Sequel that add methods to Object.
For example, if YAML is required after sequel, then the following
will raise an error:
DB[:a].filter{x > y}
because YAML adds the y method to all objects. Now, you can call
Sequel::BasicObject.remove_methods!, which will remove those
methods from Sequel::BasicObject, allowing them to be used as
intended in the above DSL.
* Sequel associations now accept an :eager_loader_key option, which
can be useful for associations to specify the column to use for the
key_hash for custom :eager_loaders.
* A JDBC subadapter for the AS400 database was added.
Other Improvements
------------------
* The one_to_one setter method and the one_to_many and many_to_many
remove_all methods now apply the association options (such as
filters) on the appropriate dataset:
Artist.one_to_many :good_albums, :class=>:Album,
:conditions=>{:good=>true}
a = Artist[10]
a.remove_all_good_albums
# Before: WHERE artist_id = 10
# After: WHERE artist_id = 10 AND good IS TRUE
* Plugin loading now works correctly when the plugin module name
is the same name as an already defined top level constant. This
means that the active_model plugin should now work correctly if
you require active_model before loading the Sequel plugin.
* The nested_attributes plugin now preserves nested attributes for
*_to_one associations on validation failures.
* Transactions now work correctly on Oracle when using the JDBC
adapter.
* Dataset#limit once again works correctly on MSSQL 2000. It was
broken in Sequel 3.9.0.
* many_to_one associations now use limit(1) to ensure only one
record is returned. If you don't want this (because maybe you
are using the :eager_graph association option), you need to
set the :key option to nil and use a custom :dataset option.
* many_to_one and one_to_many associations now work correctly
with the association :eager option to eagerly load associations
specified by :eager when lazy loading the association.
* The typecast_on_load plugin now correctly handles
reloading/refreshing the object, both explicitly and implicitly
on object creation.
* The schema parser and dumper now return tinyint columns as
booleans when connecting to mysql using the do adapter, since
DataObjects now returns the columns as booleans.
* The schema dumper now deals better with unusual or database
specific primary key types when using the :same_db option.
* On ruby 1.8, Sequel::BasicObject now undefs private methods in
addition to public and protected methods. So the following
code now works as expected:
DB[:a].filter{x > p} # WHERE x > p
* Sequel.connect with a block now returns the value of the block:
max_price = Sequel.connect('sqlite://items.db') do |db|
db[:items].max(:price)
end
* MSSQL emulated offset support now works correctly when Sequel's
core extensions are not loaded.
* Sequel::BasicObject now works correctly on rubinius, and almost
all Sequel specs now pass on rubinius.
* The nested_attributes plugin now uses a better exception message
no matching associated object is found.
* Sequel now raises a more informative error if you attempt to use
the native sqlite adapter with the sqlite3 gem instead of the
sqlite3-ruby gem.
* Multiple complex expressions with the same operator are now
combined for simpler SQL:
DB[:a].filter(:a=>1, :b=>2).filter(:c=>3)
# Before: (((a = 1) AND (b = 2)) AND (c = 3))
# After: ((a = 1) AND (b = 2) AND (c = 3))
* The Sequel::Model dataset methods (class methods proxied to the
model's dataset) and the Sequel::Dataset mutation methods
(methods that have a ! counterpart to modify the object in place)
have both been updated to use new dataset methods added in recent
versions.
Backwards Compatibility
-----------------------
* The :one_to_one option of the one_to_many associations now raises
an exception. Please see the section above about the new real
one_to_one association.
* The change to apply the association options to the one_to_many and
many_to_many remove_all methods has the potential to break some
code that uses the remove_all method on associations that use
association options. This is especially true for many_to_many
associations, as filters in many_to_many associations will often
reference columns in the associated table, while the dataset
used in the remove_all method only contains the join table. Such
cases should be handled by manually overriding the _remove_all
association instance method in the class. It was determined that
it was better to issue possibly invalid queries than to issue
queries that make unexpected modifications.
* Dataset#group_and_count now longer orders the dataset by the count.
Since it returns a modified dataset, if you want to order the
dataset, just call order on the returned dataset.
* many_to_one associations now require a working :class option.
Previously, if you provided a custom :dataset option, a working
:class option was not required in some cases.
* The MSSQL shared adapter dataset methods switched from using
the :table_options internal option key to using the :lock internal
option key.
---
### Doc Release Notes 3.11.0 (`doc/release_notes/3.11.0.txt`)
= New Features
* A few new features were added to query logging. Sequel now
includes execution time when logging queries. Queries that
raise exceptions are now logged at ERROR level. You can now
set the log_warn_duration attribute on the Database instance
and queries that take longer than that will be logged at WARN
level. By using different log levels, you can now only log
queries that raise errors, or only log queries that take a long
time.
# The default - Log all successful queries at INFO level
DB.log_warn_duration = nil
# Log all successful queries at WARN level
DB.log_warn_duration = 0
# Log successful queries that take the database more than half a
# second at WARN level, other successful queries at INFO level
DB.log_warn_duration = 0.5
All adapters included with Sequel have been modified to support
the new logging API. The previous API is still available, so
any external adapters should still work, though switching to the
new logging API is encouraged.
* Sequel::Model now has a require_modification flag. If not set
explicitly, it is enabled by default if the dataset provides an
accurate number of rows matched by an update or delete statement.
When this setting is enabled, Sequel will raise an exception if
you attempt to update or delete a model object and it doesn't end
up affecting exactly one row. For example:
DB.create_table(:as){primary_key :id}
class A < Sequel::Model; end
a = A.create
# delete object from database
a.delete
a.require_modification = false
a.save # no error!
a.delete # no error!
a.require_modification = true
a.save # Sequel::NoExistingObject exception raised
a.delete # Sequel::NoExistingObject exception raised
Like many other Sequel::Model settings, this can be set on a
global, per class, and per instance level:
Sequel::Model.require_modification = false # global
Album.require_modification = true # class
album.require_modification = false # instance
* An instance_filters plugin was added to the list of built in
plugins, allowing you to add arbitrary filters when updating or
destroying an instance. This allows you to continue using models
when previously you would have had to drop down to using datasets
to get the desired behavior:
class Item < Sequel::Model
plugin :instance_filters
end
# These are two separate objects that represent the same
# database row.
i1 = Item.first(:id=>1, :delete_allowed=>false)
i2 = Item.first(:id=>1, :delete_allowed=>false)
# Add an instance filter to the object. This filter is in effect
# until the object is successfully updated or deleted.
i1.instance_filter(:delete_allowed=>true)
# Attempting to delete the object where the filter doesn't
# match any rows raises an error.
i1.delete # raises Sequel::Error
# The other object that represents the same row has no
# instance filters, and can be updated normally.
i2.update(:delete_allowed=>true)
# Even though the filter is now still in effect, since the
# database row has been updated to allow deleting,
# delete now works.
i1.delete
* An :after_connect database option is now supported. If provided,
the option value should be a proc that takes a single argument.
It will be called with the underlying connection object before
connection object is added to the connection pool, allowing you
to set per connection options in a thread-safe manner.
This is useful for customizations you want set on every connection
that Sequel doesn't already support. For example, on PostgreSQL
if you wanted to set the schema search_path on every connection:
DB = Sequel.postgres('dbname', :after_connect=>(proc do |conn|
conn.execute('SET search_path TO schema1,schema2')
end))
* A :test database option is now supported. If set to true, it
automatically calls test_connection to make sure a connection can
be made before returning a Database instance. For backwards
compatibility reasons, this is not set to true by default, but it
is possible that the default will change in a future version of
Sequel.
* The Dataset#select_append method was added, which always appends
to the existing selected columns. It operates identically to
select_more, except in the case that no columns are currently
selected:
ds = DB[:a]
# SELECT * FROM items
ds.select_more({:id=>DB[:b].select(:a_id)}.as(:in_b))
# SELECT id IN (SELECT a_id FROM b) AS in_b FROM a
ds.select_append({:id=>DB[:b].select(:a_id)}.as(:in_b))
# SELECT *, id IN (SELECT a_id FROM b) AS in_b FROM a
* The Dataset#provides_accurate_rows_matched? method was added which
allows you to see if the dataset will return the actual number of
rows matched/affected by an update or delete call.
* Sequel will now emulate DISTINCT ON support using GROUP BY on
MySQL. On MySQL, GROUP BY is similar to DISTINCT ON, except that
the order of returned rows is not deterministic.
* Support for connecting to Microsoft SQL Server using the JTDS JDBC
driver was added to the jdbc adapter.
* JDNI connection strings are now supported in the JDBC adapter.
* The JDBC adapter should now work in situations where driver
auto-loading has problems, just as when using Tomcat or Trinidad.
* Sequel's JDBC adapter schema parsing now supports a :scale option,
useful for numeric/decimal columns.
* Sequel's schema parsing on Microsoft SQL Server now supports
:column_size and :scale options.
* When connecting to SQLite, a Database#sqlite_version method is
available that gives you the SQLite version as an integer (e.g.
30613 for 3.6.13).
= Other Improvements
* Sequel no longer raises an error if you give Dataset#filter or
related method an empty argument such as {}, [], or ''. This allows
code such as the following to work:
h = {}
h[:name] = name if name
h[:number] = number if number
ds = ds.filter(h)
Before, this would raise an error if both name and number were
nil.
* Numeric and decimal columns with a 0 scale are now treated as
integer columns by the model typecasting code, since such columns
cannot store non-integer values.
* Calling Database#disconnect when using the single threaded
connection pool no longer raises an error if there is no current
connection.
* When using the :ignore_index_errors options to
Database#create_table, correctly swallow errors raised by Sequel
due to the adapter not supporting the given index type.
* The JDBC adapter no longer leaks ResultSets when retrieving
metadata.
* You can now connect to PostgreSQL when using ruby 1.9 with the
-Ku switch.
* When using the native MySQL adapter, only tinyint(1) columns are
now returned as booleans when using the convert_tinyint_to_bool
setting (the default). Previously, all tinyint columns would
be converted to booleans if the setting was enabled.
* Correctly handle inserts returning the autogenerated keys when
using MySQL JDBC Driver version 5.1.12 with the jdbc adapter.
* The native MySQL adapter now supports :config_default_group and
:config_local_infile options.
* When connecting to SQLite, you can provide the :auto_vacuum,
:foreign_keys, :synchronous, and :temp_store options for
making the appropriate PRAGMA setting on the database in a
thread-safe manner. The previous thread-unsafe PRAGMA setting
methods are available, but their use is discouraged.
* Sequel will not enable savepoints when connecting to SQLite
unless the version is 3.6.8 or greater.
* Using limit with distinct now works correctly on Microsoft SQL
Server.
* Database#rename_table now works correctly on Microsoft SQL Server.
* If you specify an explicit :provider when using the ADO adapter,
transactions will now work correctly. The default :provider uses
a new native connection for each query, so it cannot work with
transactions, or things like temporary tables.
* If you specify an explicit :provider when connecting to Microsoft
SQL Server using the ADO adapter (e.g. SQLNCLI10 or SQLNCLI),
Sequel is now able to provide an accurate number of rows modified
and deleted.
* Using set_column_allow_null with a decimal column with a precision
and scale now works correctly when connecting to Microsoft SQL
Server.
* You can now connect to Microsoft SQL Server using the dbi adapter.
* Sequel now recognizes the NUMBER database type as a synonym for
NUMERIC and DECIMAL, which may help some Oracle users.
* Transactions can now be rolled back correctly when connecting to
Oracle via JDBC.
* The active_model plugin now supports ActiveModel 3.0.0beta2.
* Many documentation improvements were made, including the addition
of a dataset basics guide, an association basics guide, an expanded
virtual row guide, and the separation of the Sequel::Dataset RDoc
page into sections. Additional, the RDoc class/method
documentation now contains links to the appropriate guides.
= Backwards Compatibility
* When connecting to SQLite, Sequel now automatically sets the
foreign_keys PRAGMA to true, which will make SQLite 3.6.19+ use
database enforced foreign key constraints. If you do not want
the database to enforce the foreign key constraints, you should
use the :foreign_keys=>false option when connecting to the
database.
* Sequel no longer creates #{plugin_name}_opts class, instance, and
dataset methods for each plugin loaded. No built-in plugin used
them, and I couldn't find an external plugin that did either.
* The Model#associations method is no longer available if the
default Associations plugin is not loaded due to the
SEQUEL_NO_ASSOCIATIONS constant or environment variable being set.
* DISTINCT ON support is turned off by default, and only enabled when
using PostgreSQL, since that appears to be the only database that
supports it. Previously, it was enabled by default and most common
adapters turned it off.
---
### Doc Release Notes 3.12.0 (`doc/release_notes/3.12.0.txt`)
= Migration Changes
* A TimestampMigrator has been added to Sequel, and is
automatically used if any migration has a version greater than
20000100. This migrator operates similarly to the default
ActiveRecord migrator, in that it allows missing migrations.
It differs from the ActiveRecord migrator in that it supports
migrations with the same timestamp/version as well as a wide
variety of timestamp formats (though the ActiveRecord default
of YYYYMMDDHHMMSS is recommended and should be used in
portable code).
Sequel still defaults to the old migrator, but you can use the
new one without making changes to your old migrations. Just
make sure your new migration starts with a version greater than
20000100, and Sequel will automatically convert the previous
schema table to the new format.
* A new migration DSL was added:
Sequel.migration do
up do
end
down do
end
end
The old style of using a Sequel::Migration subclass is still
supported, but it is recommended that new code use the new DSL.
* The default migrator also had significant issues fixed. First,
it now saves the migration version after each migration, instead
of after all migrations, which means Sequel won't attempt to
apply already applied migrations if there was previously an error
when applying multiple migrations at once on a database that
didn't support transactional schema modification.
Second, duplicate migration versions in the default migrator now
raise an exception, as do missing migration versions. Neither
should happen when using the default migrator, which requires
consecutive integer versions, similar to the old ActiveRecord
migrator.
* Execution times for migrations are now logged to the database's
loggers.
= New Plugins
* A sharding plugin has been added that allows model objects to
work well with sharded databases. When using it, model objects
know which shard they were retrieved from, so when you save
the object, it is saved back to that shard. The sharding plugin
also works with associations, so associated records are retrieved
from the same shard the main object was retrieved from. The
sharding plugin also works with both methods of eager loading, and
provides methods that you can use to create objects on specific
shards.
* An update_primary_key plugin has been added that allows Sequel
to work correctly if you modify the primary key of a model object.
This should not be necessary if you are using surrogate keys, but
if your database uses natural primary keys which can change, this
should be helpful.
* An association_pks plugin has been added that adds association_pks
and association_pks= methods to model objects for both one_to_many
and many_to_many associations. The association_pks method returns
an array of primary key values for the associated objects, and
the association_pks= method modifies the database to ensure that
the object is only associated to the objects specified by the
array of primary keys provided to it.
* A string_stripper plugin has been added that strips all strings
that are assigned to attribute values. This is useful for web
applications where you want to easily remove leading and trailing
whitespace in form entries before storing them in the database.
* A skip_create_refresh plugin has been added that skips the refresh
of after you save a new model object. On most databases, Sequel
refreshes the model object after inserting it in order to get
values for all of the columns. For performance reasons, you can
use this plugin to skip the refresh if it isn't necessary for you.
= Other New Features
* Sequel::Model#set_fields and update_fields were added. These
methods have a similar API to set_only and update_only, but they
operate differently. While set_only and update_only operate over
the hash, these methods operate over the array of fields,
so they don't raise errors if the hash contains fields not
in the array:
params = {:a=>1, :b=>2, :c=>3}
album = Album[1]
# raises Error because :a is not in the fields
album.set_only(params, [:b, :c])
# Just sets the value of album.b and album.c
album.set_fields(params, [:b, :c])
Other than handling entries in the hash that aren't in the array,
set_fields and update_fields also handle entries not in the hash
differently:
# Doesn't modify the object, since the hash is empty
album.set_only({}, [:b, :c])
# Sets album.b and album.c to nil, since they aren't in the hash
album.set_fields({}, [:b, :c])
* The :eager_loader association option has a new API, though the
previous API still works. Instead of accepting three arguments,
it can now accept a single hash argument, which will use the
:key_hash, :rows, and :association keys for the previous three
arguments. The hash will also contain a :self key whose value
is the dataset doing the eager load, which was not possible to
determine using the old API.
* Sequel::SQL::Expression#hash has been added so that the objects
are now safe to use as hash keys.
* A Dataset#order_prepend method has been added allowing you to
prepend to an existing order. This is useful if want to modify
a dataset's order such that it first orders by the columns you
provide, but for any rows where the columns you provide are
equal, uses the existing order to further order the dataset:
ds.order(:albums__name).order_prepend(:artists__name)
# ORDER BY artists.name, albums.name
* When creating foreign key columns, you can now use a :deferrable
option to set up a foreign key constraint that is not checked
until the end of the transaction:
DB.create_table(:albums) do
primary_key :id
String :name
foreign_key :artist_id, :artists, :deferrable=>true
end
* many_to_many associations now support a :join_table_block option
that is used by the add/remove/remove_all methods. It can modify
the dataset to ensure that certain columns are included when
inserting or to add a filter so that only certain records are
deleted. It's useful if you have a many_to_many association that
is filtered to only a subset of the matching rows in the join
table.
* The single_table_inheritance plugin now supports :model_map and
:key_map options to set up a custom mapping of column values to
model classes. For simple situations such as when you are mapping
integer values to certain classes, a :model_map hash is sufficient:
Employee.plugin :single_table_inheritance, :type_id,
:model_map=>{1=>:Staff, 2=>:Manager}
Here the :model_map keys are type_id column values, and the
:model_map values are symbols or strings specifying class names.
For more complex conditions, you can use a pair of procs:
Employee.plugin :single_table_inheritance, :type_name,
:model_map=>proc{|v| v.reverse},
:key_map=>proc{|klass| klass.name.reverse}
Here the type_name column is a string column holding the reverse
of the class's name.
* The single_table_inheritance plugin now correctly sets up subclass
filters for middle tables in a class hierarchy with more than 2
levels. For example, with this code:
class Employee < Sequel::Model; end
Employee.plugin :single_table_inheritance, :kind
class Manager < Employee; end
class Executive < Manager; end
Sequel previously would not return Executives if you used
Manager.all. It now correctly recognizes subclasses so that it
will return both Managers and Executives.
* Sequel::Model.qualified_primary_key_hash has been added, giving
you a hash that can be used for filtering. It is similar to
primary_key_hash, but it qualifies the keys with the model's
table. It's useful if you have joined the table to another table
that has columns with the same name, but you want to only look
for a single model object in that dataset.
* For consistency, you can now use Dataset#order_append as an alias
for order_more.
= Other Improvements
* Sequel now correctly removes schema entries when altering tables.
Previously, some adapters that had to query the existing schema
when altering tables resulted in the previous schema being cached.
* Sequel::Model::Errors#on now always returns nil if there are no
errors on the attribute. Previously, it would return an empty
array in certain cases. Additionally, Sequel::Model::Errors#empty?
now returns true if there are no errors, where it certain cases
it would return false even if there were no errors.
* The schema_dumper extension now works with tables specified as
Sequel::SQL::Identifiers.
* Sequel now recognizes the timestamp(N) with(out) time zone column
type.
* The lazy_attributes plugin no longer requires the core extensions
to work correctly.
* DatabaseDisconnectError support has been added to the ODBC adapter,
allowing Sequel to detect disconnects and remove the connection
from the connection pool.
* A leak of JDBC statement objects when using transactions was
fixed in the jdbc adapter.
* The jdbc adapter now gives a nicer error message if you use a
connection string that it doesn't recognize and there is an error
when connecting.
* Temporary table creation was fixed on Microsoft SQL Server, but
it is not recommended as it changes the name of the table. If
you use Microsoft SQL Server, you should prefix your temporary
table names with # and use the regular create table method.
* A large number of guides were added to Sequel to make it easier
for new and existing users to learn more about Sequel. The
following guides were added:
* Querying in Sequel
* Migration and Schema Modification
* Model Hooks
* Model Validations
* Sequel for SQL Users
* Sequel for ActiveRecord Users
* RDoc section support was added to Sequel::Database, making the
method documentation easier to read.
= Backwards Compatibility
* Sequel::Database now defines the indexes and tables methods, even
if the adapter does not implement them, similar to how connect
and execute are defined. Previously, you could use respond_to? to
check if the adapter supported them, now they raise
Sequel::NotImplemented if the database adapter does not implement
them.
* Sequel used to raise NotImplementedError in certain default
definitions of methods inside Sequel::Database and Sequel::Dataset,
when the methods were supposed to be overridden in subclasses.
Sequel now uses a Sequel::NotImplemented exception class for these
exceptions, which is a subclass of Sequel::Error.
* Sequel no longer applies all association options to the dataset
used to remove all many_to_many associated objects. You should
use the new :join_table_block option to get similar behavior if
you were filtering the many_to_many association based on columns
in the join table and you wanted remove_all to only remove the
related columns.
* Sequel now calls certain before and after hook actions in plugins
in a different order than before. This should not have an effect
unless you were relying on them being called in the previous order.
Now, when overriding before hooks in plugins, Sequel always does
actions before calling super, and when overriding after hooks in
plugins, Sequel always does actions after calling super.
* The hook_class_methods plugin no longer skips later after hooks if
a previous after hook returns false. That behavior now only occurs
for before hooks.
* Sequel now only removes primary key values when updating objects if
you are saving the entire object and you have not modified the
values of the primary keys. Previously, Sequel would remove
primary key values when updating even if you specified the primary
key column specifically or the primary key column was modified and
you used save_changes/update.
* Sequel now uses explicit methods instead of aliases for certain
methods. This should only affect you if for example you overrode
Dataset#group to do one thing and wanted Dataset#group_by to do
the default action. Now, Dataset#group_by, and methods like it, are
explicit methods that just call the methods they previously
aliased. This also means that if you were overriding Dataset#group
and explicitly aliasing group_by to it, you no longer need the
alias.
* The single_table_inheritance plugin now uses IN instead of = for
subclass filters. This could lead to poor performance if the
database has a very bad query planner.
* The private transaction_statement_object method was removed from
the JDBC adapter, and Sequel will no longer check for the presence
of the method in the transaction code.
* The Sequel::Migrator object is now a class instead of a module, and
has been pretty much rewritten. If you were using any methods of
it besides apply and run, they no longer work.
---
### Doc Release Notes 3.13.0 (`doc/release_notes/3.13.0.txt`)
= New Plugins
* A json_serializer plugin was added that allows you to serialize
model instances or datasets to JSON using to_json. It requires
the json library. The API was modeled on ActiveRecord's JSON
serialization support. You can use :only and :except options
to specify the columns included, :include to specify associations
to include, as well pass options to nested associations using a
hash. In addition to serializing to JSON, it also adds support
for parsing JSON to model objects via JSON.parse or #from_json.
* An xml_serializer plugin was added that allows you to serialize
model instances or datasets to XML. It requires the nokogiri
library. It has a similar API to the json_serializer plugin, using
to_xml instead of to_json, and the from_xml class method instead
of JSON.parse.
* A tree plugin was added that allows you to treat Sequel::Model
objects as being part of a tree. It provides similar features to
rcte_tree, but works on databases that don't support recursive
common table expressions. In addition to the standard parent
and children associations, it provides instance methods to get
the ancestors, descendants, and siblings of the given tree node,
and class methods to get the roots of the tree.
* A list plugin was added that allows you to treat Sequel::Model
objects as being part of a list. This adds instance methods to
get the next and prev items in the list, or to move the item
to a specific place in the list. You can specify that all rows
in the table belong to the same list, or specify arbitrary scopes
so that the same table can contain many separate lists.
= Other New Features
* Sequel is now compatible with Ruby 1.9.2pre3.
* Sequel now supports prepared transactions/two-phase commit on
PostgreSQL, MySQL, and H2. You can specify that you want to
use prepared transactions using the :prepare option which
should be some transaction id string:
DB.transaction(:prepare=>'some string') do ... end
Assuming that no exceptions are raised in the transaction block,
Sequel will prepare the transaction. You can then commit the
transaction later:
DB.commit_prepared_transaction('some string')
If you need to rollback the prepared transaction, you can do
so as well:
DB.rollback_prepared_transaction('some string')
* Sequel now supports customizable transaction isolation levels on
PostgreSQL, MySQL, and Microsoft SQL Server. You can specify the
transaction isolation level to use for any transaction using the
:isolation option with an :uncommitted, :committed, :repeatable,
or :serializable value:
DB.transaction(:isolation=>:serializable) do ... end
You can also set the default isolation level for transactions via
the transaction_isolation_level Database attribute:
DB.transaction_isolation_level = :committed
If you are connecting to Microsoft SQL Server, it is recommended
that you set a default transaction isolation level if you plan
on using this feature.
* You can specify a NULLS FIRST/LAST ordering by using the
:nulls=>:first/:last option to asc and desc:
Album.filter(:release_date.desc(:nulls=>:first),
:name.asc(:nulls=>:last))
# ORDER BY release_date DESC NULLS FIRST,
# name ASC NULLS LAST
This syntax is supported by PostgreSQL 8.3+, Firebird 1.5+,
Oracle, and probably some other databases as well, and makes it
possible for the user to specify whether NULL values should sort
before or after other values.
* Sequel::Model.find_or_create now accepts a block that is a yielded
a new model object to be created if an existing model object is
not found.
Node.find_or_create(:name=>'A'){|i| i.parent_id = 4}
* The :frame option for windows and window functions can now be a
string that is used literally in the SQL. This is necessary if you
want to specify a custom frame, such as one that uses a specific
number of rows preceding or following.
* Savepoints are now supported on H2.
* A :methods_module association option was added, allowing you to
specify the module into which association instance methods are
placed. By default, it uses the module containing the column
accessor methods.
= Other Improvements
* The :encoding option for the native MySQL adapter should now work
correctly in all cases. This fix was included in 3.12.1.
* Sequel now handles arrays of two element arrays automatically when
using them as the value of a filter hash:
DB[a].filter([:a, :b]=>[[1, 2], [3, 4]])
Previously, you had to call .sql_array on the array in order to
tell Sequel that it was a value list and not a conditions
specifier.
* Sequel no longer attempts to use class polymorphism in the
class_table_inheritance plugin if you don't specify a cti_key.
* When using the native SQLite adapter, prepared statements are now
cached per connection for increased performance. Previously,
Sequel prepared a new statement for every query.
* tinyint(1) columns are now handled as booleans when connecting to
MySQL via JDBC.
* On PostgreSQL, if no :schema option is provided for
Database#tables, #table_exists?, or #schema, and no default_schema
is used, assume all schemas except the default non-public ones.
Previously, it assumed the public schema for tables and
table_exists?, but did not assume any schema for #schema.
This fixes issues if you use table names that overlap with table
names in the information_schema, such as domains. It's still
recommended that you specify a default_schema if you are using a
schema other than public.
* Unsigned integers are now handled correctly in the schema dumper.
* Sequel::SQL::PlaceholderLiteralString is now a GenericExpression
subclass, allowing you to treat it like most other Sequel
expression objects:
'(a || ?)'.lit(:b).like('Test%')
# ((a || b) LIKE 'Test%')
* Sequel now supports the bitwise shift operators (<< and >>) on
Microsoft SQL Server by emulating them.
* Sequel now supports most bitwise operators (&, |, ^, <<, >>) on H2
by emulating them. The bitwise complement operator is not yet
supported.
* Sequel now logs the SQL queries that are sent when connecting to
MySQL.
* If a plugin cannot be loaded, Sequel now gives a more detailed
error message.
= Backwards Compatibility
* Array#sql_array and the Sequel::SQL::SQLArray class are now
considered deprecated. Use the Array#sql_value_list and the
Sequel::SQL::ValueList class instead. SQLArray is now just
an alias for ValueList, but it now is an Array subclass instead
of a Sequel::SQL::Expression subclass.
* Using the ruby bitwise xor operator (^) on PostgreSQL now uses
PostgreSQL's bitwise xor operator (#) instead of PostgreSQL's
exponentiation operator (^). If you want exponentiation, use
the power function.
* Using the ruby bitwise complement operator (~) on MySQL now returns
a signed integer instead of an unsigned integer, for better
compatibility with other databases.
* Using nil as a case expression value (the 2nd argument to Hash#case
and Array#case) will now use NULL as the case expression value,
instead of omitting the case expression value:
# 3.12.0
{1=>2}.case(0, nil)
# CASE WHEN 1 THEN 2 ELSE 0 END
# 3.13.0
{1=>2}.case(0, nil)
# CASE NULL WHEN 1 THEN 2 ELSE 0 END
In general, you would never use nil explicitly, but the new
behavior makes more sense if you have a variable that might be nil:
parent_id = Node[1].parent_id
{1=>2}.case(0, parent_id)
If parent_id IS NULL/nil, then previously Sequel would have
generated unexpected SQL. If you don't want a case expression
value to be used, do not pass a second argument to #case.
* Some internal transaction methods now take an optional options
hash, so if you have a custom adapter, you will need to make
changes.
* Some internal association methods now take an optional options
hash.
* Some Rakefile task names were modified in the name of consistency:
spec_coverage -> spec_cov
integration -> spec_integration
integration_cov -> spec_integration_cov
---
### Doc Release Notes 3.14.0 (`doc/release_notes/3.14.0.txt`)
= New Features
* Dataset#grep now accepts :all_patterns, :all_columns, and
:case_insensitive options. Previously, grep would use a case
sensitive search where it would match if any pattern matched any
column. These three options give you more control over how the
pattern matching will work:
dataset.grep([:a, :b], %w'%test% foo')
# WHERE ((a LIKE '%test%') OR (a LIKE 'foo')
# OR (b LIKE '%test%') OR (b LIKE 'foo'))
dataset.grep([:a, :b], %w'%foo% %bar%', :all_patterns=>true)
# WHERE (((a LIKE '%foo%') OR (b LIKE '%foo%'))
# AND ((a LIKE '%bar%') OR (b LIKE '%bar%')))
dataset.grep([:a, :b], %w'%foo% %bar%', :all_columns=>true)
# WHERE (((a LIKE '%foo%') OR (a LIKE '%bar%'))
# AND ((b LIKE '%foo%') OR (b LIKE '%bar%')))
dataset.grep([:a, :b], %w'%foo% %bar%',
:all_patterns=>true,:all_columns=>true)
# WHERE ((a LIKE '%foo%') AND (b LIKE '%foo%')
# AND (a LIKE '%bar%') AND (b LIKE '%bar%'))
dataset.grep([:a, :b], %w'%test% foo', :case_insensitive=>true)
# WHERE ((a ILIKE '%test%') OR (a ILIKE 'foo')
# OR (b ILIKE '%test%') OR (b ILIKE 'foo'))
* When using the schema plugin, you can now provide a block to the
create_table methods to set the schema and create the table
in the same call:
class Artist < Sequel::Model
create_table do
primary_key :id
String :name
end
end
* The tree plugin now accepts a :single_root option, which uses a
before_save hook to attempt to ensure that there is only a single
root in the tree. It also adds a Model.root method to get the
single root of the tree.
* The tree plugin now adds a Model#root? instance method to check
if the current node is a root of the tree.
* Model#save now takes a :raise_on_failure option which will
override the object's raise_on_save_failure setting. This makes
it easier to get the desired behavior (raise or just return false)
in library code without using a begin/ensure block.
* The Database#adapter_scheme instance method was added, which
operates the same as the class method.
* Sequel now handles the literalization of OCI8::CLOB objects in
the Oracle adapter.
= Other Improvements
* When using the timezone support, Sequel will now correctly load
times and datetimes in standard time when the current timezone is
in daylight time, or vice versa. Previously, if you tried to
to load a time or datetime in December when in July in a timezone
that used daylight time, it would be off by an hour.
* The rcte_tree plugin now works correctly when a :conditions option
is used.
* The single_table_inheritance plugin now works correctly when the
class discriminator column has the same name as an existing ruby
method (such as type).
* Database#each_server now works correctly when a connection string
is used to connect, instead of an options hash.
* Model#destroy now respects the object's use_transactions setting,
instead of always using a transaction.
* Model#exists? now uses a simpler and faster query.
* Sequel now handles the aggregate methods such as count and sum
correctly on Microsoft SQL Server when using an ordered dataset
with a clause such as DISTINCT or GROUP and without a limit.
* Sequel now handles rename_table correctly on Microsoft SQL Server
when using a case sensitive collation, or when qualifying the
table with a schema.
* Sequel now parses the schema correctly on Oracle when the same
table name is used in multiple schemas.
* Sequel now handles OCIInvalidHandle errors when disconnecting
in the Oracle adapter.
* Sequel now raises a Sequel::Error instead of an ArgumentError
if the current or target migration version does not exist.
* When a mismatched number of composite keys are used in
associations, Sequel now uses a more detailed error message.
* Significant improvements were made to the Dataset and Model
RDoc documentation.
= Backwards Compatibility
* Model#valid? now must accept an optional options hash.
* The Model#save_failure private method was renamed to
raise_hook_failure.
* The LOCAL_DATETIME_OFFSET_SECS and LOCAL_DATETIME_OFFSET constants
have been removed from the Sequel module.
* Sequel now uses obj.to_json instead of JSON.generate(obj). This
shouldn't affect backwards compatibility, but did fix a bug in
certain cases.
---
### Doc Release Notes 3.15.0 (`doc/release_notes/3.15.0.txt`)
= Performance Enhancements
* A mysql2 adapter was added to Sequel. It offers a large (2-6x)
performance increase over the standard mysql adapter. In order to
use it, you need to install mysql2, and change your connection
strings to use mysql2:// instead of mysql://.
* Support for sequel_pg was added to the native postgres adapter,
when pg is being used as the backend. sequel_pg also offers a
large (2-6x) performance increase over the default row fetching
code that the Sequel postgres adapter uses. In order to use it,
you just need to install sequel_pg, and the postgres adapter will
pick it up automatically.
* Mass assignment has been made about 10x faster by caching the
allowed setter methods in the model.
= Other Improvements
* The following construct is now safe to use in environments that
reload code without unloading existing constants:
class MyModel < Sequel::Model(DB[:table])
end
Previously, this would raise a superclass mismatch TypeError.
* Sequel now handles the case where both an implicit and an explicit
table alias are given to join_table, preferring the explicit alias.
This can happen if you are using models with aliased table names
and eager graphing them. Previously, this would result in invalid
SQL, with both aliases being used.
* You can use use an aliased table for the :join_table option
of a many_to_many association.
* The active_model plugin now supports the final release of
ActiveModel 3.0.0.
* Typecasting now works correctly for attributes loaded lazily
when using the lazy_attributes plugin.
* The class_table_inheritance plugin now works with non-integer
primary keys on SQLite.
* Temporary tables are now ignored when parsing the schema on
PostgreSQL.
* On MySQL, an :auto_increment key with a true value is added to
the Database#schema output hash if the related column is
auto incrementing.
* The mysql adapter now handles Mysql::Error exceptions raised when
disconnecting.
* On SQLite, emulated alter_table commands that require dropping
the table now preserve the foreign key information, if SQLite
foreign key support is enabled (it is by default).
* DSN-less connections now work correctly in more cases in the
ODBC adapter.
* A workaround has been added for a bug in the Microsoft SQL
Server JDBC Driver 3.0, involving it incorrectly returning a
smallint instead of a char type for the IS_AUTOINCREMENT
metadata value.
* An bug in the error handling when connecting to PostgreSQL using
the do (DataObjects) adapter has been fixed.
= Backwards Compatibility
* The caching of allowed mass assignment methods can result in the
incorrect exception class being raised if you manually undefine
instance setter methods in the model class. If you do this, you
need to clear the setter methods cache manually:
MyModel.clear_setter_methods_cache
---
### Doc Release Notes 3.16.0 (`doc/release_notes/3.16.0.txt`)
= New Adapter
* A swift adapter was added to Sequel. Swift is a relatively new
ruby database library, built on top of a relatively new backend
called dbic++. While not yet considered production ready, it is
very fast. The swift adapter is about 33% faster and 40% more
memory efficient for selects than the postgres adapter using pg
with sequel_pg, though it is slower and less memory efficient
for inserts and updates.
Sequel's swift adapter currently supports only PostgreSQL and
MySQL, but support for other databases will probably be added in
the future.
= Other Improvements
* Sequel now correctly literalizes DateTime objects on ruby 1.9 for
databases that support fractional seconds.
* The identity_map plugin now handles composite keys in many_to_one
associations.
* The rcte_tree plugin now works when the model's dataset does not
select all columns. This can happen when using the lazy_attributes
plugin on the same model.
* Sequel now supports INTERSECT and EXCEPT on Microsoft SQL Server
2005+.
* The Database#create_language method in the shared PostgreSQL
adapter now accepts a :replace option to replace the currently
loaded procedural language if it already exists. This option
is ignored for PostgreSQL versions before 9.0.
* The identity_map plugin now handles cases where the plugin is
loaded separately by two different models.
= Backwards Compatibility
* While not technically backwards compatibility related, it was
discovered that the identity_map plugin is incompatible with
the standard eager loading of many_to_many and many_through_many
associations. If you want to eagerly load those associations and
use the identity_map plugin, you should use eager_graph instead
of eager.
---
### Doc Release Notes 3.17.0 (`doc/release_notes/3.17.0.txt`)
= New Features
* You can now change the level at which Sequel logs SQL statements,
by calling Database#sql_log_level= with the method name symbol.
The default is still :info for backwards compatibility. Previously,
you had to use a proxy logger to get similar capability.
* You can now specify graph aliases where the alias would be the same
as the table column name using just the table name symbol, instead
having to repeat the alias as the second element of an array. More
clearly:
# < 3.17.0:
DB[:a].graph(:b, :a_id=>:id).
set_graph_aliases(:c=>[:a, :c], :d=>[:b, :d])
# >= 3.17.0:
DB[:a].graph(:b, :a_id=>:id).set_graph_aliases(:c=>:a, :d=>:b)
Both of these now yield the SQL:
SELECT a.c, b.d FROM a LEFT OUTER JOIN b ON (b.a_id = a.id)
* You should now be able to connect to MySQL over SSL in the native
MySQL adapter using the :sslca, :sslkey, and related options.
* Database#views and Database#view_exists? methods were added to the
Oracle adapter, allowing you to get a an array of view name symbols
and to check whether a given view exists.
= Other Improvements
* The nested_attributes plugin now avoids unnecessary update calls
when deleting associated objects, resulting in better performance.
* The optimistic_locking plugin now increments the lock column if no
other columns were modified but the Model#modified! was called. This
means it now works correctly with the nested_attributes plugin when
no changes to the main model object are made.
* The xml_serializer plugin can now round-trip nil values correctly.
Previously, nil values would be converted into empty strings. This
is accomplished by including a nil attribute in the xml tag.
* Database#each_server now works correctly when using the jdbc and do
adapters and a connection string without a separate :adapter option.
* You can now clone many_through_many associations.
* The default wait_timeout used by the mysql and mysql2 adapters was
decreased slightly so that it works correctly with MySQL database
servers that run on Windows.
* Many improvements were made to the AS400 jdbc subadapter.
* Many improvements were made to the swift adapter and subadapters.
* Dataset#ungraphed now removes any cached graph aliases set with
set_graph_aliases or add_graph_aliases.
---
### Doc Release Notes 3.18.0 (`doc/release_notes/3.18.0.txt`)
= New Features
* Reversible migration support has been added:
Sequel.migration do
change do
create_table(:artists) do
primary_key :id
String :name, :null=>false
end
end
end
The change block acts the same way as an up block, except that
it automatically creates a down block that reverses the changes.
So the above is equivalent to:
Sequel.migration do
up do
create_table(:artists) do
primary_key :id
String :name, :null=>false
end
end
down do
drop_table :artists
end
end
The following methods are supported in a change block:
* create_table
* add_column
* add_index
* rename_column
* rename_table
* alter_table (supporting the following methods):
* add_column
* add_constraint
* add_foreign_key (with a symbol, not an array)
* add_primary_key (with a symbol, not an array)
* add_index
* add_full_text_index
* add_spatial_index
* rename_column
Use of an other method in a change block will result in the
creation of a down block that raises an exception.
* A to_dot extension has been added that adds a Dataset#to_dot
method, which returns a string that can be used as input to
the graphviz dot program in order to create visualizations
of the dataset's abstract syntax tree. Examples:
* http://sequel.jeremyevans.net/images/to_dot_simple.gif
* http://sequel.jeremyevans.net/images/to_dot_complex.gif
Both the to_dot extension and reversible migrations support
were inspired by Aaron Patterson's recent work on ActiveRecord
and ARel.
* The user can now control how the connection pool handles attempts
to access shards that haven't been configured. The default is
still to assume the :default shard. However, you can specify a
different shard using the :servers_hash option when connecting
to the database:
DB = Sequel.connect(..., :servers_hash=>Hash.new(:some_shard))
You can also use this feature to raise an exception if an
unconfigured shard is used:
DB = Sequel.connect(..., :servers_hash=>Hash.new{raise ...})
* The mysql and mysql2 adapters now both support the :read_timeout
and :connect_timeout options. read_timeout is the timeout in
seconds for reading back results of a query, and connect_timeout
is the timeout in seconds before a connection attempt is abandoned.
= Other Improvements
* The json_serializer plugin will now typecast column values for
columns with unrestricted setter methods when parsing JSON into
model objects. It now also calls the getter method when creating
the JSON, instead of directly taking the values from the underlying
hash.
* When parsing the schema for a model with an aliased table name,
the unaliased table name is now used.
* The SQLite adapter has been updated to not rely on the native
type_translation support, since that will be removed in the next
major version of sqlite3-ruby. Sequel now implements it's own
type translation in the sqlite adapter, similarly to how the mysql
and postgres adapters handle type translation.
* On SQLite, when emulating natively unsupported schema methods such
as drop_column, Sequel will now attempt to recreate applicable
indexes on the underlying table.
* A more informative error message is now used when connecting fails
when using the jdbc adapter.
* method_missing is no longer removed from Sequel::BasicObject on
ruby 1.8. This should improve compatibility in some cases with
Rubinius.
= Backwards Compatibility
* On SQLite, Sequel no longer assumes that a plain integer in a
datetime or timestamp field represents a unix epoch time.
* Previously, saving a model object that used the instance_hooks
plugin removed all instance hooks. Now, only the applicable hooks
are removed. So if you save a new object, the update instance
hooks won't be removed. And if you save an existing object, delete
instance hooks won't be removed.
* The private Dataset#identifier_list method has been moved into the
SQLite adapter, since that is the only place it was used.
---
### Doc Release Notes 3.19.0 (`doc/release_notes/3.19.0.txt`)
= New Features
* The add_* association methods now accept a primary key, and
associates the receiver to the associated model object with that
primary key:
artist.add_album(42)
# equivalent to: artist.add_album(Album[42])
* The validation_class_methods plugin now has the ability to
reflect on validations:
Album.plugin :validation_class_methods
Album.validates_acceptance_of(:a)
Album.validation_reflections
# => {:a=>[[:acceptance, {:tag=>:acceptance, :allow_nil=>true,
:message=>"is not accepted", :accept=>"1"}]]}
= Other Improvements
* In the postgres, mysql, and sqlite adapters, typecasting now uses
methods instead of procs. Since methods aren't closures (while
procs are), this makes typecasting faster (up to 15%).
* When typecasting model column values, the classes of the new and
existing values are checked in addition to the values themselves.
Previously, if the new and existing values were equal (i.e. 1.0
and 1), it wouldn't update the value. Now, if the classes are
different, it always updates the value.
* Date and DateTime objects are now handled correctly when using
prepared statements/bound variables in the jdbc adapter.
* Date, DateTime, Time, true, false, and SQL::Blob objects are now
handled correctly when using prepared statements/bound variables
in the sqlite adapter.
* Sequel now uses varbinary(max) instead of image for the generic
File (blob) type on Microsoft SQL Server. This makes it possible
to use an SQL::Blob object as a prepared statement argument.
* Sequel now handles blobs better in the Amalgalite adapter.
* When disconnecting a connection using the sqlite adapter, all
open prepared statements are now closed first. Previously,
attempting to disconnect a connection with open prepared statements
resulted in an error.
* The license file has been renamed from COPYING to MIT-LICENSE, to
make it easier to determine at a glance which license is used.
= Backwards Compatibility
* Because Sequel switched the generic File type from image to
varbinary(max) on Microsoft SQL Server, any migrations/schema
modification methods that used the File type will now result in a
different column type than before.
* The MYSQL_TYPE_PROCS, PG_TYPE_PROCS, and SQLITE_TYPE_PROCS
constants have been removed from the mysql, postgres, and sqlite
adapters, respectively. The UNIX_EPOCH_TIME_FORMAT and
FALSE_VALUES constants have also been removed from the sqlite
adapter.
* Typecasting in the sqlite adapters now uses to_i and to_f instead
of Integer() and Float() with rescues. If you put non-numeric
data in numeric columns on SQLite, this could cause problems.
---
### Doc Release Notes 3.2.0 (`doc/release_notes/3.2.0.txt`)
New Features
------------
* Common table expressions (CTEs) are now supported. CTEs use the
SQL WITH clause, and specify inline views that queries can use.
They also support a recursive mode, where the CTE can recursively
query its own output, allowing you do do things like load all
branches for a given node in a plain tree structure.
The standard with takes an alias and a dataset:
DB[:vw].with(:vw, DB[:table].filter{col < 1})
# WITH vw AS (SELECT * FROM table WHERE col < 1)
# SELECT * FROM vw
The recursive with takes an alias, a nonrecursive dataset, and a
recursive dataset:
DB[:vw].with_recursive(:vw,
DB[:tree].filter(:id=>1),
DB[:tree].join(:vw, :id=>:parent_id).
select(:vw__id, :vw__parent_id))
# WITH RECURSIVE vw AS (SELECT * FROM tree
# WHERE (id = 1)
# UNION ALL
# SELECT vw.id, vw.parent_id
# FROM tree
# INNER JOIN vw ON (vw.id = tree.parent_id))
# SELECT * FROM vw
CTEs are supported by Microsoft SQL Server 2005+, DB2 7+,
Firebird 2.1+, Oracle 9+, and PostgreSQL 8.4+.
* SQL window functions are now supported, and a DSL has been added to
ease their creation. Window functions act similarly to aggregate
functions but operate on sliding ranges of rows.
In virtual row blocks (blocks passed to filter, select, order, etc.)
you can now provide a block to method calls to change the default
behavior to create functions that weren't possible previously. The
blocks aren't called, but their presence serves as a flag.
What function is created depends on the arguments to the method:
* If there are no arguments, an SQL::Function is created with the
name of method used, and no arguments. Previously, it was not
possible to create functions without arguments using the virtual
row block DSL. Example:
DB.dataset.select{version{}} # SELECT version()
* If the first argument is :*, an SQL::Function is created with a
single wildcard argument (*). This is mostly useful for count:
DB[:t].select{count(:*){}} # SELECT count(*) FROM t
* If the first argument is :distinct, an SQL::Function is created
with the keyword DISTINCT prefacing all remaining arguments. This
is useful for aggregate functions such as count:
DB[:t].select{count(:distinct, col1){}}
# SELECT count(DISTINCT col1) FROM t
* If the first argument is :over, the second argument, if provided,
should be a hash of options to pass to SQL::Window. The options
hash can also contain :*=>true to use a wildcard argument as the
function argument, or :args=>... to specify an array of arguments
to use as the function arguments.
DB[:t].select{rank(:over){}} # SELECT rank() OVER ()
DB[:t].select{count(:over, :*=>true){}} # SELECT count(*) OVER ()
DB[:t].select{sum(:over, :args=>col1,
:partition=>col2, :order=>col3){}}
# SELECT sum(col1) OVER (PARTITION BY col2 ORDER BY col3)
PostgreSQL also supports named windows. Named windows can be
specified by Dataset#window, and window functions can reference
them using the :window option.
* Schema information for columns now includes a :ruby_default entry
which contains a ruby object that represents the default given by
the database (which is stored in :default). Not all :default
entries can be parsed into a :ruby_default, but if the
schema_dumper extension previously supported it, it should work.
* Methods to create compound datasets (union, intersect, except), now
take an options hash instead of a true/false flag. The previous
API is still supported, but switching to specifying the ALL setting
using :all=>true is recommended.
Additionally, you can now set :from_self=>false to not wrap the
returned dataset in a "SELECT * FROM (...)".
* Dataset#ungraphed was added that removes the graphing information
from the dataset. This allows you to use Dataset#graph for the
automatic aliasing, or #eager_graph for the automatic aliasing and
joining, and then remove the graphing information so that the
resulting objects will not be split into subhashes or associations.
* There were some introspection methods added to Dataset to describe
which capabilities that dataset does or does not support:
supports_cte?
supports_distinct_on?
supports_intersect_except?
supports_intersect_except_all?
supports_window_functions?
In addition to being available for the user to use, these are also
used internally, so attempting to use a CTE on a dataset that
doesn't support it will raise an Error.
* Dataset#qualify was added, which is like qualify_to with a default
of first_source.
Additionally, qualify now affects PlaceholderLiteralStrings. It
doesn't scan the string (as Sequel never attempts to parse SQL),
but if you provide the column as a symbol placeholder argument, it
will qualify it.
* You can now specify the table and column Sequel::Migrator will use
to record the current schema version. The new Migrator.run method
must be used to use these new options.
* The JDBC adapter now accepts :user and :password options, instead
of requiring them to be specified in the connection string and
handled by the JDBC driver. This should allow connections to
Oracle using the Thin JDBC driver.
* You can now specify the max_connections, pool_timeout, and
single_threaded settings directly in the connection string:
postgres:///database?single_threaded=t
postgres:///database?max_connections=10&pool_timeout=20
* Dataset#on_duplicate_key_update now affects Dataset#insert when
using MySQL.
* You can now specify the :opclass option when creating PostgreSQL
indexes. Currently, this only supports a single operator class
for all columns. If you need different operator classes per
column, please post on sequel-talk.
* Model#autoincrementing_primary_key was added and can be used if
the autoincrementing key isn't the same as the primary key. The
only likely use for this is on MySQL MyISAM tables with composite
primary keys where only one of the composite parts is
autoincrementing.
* You can now use database column values as search patterns and
specify the text to search as a String or Regexp:
String.send(:include, Sequel::SQL::StringMethods)
Regexp.send(:include, Sequel::SQL::StringMethods)
'a'.like(:x) # ('a' LIKE x)
/a/.like(:x) # ('a' ~ x)
/a/i.like(:x) # ('a' ~* x)
/a/.like(:x, 'b') # (('a' ~ x) OR ('a' ~ 'b'))
* The Dataset#dataset_alias private method was added. It can be
overridden if you have tables named t0, t1, etc., and want to make
sure the default dataset aliases that Sequel uses do not clash
with existing table names.
* Sequel now raises an Error if you call Sequel.connect with
something that is not a Hash or String.
* bin/sequel now accepts a -N option to not test the database
connection.
* An opening_databases.rdoc file was added to the documentation
directory, which should be a good introduction for new users about
how to set up your Database connection.
Other Improvements
------------------
* MySQL native adapter SELECT is much faster than before, up to 75%
faster.
* JDBC SELECT is about 10% faster than before. It's still much
slower than the native adapters, due to conversion issues.
* bin/sequel now works with a YAML file on ruby 1.9.
* MySQL foreign key table constraints have been fixed.
* Database#indexes now works on PostgreSQL if the schema used is a
Symbol. It also works on PostgreSQL versions all the way back to
7.4.
* Graphing of datasets with dataset sources has been fixed.
* Changing a columns name, type, or NULL status on MySQL now
supports a much wider selection of column defaults.
* The stored procedure code is now thread-safe. Sequel is
thread-safe in general, but due to a bug the previous stored
procedure code was not thread-safe.
* The ODBC adapter now drops statements automatically instead of
requiring the user to do so manually, making it more similar
to other adapters.
* The single_table_inheritance plugin no longer overwrites the STI
field if the field already has a value. This allows you to use
create in the generic class to insert a value that will be
returned as a subclass:
Person.create(:kind => "Manager")
* When altering columns on MySQL, :unsigned, :elements, :size and other
options given are no longer ignored.
* The PostgreSQL shared adapter's explain and analyze methods have
been fixed, they had been broken in 3.0.
* Parsing of the server's version is more robust on PostgreSQL.
It should now work correctly for 8.4 and 8.4rc1 type versions.
Backwards Compatibility
-----------------------
* Dataset#table_exists? has been removed, since it never worked
perfectly. Use Database#table_exists? instead.
* Model.grep now calls Dataset#grep instead of Enumerable#grep.
If you are using Model.grep, you need to modify your application.
* The MSSQL shared adapter previously used the :with option for
storing the NOLOCK setting of the query. That option has been
renamed to :table_options, since :with is now used for CTEs.
This should not have an effect unless you where using the option
manually.
* Previously, providing a block to a method calls in virtual row
blocks did not change behavior, where now it causes a different
code path to be used. In both cases, the block is not evaluated,
but that may change in a future version.
* Dataset#to_table_reference protected method was removed, as it was
no longer used.
* The pool_timeout setting is now converted to an Integer, so if you
used to pass in a Float, it no longer works the same way.
* Most files in adapters/utils have been removed, in favor of
integrating the code directly into Database and Dataset. If you
were previously checking for the UnsupportedIntersectExcept or
related modules, use the Dataset introspection methods instead
(e.g. supports_intersect_except?).
* If you were using the ODBC adapter and manually dropping returned
statements, you should note that now statements are dropped
automatically, and the execute method doesn't return a statement
object.
* The MySQL adapter on_duplicate_key_update_sql is now a private
method.
* If you were modifying the :from dataset option directly, note that
Sequel now expects this option to be preprocessed. See the new
implementation of Dataset#from for an idea of the changes
required.
* Dataset#simple_select_all? now returns false instead of true for a
dataset that selects from another dataset.
---
### Doc Release Notes 3.20.0 (`doc/release_notes/3.20.0.txt`)
= New Features
* The swift adapter now supports an SQLite subadapter. Use the
:db_type => 'sqlite' option when connecting. You can use an
in memory database with the following connection string:
swift:///?database=:memory:&db_type=sqlite
* Arbitrary JDBC properties can now be set in the JDBC adapter
using the :jdbc_properties option when connecting. The value
of this option should be a hash where keys and values are JDBC
property keys and values.
* Basic Microsoft Access support was added to the ado adapter.
The creation of autoincrementing primary key integers now works,
and identifiers are now quoted with [].
* The Database#indexes method now supports a :partial option when
connecting to MySQL, which makes it include partial indexes (which
are usually excluded).
= Other Improvements
* The class_table_inheritance plugin now handles subclass
associations better. Previously, the implicit eager loading code
had issues when you called an association method that only existed
in the subclass.
* The error message used when a validates_max_length validation is
applied to a nil column value has been improved. You can override
the message yourself using the :nil_message option.
* The read_timeout and connect_timeout options now work correctly in
the mysql adapter.
* Another MySQL disconnect error message is now recognized.
= Backwards Compatibility
* The swift adapter was upgraded to support swift 0.8.1. Older
versions of swift are no longer supported.
---
### Doc Release Notes 3.21.0 (`doc/release_notes/3.21.0.txt`)
= New Features
* A tinytds adapter was added, enabling Sequel users on a C-based
ruby running on *nix easy access to Microsoft SQL Server.
Previously, the best way to connect to Microsoft SQL Server from
a C-based ruby on *nix was to use the ODBC adapter with unixodbc
and freetds. However, setting that up is nontrivial, while
setting up tinytds is very easy.
Note that the tinytds adapter currently requires the git master
branch of tiny_tds, but tiny_tds 0.4.0 should include the related
changes.
* An association_autoreloading plugin has been added to Sequel,
which removes stale many_to_one associations from the cache when
the associated foreign key setter is used to change the value of
the foreign key.
* bin/sequel now operates more like a standard *nix utility.
If given a file on the command line after the connection
string, it will assume that file has ruby code and load it.
If stdin is not a tty, it will read from stdin and execute it
as ruby code.
For recent Linux users, this means you can have a shebang line
such as:
#!/usr/bin/sequel postgres://user:pass@host/db
to create a self contained script.
* bin/sequel now supports -r and -I options similar to ruby's
-r and -I options.
* MySQL datasets now have a calc_found_rows method that uses
SQL_CALC_FOUND_ROWS, which provides a fast way to limit the
number of results returned by a dataset while having an easy
way to determine how many rows would have been returned if no
limit was applied.
= Other Improvements
* The Sequel::Model.plugin method can now be overridden just like
any other method. Previously, it was the only method that
was defined directly on the class. This allows the creation
of plugins that can modify the plugin system itself.
* Symbol splitting (:table__column___alias) now works correctly
for identifiers that include characters that aren't in [\w ].
Among other things, this means that identifiers with accented
characters or even kanji characters can be used with symbol
splitting.
* If cover? is defined, it is now used in preference to include?
for the validates_includes/validates_inclusion_of validations.
ruby 1.9 defines include? differently for some ranges and can
be very slow, while cover? is similar to the 1.8 behavior of
just checking the beginning and end of the range.
* The bin/sequel -L option now takes effect even if the -m,
-C, -d, or -D options are used.
* The schema_dumper extension now recognizes the "bigint unsigned"
type.
* On Microsoft SQL Server, if joining to a subselect that uses a
common table expression, that common table expression is
promoted to the main dataset. This allows most queries to work
correctly, but is vulnerable to issues if both the current
dataset and the joined dataset use common table expressions with
the same name. Unfortunately, unlike PostgreSQL, Microsoft SQL
Server does not allow common table expressions to occur in
subselects.
* The NULL/NOT NULL, DEFAULT, and UNIQUE column options now
use the proper order on H2 and Oracle, so they can now be
used in conjunction with each other.
* Row locks are now enabled on Oracle.
* The join_table method on MySQL no longer ignores the block it was
given.
* The informix adapter now supports ruby-informix version >= 0.7.3,
while still being backwards compatible with older versions.
* The specs now run under both RSpec 2 and RSpec 1.
---
### Doc Release Notes 3.22.0 (`doc/release_notes/3.22.0.txt`)
= New Features
* Support COLLATE in column definitions. At least MySQL and Microsoft
SQL Server support them, and PostgreSQL 9.1 should as well.
* When connecting to Microsoft SQL Server, you can use the
mssql_unicode_strings accessor to turn of the default usage
of unicode strings (N'') and use regular strings (''). This
can improve performance, but changes the behavior. It's
set to true by default for backwards compatibility. You can
change it at both the dataset and database level:
DB.mssql_unicode_strings = false # default for datasets
dataset.mssql_unicode_strings = false # just this dataset
* In the oracle adapter, if Sequel.application_timezone is :utc, set
the timezone for the connection to use the 00:00 timezone.
= Other Improvements
* In the single_table_inheritance plugin, correctly handle a
multi-level class hierarchy so that loading instances from a
middle level of the hierarchy can return instances of subclasses.
* Don't use a schema when creating a temporary table, even if
default_schema is set.
* Fix the migrator when a default_schema is used.
* In the ado adapter, assume a connection to SQL Server if the
:conn_string is given and doesn't indicate Access/Jet.
* Fix fetching rows in the tinytds adapter when the
identifier_output_method is nil.
* The tinytds adapter now checks for disconnect errors, but it might
not be reliable until the next release of tiny_tds.
* The odbc adapter now handles ODBC::Time instances correctly.
---
### Doc Release Notes 3.23.0 (`doc/release_notes/3.23.0.txt`)
= New Features
* Sequel now allows dynamic customization for eager loading.
Previously, the parameters for eager loading were fixed at
association creation time. Now, they can be modified at query
time. To dynamically modify an eager load, you use a hash with
the proc as the value. For example, if you have this code:
Artist.eager(:albums)
And you only want to eagerly load albums where the id is greater
than or equal to some number provided by the user, you do:
min = params[:min].to_i
Artist.eager(:albums=>proc{|ds| ds.where{id > min}})
This also works when eager loading via eager_graph:
Artist.eager_graph(:albums=>proc{|ds| ds.where{id > min}})
For eager_graph, the dataset is the dataset to graph into the
current dataset, and filtering it will result in an SQL query
that joins to a subquery.
You can also use dynamic customization while cascading to also
eagerly load dependent associations, by making the hash value
a single entry hash with a proc key and the value being the
dependent associations to eagerly load. For example, if you want
to eagerly load tracks for those albums:
Artist.eager(:albums=>{proc{|ds| ds.where{id > min}}=>:tracks})
* Sequel also now allows dynamic customization for regular
association loading. Previously, this was possible by using the
association's dataset:
albums = artist.albums_dataset.filter{id > min}
However, then there was no handling of caching, callbacks, or
reciprocals. For example:
albums.each{|album| album.artist}
Would issue one query per album to get the artist, because the
reciprocal association was not set. Now you can provide a
block to the association method:
albums = artist.albums{|ds| ds.filter{id > min}}
This block is called with the dataset used to retrieve the
associated objects, and should return a modified version of that
dataset.
Note that ruby 1.8.6 doesn't allow blocks to take block arguments,
so you have to pass the block as a separate proc argument to the
association method if you are still using 1.8.6.
* Sequel now supports filtering by associations. This wasn't
previously supported as filtering is a dataset level feature and
associations are a model level feature, and datasets do not depend
on models. Now, model datasets have the ability to filter by
associations. For example, to get all albums for a given artist,
you could do:
artist = Artist[1]
Album.filter(:artist=>artist)
Since the above can also be accomplished with:
artist.albums
this may not seem like a big improvement, but it allows you to
filter on multiple associations simultaneously:
Album.filter(:artist=>artist, :publisher=>publisher)
For simple many_to_one associations, the above is just a simpler
way to do:
Album.filter(:artist_id=>artist.id, :publisher_id=>publisher.id)
Sequel supports this for all association types, including
many_to_many and many_through_many, where a subquery is used, and
it also works when composite key associations are used:
Album.filter(:artist=>artist, :tags=>tag)
This will give you the albums for that artist that are also tagged
with that tag. To provide multiple values for the same
association, mostly useful for many_to_many associations, you can
either use separate filter calls or specify the conditions as an
array:
Album.filter(:tags=>tag1).filter(:tags=>tag2)
Album.filter([[:tags, tag1], [:tags, tag2]])
* A columns_introspection extension has been added that makes
datasets attempt to guess their columns in some cases instead of
issuing a database query. This can improve performance in cases
where the columns are needed implicitly, such as graphing. After
loading the extension, you can enable the support for specific
datasets by extending them with Sequel::ColumnIntrospection. To
enable introspection for all datasets, use:
Sequel::Dataset.introspect_all_columns
* A serialization_modification_detection plugin has been added.
Previously, Sequel could not detect modifications made to
serialized objects. It could detect modification if you assigned
a new value:
model.hash_column = model.hash_column.merge(:foo=>:bar)
but not if you just modified the object directly:
model.hash_columns[:foo] = :bar
With this plugin, such modifications can be detected, at a
potentially significant performance cost.
= Other Improvements
* When using a migration directory containing both older integer
migrations and newer timestamp migrations, where some integer
migrations have not been applied, make sure to apply the remaining
integer migrations before the timestamp migrations. Previously,
they could be applied out of order due to a lexicographic sort
being used instead of a numeric sort.
* If a model does not select all columns from its table, the
insert_select optimization is no longer used. Previously,
creating a new model object for such a model could result in the
object containing columns that the model does not select.
* You can now use :select=>[] as an option for many_to_many
associations to select all columns from both the associated
table and the join table. Previously, this raised an error and
required you do :select=>'*'.lit as a workaround. The default
remains to select all columns in the associated table and none
from the join table.
* The xml_serializer plugin now handles namespaced models by
using __ instead of / as the namespace separator. Previously, /
was used and caused problems as it is not valid XML.
* The :eager_grapher association option can now accept a proc that
takes a single hash of options instead of a fixed 3 arguments.
This is the recommended way going forward of writing custom
:eager_graphers, and all of the internal ones have been converted.
The previous way of using 3 arguments is still supported.
* A bug in the identity_map plugin for many_to_one associations
without full association reflection information has been fixed.
* Sequel is now using GitHub Issues for issue tracking. Old issues
have been migrated from Google Code.
= Backwards Compatibility
* The filter by associations support breaks backward compatibility for
users who previously added an sql_literal instance method to
Sequel::Model. Usually, that was done to for reasons similar to
but inferior than the filter by association support. The following
code can be used as a temporary workaround until you can modify
your program to use the new filter by associations support:
Sequel::Model::Associations::DatasetMethods.
send(:remove_method, :complex_expression_sql)
* The private Sequel::Model#_load_associated_objects method now takes
an additional, optional options hash. Plugins that override that
method need to be modified.
---
### Doc Release Notes 3.24.0 (`doc/release_notes/3.24.0.txt`)
= Prepared Statement Plugins
* The prepared_statements plugin makes Sequel::Model classes use
prepared statements for creating, updating, and destroying model
instances, as well as looking up model objects by primary key.
With this plugin, all of the following will use prepared
statements:
Artist.plugin :prepared_statements
Artist.create(:name=>'Foo')
a = Artist[1]
a.update(:name=>'Bar')
a.destroy
* The prepared_statements_safe plugin reduces the number of
prepared statements that can be created by doing two things. First,
it makes the INSERT statements used when creating instances to use
as many columns as possible, setting specific values for all
columns with parseable default values. Second, it changes
save_changes to just use save, saving all columns instead of just
the changed ones.
The reason for this plugin is that Sequel's default behavior of
using only the values specifically set when creating instances
and having update only set changed columns by default can lead
to a large number of prepared statements being created.
For prepared statements to be used, each set of columns in the
insert and update statements needs to have its own prepared
statement. If you have a table with 1 primary key column and
4 other columns, you can have up to 2^4 = 16 prepared statements
created, one for each subset of the 4 columns. If you have 1
primary key column and 20 other columns, there are over a million
subsets, and you could hit your database limit for prepared
statements (a denial of service attack).
Using the prepared_statements_safe plugin mitigates this
issue by reducing the number of columns that may or may not be
present in the query, in many cases making sure that each model
will only have a single INSERT and a single UPDATE prepared
statement.
* The prepared_statements_associations plugin allows normal
association method calls to use prepared statements if possible.
For example:
Artist.plugin :prepared_statements_associations
Artist.many_to_one :albums
Artist[1].albums
Will use a prepared statement to return the albums for that artist.
This plugin works for all supported association types. There are
some associations (filtered and custom associations) that Sequel
cannot currently use a prepared statement reliably, for those
Sequel will use a regular query.
* The prepared_statements_with_pk plugin allows the new
Dataset#with_pk method (explained below) to use prepared statements.
For example:
Artist.plugin :prepared_statements_with_pk
Artist.filter(...).with_pk(1)
Will use a prepared statement for this query. The most benefit
from prepared statements come from queries that are expensive to
parse and plan but quick to execute, so using this plugin with
a complex filter can in certain cases yield significant performance
improvements.
However, this plugin should be considered unsafe as it is possible
that it will create an unbounded number of prepared statements. It
extracts parameters from the dataset using Dataset#unbind
(explained below), so if your code has conditions that vary per
query but that Dataset#unbind does not handle, an unbounded number
of prepared statements can be created. For example:
Artist.filter(:a=>params[:b].to_i).with_pk[1]
Artist.exclude{a > params[:b].to_i}.with_pk[1]
are safe, but:
Artist.filter(:a=>[1, params[:b].to_i]).with_pk[1]
Artist.exclude{a > params[:b].to_i + 2}.with_pk[1]
are not. For queries that are not safe, Dataset#with_pk should
not be used with this plugin, you should switch to looking up by
primary key manually (for a regular query):
Artist.filter(:a=>[1, params[:b].to_i])[:id=>1]
or using the prepared statement API to create a custom prepared
statement:
# PS = {}
PS[:name] ||= Artist.filter(:a=>[1, :$b], :id=>:$id).
prepare(:select, :name)
PS[:name].call(:b=>params[:b].to_i, :id=>1)
= Other New Features
* Filtering by associations got a lot more powerful. Sequel 3.23.0
introduced filtering by associations:
Album.filter(:artist=>artist)
This capability is much expanded in 3.24.0, allowing you to
exclude by associations:
Album.exclude(:artist=>artist)
This will match all albums not by that artist.
You can also filter or exclude by multiple associated objects:
Album.filter(:artist=>[artist1, artist2])
Album.exclude(:artist=>[artist1, artist2])
The filtered dataset will match all albums by either of those
two artists, and the excluded dataset will match all albums not
by either of those two artists.
You can also filter or exclude by using a model dataset:
Album.filter(:artist=>Artist.filter(:name.like('A%'))).all
Album.exclude(:artist=>Artist.filter(:name.like('A%'))).all
Here the filtered dataset will match all albums where the
associated artist has a name that begins with A, and the excluded
dataset will match all albums where the associated artist does not
have a name that begins with A.
All of these types of filtering and excluding work with all of
association types that ship with Sequel, even the many_through_many
plugin.
* Sequel now supports around hooks, which wrap the related before
hook, behavior, and after hook. Like other Sequel hooks, these
are implemented as instance methods. For example, if you wanted
to log DatabaseErrors raised during save:
class Artist < Sequel::Model
def around_save
super
rescue Sequel::DatabaseError => e
# log the error
raise
end
end
All around hooks should call super, not yield. If an around hook
doesn't call super or yield, it is treated as a hook failure,
similar to before hooks returning false.
For around_validation, the return value of super should be whether
the object is valid. For other around hooks, the return value of
super is currently true, but it's possible that will change in the
future.
* Dataset#with_pk has been added to model datasets that allows you
to find the object with the matching primary key:
Artist.filter(:name.like('A%')).with_pk(1)
This should make easier the common case where you want to find
a particular object that is associated to another object:
Artist[1].albums_dataset.with_pk(2)
Before, there was no way to do that without manually specifying
the primary key:
Artist[1].albums_dataset[:id=>2]
To use a composite primary key with with_pk, you have to provide
an array:
Artist[1].albums_dataset.with_pk([1, 2])
* Dataset#[] for model datasets will now call with_pk if given a
single Integer argument. This makes the above case even easier:
Artist[1].albums_dataset[2]
Note that for backwards compatibility, this only works for
single integer primary keys. If you have a composite primary key
or a string/varchar primary key, you have to use with_pk.
* Dataset#unbind has been added, which allows you to take a dataset
that uses static bound values and convert them to placeholders.
Currently, the only cases handled are SQL::ComplexExpression
objects that use a =, !=, <, >, <=, or >= operator where the first
argument is a Symbol, SQL::Identifier, or
SQL::QualifiedIdentifier, and the second argument is a Numeric,
String, Date, or Time. Dataset#unbind returns a two element array,
where the first element is a modified copy of the receiver, and the
second element is a bound variable hash:
ds, bv = DB[:table].filter(:a=>1).unbind
ds # DB[:table].filter(:a=>:$a)
bv # {:a=>1}
The purpose of doing this is that you can then use prepare or call
on the returned dataset with the returned bound variables:
ds.call(:select, bv)
# SELECT * FROM table WHERE (a = ?); [1]
ps = ds.prepare(:select, :ps_name)
# PREPARE ps_name AS SELECT * FROM table WHERE (a = ?)
ps.call(bv)
# EXECUTE ps_name(1)
Basically, Dataset#unbind takes a specific statement and attempts
to turn it into a generic statement, along with the placeholder
values it extracted.
Unfortunately, Dataset#unbind cannot handle all cases. For
example:
DB[:table].filter{a + 1 > 10}.unbind
will not unbind any values. Also, if you have a query with
multiple different values for a variable, it will raise an
UnbindDuplicate exception:
DB[:table].filter(:a=>1).or(:a=>2).unbind
* A defaults_setter plugin has been added that makes it easy to
automatically set default values when creating new objects. This
plugin makes Sequel::Model behave more like ActiveRecord in that
new model instances (before saving) will have default values
parsed from the database. Unlike ActiveRecord, only values with
non-NULL defaults are set. Also, Sequel allows you to easily
modify the default values used:
Album.plugin :default_values
Album.new.values # {:copies_sold => 0}
Album.default_values[:copies_sold] = 42
Album.new.values # {:copies_sold => 42}
Before, this was commonly done in an after_initialize hook, but
that's slower as it is also called for model instances loaded from
the database.
* A Database#views method has been added that returns an array
of symbols representing view names in the database. This works
just like Database#tables except it returns views.
* A Sequel::ASTTransformer class was added that makes it easy to
write custom transformers of Sequel's internal abstract syntax
trees. Dataset#qualify now uses a subclass of ASTTransformer to do
its transformations, as does the new Dataset#unbind.
= Other Improvements
* Database#create_table? now uses a single query with IF NOT EXISTS
if the database supports such syntax. Previously, it issued a
SELECT query to determine table existence. Sequel currently
supports this syntax on MySQL, H2, and SQLite 3.3.0+.
The Database#supports_create_table_if_not_exists? method was added
to allow users to determine whether this syntax is supported.
* Multiple column IN/NOT IN emulation now works correctly with
model datasets (or other datasets that use a row_proc).
* You can now correctly invert SQL::Constant instances:
Sequel::NULL # NULL
~Sequel::NULL # NOT NULL
Sequel::TRUE # TRUE
~Sequel::TRUE # FALSE
* A bug in the association_pks plugin has been fixed in the case
where the associated table had a different primary key column name
than the current table.
* The emulated prepared statement support now supports nil and false
as bound values.
* The to_dot extension was refactored for greater readability. The
only change was a small fix in the display for SQL::Subscript
instances.
* The Dataset#supports_insert_select? method is now available to let
you know if the dataset supports insert_select. You should use
this method instead of respond_to? for checking for insert_select
support.
* Prepared statements/bound variable can now use a new :insert_select
type for preparing a statement that will insert a row and return
the row inserted, if the dataset supports insert_select.
* The Model#initialize_set private method now exists for easier plugin
writing. It is only called for new model objects, with the hash
given to initialize. By default, it just calls set.
* A small bug when creating anonymous subclasses of Sequel::Model on
ruby 1.9 has been fixed.
* If Thread#kill is used inside a transaction on ruby 1.8 or
rubinius, the transaction is rolled back. This situation is not
handled correctly on JRuby or ruby 1.9, and I'm not sure it's
possible to handle correctly on those implementations.
* The postgres adapter now supports the
Sequel::Postgres::PG_NAMED_TYPES hash for associating conversion
procs for custom types that don't necessarily have the same type
oid on different databases. This hash uses symbol keys and
proc values:
Sequel::Postgres::PG_NAMED_TYPES[:interval] = proc{|v| ...}
The conversion procs now use a separate hash per Database object
instead of a hash shared across all Database objects. You
can now modify the types for a particular Database object, but
you have to use the type oid:
DB.conversion_procs[42] = proc{|v| ...}
* On SQLite and MSSQL, literalization of true and false values given
directly to Dataset#filter has been fixed. So the following now
works correctly on those databases:
DB[:table].filter(true)
DB[:table].filter(false)
Unfortunately, because SQLite and MSSQL don't have a real boolean
type, these will not work:
DB[:table].filter{a & true}
DB[:table].filter{a & false}
You currently have to work around the issue by doing:
DB[:table].filter{a & Sequel::TRUE}
DB[:table].filter{a & Sequel::FALSE}
It is possible that a future version of Sequel will remove the need
for this workaround, but that requires having a separate
literalization method specific to filters.
* The MySQL bit type is no longer treated as a boolean. On MySQL, the
bit type is a bitfield, which is very different than the MSSQL bit
type, which is the closest thing to a boolean on MSSQL.
* The bool database type is now recognized as a boolean. Some SQLite
databases use bool, such as the ones used in Firefox.
* SQL_AUTO_IS_NULL=0 is now set by default when connecting to MySQL
using the swift or jdbc adapters. Previously, it was only set by
default when using the mysql or mysql2 adapters.
* Dataset#limit now works correctly on Access, using the TOP syntax.
* Dataset#limit now works correctly on DB2, using the FETCH FIRST
syntax.
* The jdbc mssql subadapter was split into separate subadapters for
sqlserver (using Microsoft's driver) and jtds (using the open
source JTDS driver).
* The jdbc jtds subadapter now supports converting Java CLOB
objects to ruby strings.
* Tables from the INFORMATION_SCHEMA are now ignored when parsing
schema on JDBC.
* The informix adapter has been split into shared/specific parts, and
a jdbc informix subadapter has been added.
* Dataset#insert_select now works correctly on MSSQL when the core
extensions are disabled.
* The sqlite adapter now logs when preparing a statement.
* You no longer need to be a PostgreSQL superuser to run the postgres
adapter specs.
* The connection pool specs are now about 10 times faster and not
subject to race conditions due to using Queues instead of
sleeping.
= Backwards Compatibility
* Model#save no longer calls Model#valid?. It now calls the
Model#_valid? private method that Model#valid? also calls. To mark
a model instance invalid, you should override the Model#validate
method and add validation errors to the object.
* The BeforeHookFailure exception class has been renamed to
HookFailure since hook failures can now be raised by around hooks
that don't call super. BeforeHookFailure is now an alias to
HookFailure, so no code should break, but you should update your
code to reflect the new name.
* Any custom argument mappers used for prepared statements now need
to implement the prepared_arg? private instance method and have it
return true.
* If your databases uses bit as a boolean type and isn't MSSQL, it's
possible that those columns will no longer be treated as booleans.
Please report such an issue on the bugtracker.
* It is possible that the filtering and excluding by association
datasets will break backwards compatibility in some apps. This can
only occur if you are using a symbol with the same name as an
association with a model dataset whose model is the same as the
associated class. As associations almost never have the same names
as columns, this would require either aliasing or joining to
another table. If for some reason this does break your app, you
can work around it by changing the symbol to an SQL::Identifier or
a literal string.
* The Sequel::Postgres.use_iso_date_format= method now only affects
future Database objects.
* On MySQL, Database#tables no longer returns view names, it only
returns table names. You have to use Database#views to get view
names now.
---
### Doc Release Notes 3.25.0 (`doc/release_notes/3.25.0.txt`)
= New Features
* drop_table, drop_view, drop_column, and drop_constraint all now
support a :cascade option for using CASCADE.
DB.drop_table(:tab, :cascade=>true)
# DROP TABLE tab CASCADE
DB.drop_column(:tab, :col, :cascade=>true)
# ALTER TABLE tab DROP COLUMN col CASCADE
A few databases support CASCADE for dropping tables and views,
but only PostgreSQL appears to support it for columns and
constraints. Using the :cascade option when the underlying
database doesn't support it will probably result in a
DatabaseError being raised.
* You can now use datasets as expressions, allowing things such as:
DB[:table1].select(:column1) > DB[:table2].select(:column2)
# (SELECT column1 FROM table1) > (SELECT column2 FROM table2)
DB[:table1].select(:column1).cast(Integer)
# CAST((SELECT column1 FROM table1) AS integer)
* Dataset#select_group has been added for grouping and selecting on
the same columns.
DB[:a].select_group(:b, :c)
# SELECT b, c FROM a GROUP BY b, c
* Dataset#exclude_where and #exclude_having methods have been added,
allowing you to specify which clause to affect. #exclude's
behavior is still to add to the HAVING clause if one is present,
and use the WHERE clause otherwise.
* Dataset#select_all now accepts optional arguments and will select
all columns from those arguments if present:
DB[:a].select_all(:a)
# SELECT a.* FROM a
DB.from(:a, :b).select_all(:a, :b)
# SELECT a.*, b.* FROM a, b
* Dataset#group and #group_and_count now both accept virtual row
blocks:
DB[:a].select(:b).group{c(d)}
# SELECT b FROM a GROUP BY c(d)
* If you use a LiteralString as a validation error message,
Errors#full_messages will now not add the related column name to
the start of the error message.
* Model.set_dataset now accepts SQL::Identifier,
SQL::QualifiedIdentifier, and SQL::AliasedExpression instances,
treating them like Symbols.
= Other Improvements
* The association_pks plugin's setter method will now automatically
convert a given array of strings to an array of integers if the
primary key field is an integer field, which should make it easier
to use in web applications.
* nil bound variable, prepared statement, and stored procedure
arguments are now handled correctly in the JDBC adapter.
* On 1.9, you can now load plugins even when ::ClassMethods,
::InstanceMethods, or ::DatasetMethods is defined.
= Backwards Compatibility
* The tinytds adapter now only works with tiny_tds 0.4.5 and greater.
Also, if you were using the tinytds adapter with FreeTDS 0.91rc1,
you need to upgrade to FreeTDS 0.91rc2 for it to work. Also, if
you were referencing an entry in the freetds.conf file, you now
need to specify it directly using the :dataserver option when
connecting, the adapter no longer copies the :host option to the
:dataserver option.
* On postgresql, Sequel now no longer drops tables with CASCADE by
default. You now have to use the :cascade option to drop_table if
you want to use CASCADE.
* The Database#drop_table_sql private method now takes an additional
options hash argument.
---
### Doc Release Notes 3.26.0 (`doc/release_notes/3.26.0.txt`)
= Performance Enhancements
* The internal implementation of eager_graph has been made 75% to
225% faster than before, with greater benefits to more complex
graphs.
* Dataset creation has been made much faster (2.5x on 1.8 and 4.4x on
1.9), and dataset cloning has been made significantly faster (40%
on 1.8 and 20% on 1.9).
= Other Improvements
* Strings passed to setter methods for integer columns are no longer
considered to be in octal format if they include leading zeroes.
The previous behavior was never intended, but was a side effect of
using Kernel#Integer. Strings with leading zeroes are now treated
as decimal, and you can still use the 0x prefix to treat them as
hexadecimal. If anyone was relying on the old octal behavior, let
me know and I'll add an extension that restores the octal behavior.
* The identity_map plugin now works with the standard eager loading
of many_to_many and many_through_many associations.
* Database#create_table! now only attempts to drop the table if it
already exists. Previously, it attempted to drop the table
unconditionally ignoring any errors, which resulted in misleading
error messages if dropping the table raised an error caused by
permissions or referential integrity issues.
* The default connection pool now correctly handles the case where a
disconnect error is raised and an exception is raised while
running the disconnection proc.
* Disconnection errors are now detected when issuing transaction
statements such as BEGIN/ROLLBACK/COMMIT. Previously, these
statements did not handle disconnect errors on most adapters.
* More disconnection errors are now detected. Specifically, the ado
adapter and do postgres subadapter now handle disconnect errors,
and the postgres adapter handles more types of disconnect errors.
* Database#table_exists? now always issues a query to select from the
table, it no longer attempts to parse the schema to determine the
information on PostgreSQL and Oracle.
* Date, DateTime, and Time values are now literalized correctly on
Microsoft Access.
* Connecting with the mysql adapter with an options hash now works if
the :port option is a string, which makes it easier to use when the
connection information is stored in YAML.
* The xml_serializer plugin now works around a bug in pure-Java
nokogiri regarding the handling of nil values.
* Nicer error messages are now used if there is an attempt to call
an invalid or restricted setter method.
* The RDocs are now formatted with hanna-nouveau, which allows for
section ordering, so the Database and Dataset RDoc pages are
more friendly.
= Backwards Compatibility
* If you call a Dataset method such as #each on an eager_graphed
dataset, you now get plain hashes that have column alias symbol
keys and their values. Previously, you got a graphed response with
table alias keys and model values. It's not wise to depend on the
behavior, the only supported way of returning records when eager
loading is to use #all.
* An error is now raised if you attempt to eager load via
Dataset#eager a many_to_many association that includes an
:eager_graph option. Previously, incorrect SQL would have been
generated and an error raised by the database.
* Datasets are no longer guaranteed to have @row_proc,
@identifier_input_method, and @identifier_output_method defined
as instance variables. You should be be using methods to access
them anyway.
* Database#table_exists? on PostgreSQL no longer accepts an options
hash. Previously, you could use a :schema option. You must now
provide the schema inside the table argument (e.g. :schema__table).
* If you want to use the rdoc tasks in Sequel's Rakefile, and you are
still using the hanna RDoc template with RDoc 2.3, you need to
upgrade to using hanna-nouveau with RDoc 3.8+.
---
### Doc Release Notes 3.27.0 (`doc/release_notes/3.27.0.txt`)
= New Features
* Model.dataset_module has been added for easily adding methods to
a model's dataset:
Album.dataset_module do
def with_name_like(x)
filter(:name.like(x))
end
def selling_at_least(x)
filter{copies_sold > x}
end
end
Album.with_name_like('Foo%').selling_at_least(100000).all
Previously, you could use def_dataset_method to accomplish the
same thing. dataset_module is generally cleaner, plus you are
using actual methods instead of blocks, so calling the methods
is faster on some ruby implementations.
* Sequel now uses a Sequel::SQLTime class (a subclass of Time) when
dealing with values for SQL time columns (which don't have a date
component). These values are handled correctly when used in
filters or insert/update statements (using only the time
component), so Sequel can now successfully round trip values for
time columns. Not all adapters support returning time column
values as SQLTime instances, but the most common ones do.
* You can now drop foreign key, primary key, and unique constraints
on MySQL by passing the :type=>(:foreign_key|:primary_key|:unique)
option to Database#drop_constraint.
* The ODBC adapter now has initial support for the DB2 database, use
the :db_type=>'db2' option to load the support.
= Other Improvements
* The mysql2 adapter now uses native prepared statements.
* The tinytds adapter now uses uses sp_executesql for prepared
statements.
* DateTime and Time objects are now converted to Date objects when
they are assigned to a date column in a Model instance.
* When converting a Date object to a DateTime object, the resulting
DateTime object now has no fractional day components. Previously,
depending on your timezone settings, it could have had fractional
day components.
* The mysql2 adapter now supports stored procedures, as long as they
don't return results.
* Mass assignment protection now handles including modules in model
classes and extending model instances with modules. Previously, if
you defined a setter method in a module, access to it may have been
restricted.
* The prepared_statements_safe plugin now works on classes without
datasets, so you can now do the following to load it for all models:
Sequel::Model.plugin :prepared_statements_safe
* Dataset#hash now works correctly when handling SQL::Expression
instances.
* Model#hash now correctly handles classes with no primary key or with
a composite primary key.
* Model#exists? now always returns false for new model objects.
= Backwards Compatibility
* If you were previously setting primary key values manually for new
model objects and then calling exists? to see if the instance is
already in the database, you need to change your code from:
model.exists?
to:
model.this.get(1).nil?
---
### Doc Release Notes 3.28.0 (`doc/release_notes/3.28.0.txt`)
= New Adapter Support
* Sequel now has much better support for the DB2 database.
* An ibmdb adapter has been added, and is the recommended adapter to
to use if you want to connect to DB2 from MRI.
* A jdbc db2 subadapter has been added, allowing good DB2 support on
JRuby.
* The db2 adapter has been cleaned up substantially, and now works
well, but it is still recommended that you switch to ibmdb if you
are using the db2 adapter.
* The firebird adapter has been split into shared and specific parts,
and quite a few fixes were made to it.
* A jdbc firebird subadapter has been added, allowing connection to
firebird databases from JRuby.
= New PostgreSQL 9.1 Features
* Dataset#returning has been added for using the RETURNING clause on
INSERT/UPDATE/DELETE queries. RETURNING allows such queries to
return results in much the same way as a SELECT query works.
When Dataset#returning is used, Dataset #insert, #update, and
#delete now accept a block that is passed to Dataset #fetch_rows
which is yielded plain ruby hashes for each row inserted, updated,
or deleted. If Dataset#returning is used and a block is not given
to those methods, those methods will return an array of plain hashes
for all rows inserted, updated, and deleted.
* Dataset#with_sql now treats a symbol as a first argument as a method
name to call to get the SQL. The expected use case for this is with
Dataset#returning and insert/update/delete:
DB[:items].
returning(:id).
with_sql(:update_sql, :b => :b + 1).
map(:id)
Basically, it makes it more easily to statically set the
insert/update/delete SQL, and then be able to use the full
dataset API for returning results. As mentioned above, using
Dataset#returning with #insert, #update, and #delete yields plain
hashes, so if you want to have the row_proc applied (e.g. you are
using models), you need to use this method instead, since you can
then call #each or #all to make sure the row_proc is called on all
returned rows.
* Dataset#with (common table expressions) now affects
INSERT/UPDATE/DELETE queries.
* Database#create_table? now uses CREATE TABLE IF NOT EXISTS on
PostgreSQL 9.1.
= Other New Features
* The :limit option is now respected when eager loading via either
eager or eager_graph. By default, Sequel will just do an array
slice of the resulting ruby array, which gets the correct answer,
but does not offer any performance improvements. Sequel also
offers a new :eager_limit_strategy option for using more advanced
query types that only load the related records from the database.
The available values for the :eager_limit_strategy option are:
:window_function - This uses the row_number window function
partitioned by the related key fields. It can only be used
on databases that support window functions (PostgreSQL 8.4+,
Microsoft SQL Server 2005+, DB2).
:correlated_subquery - This uses a correlated subquery that is
limited. It works on most databases except MySQL and DB2.
You can provide a value of true as the option to have Sequel
pick a strategy to use. Sequel will never use a correlated
subquery for true, since in some cases it can perform worse than
loading all related records and doing the array slice in ruby.
If you want to enable an eager_limit_strategy globally, you can
set Sequel::Model.default_eager_limit_strategy to a value, and
all associations that use :limit will default to using that
strategy.
* one_to_one associations that do not represent true one-to-one
database relationships, but represent one-to-many relationships
where you are only returning the first object based on a given
order are also now handled correctly when eager loading.
Previously, eager loading such associations resulted in the last
matching object being associated instead of the first matching
object being associated.
You can also use an :eager_limit_strategy for one_to_one
associations. In addition to the :window_function and
:correlated_subquery values, there is also a :distinct_on value
that is available on PostgreSQL for using DISTINCT ON, which is
the fastest strategy if you are using PostgreSQL.
* Dataset#map, #to_hash, #select_map, #select_order_map, and
#select_hash now accept arrays of symbols, and if given arrays
of symbols, use arrays of results. For example:
DB[:items].map([:id, :name])
# => [[1, 'foo'], [2, 'bar'], ...]
DB[:items].to_hash([:id, :foo_id], [:name, :bar_id])
# => {[1, 3]=>['foo', 5], [2, 4]=>['bar', 6], ...}
* For SQL expression objects where Sequel cannot deduce the type
of the object, it now will consider the type of the argument
when a &, |, or + operator is used. For example:
:x & 1
Previously, this did "x AND 1", now it does "x & 1". Using a
logical operator on an integer doesn't make sense, but it's
possible people did so if the database uses 1/0 for true/false.
Likewise:
:x + 'foo'
Previously, this did "x + 'foo'" (addition), now it does
"x || 'foo'" (string concatenation).
* The sql_string, sql_number, and sql_boolean methods are now
available on SQL::ComplexExpressions, so you can do:
(:x + 1).sql_string + ' foos'
# (x + 1) || ' foos'
Previously, there was not an easy way to generate such SQL
expressions.
* :after_load association hooks are now applied when using
eager_graph. Previously, they were only applied when using
eager, not when using eager_graph.
* Database#copy_table has been added to the postgres adapter if pg
is used as the underlying driver. It allows you to get very
fast exports of table data in text or CSV format. It also
accepts datasets, allowing fast exports of arbitrary queries
in text or CSV format.
* SQL extract support (:timestamp.extract(:year)) is now emulated
on the databases that don't natively support it, such as SQLite,
Microsoft SQL Server, and DB2. At least the following values are
supported for extraction: :year, :month, :day, :hour, :minute,
and :second.
* The bitwise XOR operator is now emulated on SQLite. Previously,
attempting to use it would cause the database to raise an error.
* A Database#use_timestamp_timezones accessor has been added on
SQLite. This allows you to turn off the use of timezones in
timestamps by setting the value to false. This is necessary if you
want you want to use the SQLite datetime functions, or the new
ability to emulate extract.
Note that this setting does not affect the current database
content. To convert old databases to the new format, you'll
have to resave all rows that have timestamps.
At some point in the future, Sequel may default to not using
timezones in timestamps by default on SQLite, so if you would
like to rely on the current behavior, you should set this
accessor to true now.
* Sequel now works around bugs in MySQL when using a subselect with
a LIMIT by using a nested subselect.
* Sequel now works around issues in Microsoft SQL Server and DB2 when
using a subselect with IN/NOT IN that uses the emulated offset
support.
* The jdbc adapter now returns java.sql.Clob objects as
Sequel::SQL::Blobs.
* Sequel now considers database clob types as the :blob schema type.
* Sequel::SQLTime.create has been added for more easily creating
instances:
Sequel::SQLTime.create(hour, minute, second, usec)
* Dataset#select_all now accepts SQL::AliasedExpression and
SQL::JoinClause arguments and returns the appropriate
SQL::ColumnAll value that selects all columns from the related
table.
* Model.set_dataset now accepts Sequel::LiteralString objects that
represent table names. This usage is not encouraged except in
rare cases such as using a set returning function in PostgreSQL.
* Dataset#supports_cte? now takes an optional argument specifying the
type of query (:insert, :update, :delete, :select). It defaults to
:select.
* Dataset#supports_returning? has been added. It requires an
argument specifying the type of query (:insert, :update, or
:delete).
* Dataset#supports_cte_in_subqueries? has been added for checking
for support for this ability. Apparently, only PostgreSQL
currently supports this. For other adapters that support CTEs but
not in subqueries, if a subquery with a CTE is used in a JOIN, the
CTE is moved from the subquery to the main query.
* Dataset#supports_select_all_and_column has been added for seeing
if "SELECT *, foo ..." style queries are supported. This is false
on DB2, which doesn't allow such queries. When it is false, using
select_append on a dataset that doesn't specifically select columns
will now change the query to do "SELECT table.*, foo ..." instead,
working around the limitation on DB2.
* Dataset#supports_ordered_distinct_on? has been added. Currently,
this is only true on PostgreSQL. MySQL can emulate DISTINCT ON
using GROUP BY, but it doesn't respect ORDER BY, so it some
cases it cannot be used equivalently.
* Dataset#supports_where_true? has been added for checking for support
of WHERE TRUE (or WHERE 1 if 1 is true). Not all databases support
using such a construct, and on the databases that do not, you have
to use WHERE (1 = 1) or something similar.
= Other Improvements
* Sequel 3.27.0 was negatively affected by a serious bug in
ActiveSupport's Time.=== that has still not been fixed, which
broke the literalization of Time objects. In spite of the bad
precedent it sets, Sequel now avoids using Time.=== on a
subclass of Time to work around this ActiveSupport bug.
* Dataset#with_pk now uses a qualified primary key instead of an
unqualified primary key, which means it can now be used correctly
after joining to a separate table.
* Association after_load hooks when lazy loading are now called
after the association has been loaded, which allows them to change
which records are cached. This makes the lazy load case more
similar to the eager load case.
* The metaprogrammatically created methods that implement Sequel's
DSL support have been made significantly faster by using
module_eval instead of define_method.
* The type translation in the postgres, mysql, and sqlite adapters
has been made faster by using Method objects that result in more
direct processing.
* Typecasting values for time columns from Time values to
Sequel::SQLTime values now correctly handles fractional seconds on
ruby 1.9.
= Backwards Compatibility
* Dataset#insert_returning_sql has been changed to a private method
in the PostgreSQL and Firebird adapters, and it operates
differently than it did previously. The private
#insert_returning_pk_sql and #insert_returning_select_sql methods
have been removed.
* Dataset#with_pk no longer does some defensive checking for misuse of
primary keys (e.g. providing a composite key when the model uses
a single key). Previously, Sequel would raise an Error
immediately, now such behavior is undefined, with the most likely
behavior being the database raising an Error.
* The :alias_association_type_map and :alias_association_name_map
settings have been removed from the :eager_graph dataset option,
in favor of just storing the related association reflection.
* The internals of the db2 adapter have changed substantially, if you
were relying on some of the private methods defined in it, you will
probably have to modify your code.
* The firebird adapter was substantially modified, specifically parts
related to insert returning autogenerated primary key values, so if
you were previously using the adapter you should probably take more
care than usual when testing your upgrade.
* The Dataset::WITH_SUPPORTED constant has been removed.
* The Dataset#supports_cte? method now accepts an optional argument.
If you overrode this method, your overridden method now must
accept an optional argument.
* If you were previously doing:
:x & 1
and wanting "x AND 1", you have to switch to:
:x.sql_boolean & 1
Likewise, if you were previously doing:
:x + 'foo'
and wanting "x + 'foo'", you need to switch to:
:x.sql_number + 'foo'
* Sequel no longer does defensive type checking in the SQL expression
support, as it was often more strict than the database and would
not allow the creation of expressions that were valid for the
database.
---
### Doc Release Notes 3.29.0 (`doc/release_notes/3.29.0.txt`)
= New Adapter Support
* Sequel now has much better support for Oracle, both in the
ruby-oci8-based oracle adapter and in the jdbc/oracle adapter.
* Sequel now has much better support for connecting to HSQLDB
using the jdbc adapter. This support does not work correctly
with the jdbc-hsqldb gem, since the version it uses is too
old. You'll need to load the .jar file manually until the
gem is updated.
* Sequel now has much better support for connecting to Apache
Derby databases using the jdbc adapter. This works with
the jdbc-derby gem, but it's recommend you grab an updated
.jar file as the jdbc-derby gem doesn't currently support
truncate or booleans.
* The db2 adapter has had most of the remaining issues fixed,
and can now run Sequel's test suite cleanly. It's still
recommended that users switch to the ibmdb adapter if they
are connecting to DB2.
* A mock adapter has been added which provides a mock Database
object that allows you to easily set the returned rows, the
number of rows modified by update/delete, and the
autogenerating primary key integer for insert. It also allows
you to set specific columns in the dataset when retrieving
rows. The specs were full of partial implementations of
mock adapters, this mock adapter is much more complete and
offers full support for mocking transactions and database
sharding. Example:
DB = Sequel.mock(:fetch=>{:id=>1}, :numrows=>2, :autoid=>3)
DB[:items].all # => [{:id => 1}]
DB[:items].insert # => 3
DB[:items].insert # => 4
DB[:items].delete # => 2
DB[:items].update(:id=>2) # => 2
DB.sqls # => ['SELECT ...', 'INSERT ...', ...]
In addition to being useful in the specs, the mock adapter is
also used if you use bin/sequel without a database argument,
which makes it much easier to play around with Sequel on the
command line without being tied to a real database.
= New Transaction Features
* Database after_commit and after_rollback hooks have been added,
allowing you to set procs that are called after the currently-
in-effect transaction commits or rolls back. If the Database
is not currently in a transaction, the after_commit proc is
called immediately and the after_rollback proc is ignored.
* Model after_commit, after_rollback, after_destroy_commit, and
after_destroy_rollback hooks have been added that use the new
Database after_commit/after_rollback hook to execute code after
commit or rollback.
* Database#transaction now supports a :rollback => :reraise option
to reraise any Sequel::Rollback exceptions raised by the block.
* Database#transaction now supports a :rollback => :always option
to always rollback the transaction, which is mostly useful when
using transaction-based testing.
* Sequel.transaction has been added, allowing you to run
simultaneous transactions on multiple Database objects:
Sequel.transaction([DB1, DB2]){...}
# similar to:
DB1.transaction{DB2.transaction{...}}
You can combine this with the :rollback => :always option to
easily use multiple databases in the same test suite and make sure
that changes are rolled back on all of them.
* Database#in_transaction? has been added so that users can detect
whether the code is currently inside a transaction.
* The generic JDBC transaction support, used by 6 of Sequel's jdbc
subadapters, now supports savepoints if the underlying JDBC driver
supports savepoints.
= Other New Features
* A dataset_associations plugin has been added, allowing datasets
to call association methods, which return datasets of rows in
the associated table that are associated to rows in the current
dataset.
# Dataset of tracks from albums with name < 'M'
# by artists with name > 'M'
Artist.filter(:name > 'M').albums.filter(:name < 'M').tracks
# SELECT * FROM tracks
# WHERE (tracks.album_id IN (
# SELECT albums.id FROM albums
# WHERE ((albums.artist_id IN (
# SELECT artists.id FROM artists
# WHERE (name > 'M')))
# AND (name < 'M'))))
* Database#extend_datasets has been added, allowing you to do the
equivalent of extending all of the database's future datasets
with a module. For performance, it creates an anonymous
subclass of the current dataset class and includes a module in
it, and uses the subclass to create future datasets.
Using this feature allows you to override any dataset method
and call super, similar to how Sequel::Model plugins work. The
method takes either a module:
Sequel.extension :columns_introspection
DB.extend_datasets(Sequel::ColumnsIntrospection)
or a block that it uses to create an anonymous module:
DB.extend_datasets do
# Always select from table.* instead of *
def from(*tables)
ds = super
if !@opts[:select] || @opts[:select].empty?
ds = ds.select_all(*tables)
end
ds
end
end
* Database#<< and Dataset#<< now return self, which allow them
to be used in chaining:
DB << "UPDATE foo SET bar_id = NULL" << "DROP TABLE bars"
DB[:foo] << {:bar_id=>0} << DB[:bars].select(:id)
* A Database#timezone accessor has been added, allowing you to
override Sequel.database_timezone on a per-Database basis, which
allows you to use two separate Database objects in the same
process that have different timezones.
* You can now modify the type conversion procs on a per-Database
basis when using the mysql, sqlite, and ibmdb adapters, by
modifying the hash returned by Database#conversion_procs.
* Model.dataset_module now accepts a Module instance as an argument,
and extends the model's dataset with that module.
* When using the postgres adapter with the pg driver, you can now
use Database#listen to wait for notifications. All adapters that
connect to postgres now support Database#notify to send
notifications:
# process 1
DB.listen('foo') do |ev, pid, payload|
ev # => 'foo'
notify_pid # => some Integer
payload # => 'bar'
end
# process 2
DB.notify('foo', :payload=>'bar')
* many_to_one associations now have a :qualify option that can be set
to false to not qualify the primary key when loading the
association. This shouldn't be necessary to use in most cases, but
in some cases qualifying a primary key breaks certain queries (e.g.
using JOIN USING on the same column on Oracle).
* Database#schema can now take a dataset as an argument if it just
selects from a single table. If a dataset is provided, the
schema parsing will use that dataset's identifier_input_method
and identifier_output_method for the parsing, instead of the
database's default. This makes it possible for Model classes
to correctly get the table schema if they use a dataset whose
identifier_(input|output)_method differs from the database
default.
* On databases that support common table expressions (CTEs) but do
not support CTE usage in subselects, Sequel now emulates support
by moving CTEs from the subselect to the main select when using
the Dataset from, from_self, with, with_recursive, union,
intersect, and except methods.
* The bitwise compliment operator is now emulated on H2.
* You can now set the convert_tinyint_to_bool setting on a
per-Database basis in the mysql and mysql2 adapters.
* You can now set the convert_invalid_date_time setting on a
per-Database basis in the mysql adapter.
* Database instances now have a dataset_class accessor that allows
you to set which class is used when creating datasets. This is
mostly used to implement the extend_datasets support, but it
could be useful for other purposes.
* Dataset#unused_table_alias now accepts an optional 2nd argument,
which should be an array of additional symbols that should be
considered as already used.
* Dataset#requires_placeholder_type_specifiers? has been added to
check if the dataset requires you use type specifiers for
bound variable placeholders.
The prepared_statements plugin now checks this setting and works
correctly on adapters that set it to true, such as oracle.
* Dataset#recursive_cte_requires_column_aliases? has been added
to check if you must provide a column list for a recursive CTE.
The rcte_tree plugin now checks this setting an works correctly
on databases that set it to true, such as Oracle and HSQLDB.
= Performance Improvements
* Numerous optimizations were made to loading model objects from
the database, resulting in a 7-16% speedup.
Model.call was added, and now .load is just an alias for .call.
This allows you to make the model dataset's row_proc the model
itself, instead of needing a separate block, which improves
performance.
While Model.load used to call .new (and therefore #initialize),
Model.call uses .allocate/#set_values/#after_initialize for speed.
This saves a method call or two, and skips setting the @new
instance variable.
* Dataset#map, #to_hash, #select_map, #select_order_map, and
#select_hash are now faster if any of the provided arguments are
an array of symbols.
* The Model.[] optimization is now applied in more cases.
= Other Improvements
* Sequel now creates accessor methods for all columns in a model's
table, even if the dataset doesn't select the columns. This has
been the specified behavior for a while, but the spec was broken.
This allows you do to:
Model.dataset = DB[:table].select(:column1, :column2)
Model.select_more(:column3).first.column3
* Model.def_dataset_method now correctly handles method names that
can't be used directly (such as method names with spaces). This
isn't so the method can be used with arbitrary user input, but
it will allow safe creation of dataset methods that are derived
from column names, which could contain spaces.
* Model.def_dataset_method no longer overrides private model
methods.
* The optimization that Model.[] uses now works correctly if the
model's dataset uses a different identifier_input_method than
the database.
* Sharding is supported correctly by default for the transactions
used by model objects. Previously, you had to use the sharding
plugin to make sure the same shard was used for transactions as
for the insert/update/delete statements.
* Sequel now fully supports using an aliased table for the
:join_table option of a many_to_many association. The only real
use case for an aliased :join_table option is when the join table
is the same as the associated model table.
* A bug when eagerly loading a many_through_many association with
composite keys where one of the join tables requires an alias
has been fixed.
* Sequel's transaction internals have had substantial improvements.
You can now open up simultaneous transactions on two separate
shards of the same Database object in the same thread. The new
design allows for future support of connection pools that aren't
based on threads. Sequel no longer abuses thread-local variables
to store savepoint state.
* Dataset#select_map and #select_order_map now return an array of
single element arrays if given an array with a single entry as
an argument. Previously, they returned an array of values, which
wasn't consistent.
* Sequel's emulation of bitwise operators with more than 2 arguments
now works on all adapters that use the emulation. The emulation
was broken in 3.28.0 when more than 2 arguments were used on H2,
DB2, Microsoft SQL Server, PostgreSQL, and SQLite.
* Dataset#columns now correctly handles the emulated offset support
used on DB2, Oracle, and Microsoft SQL Server when using the
jdbc, odbc, ado, and dbi adapters. Previously, Dataset#columns
could contain the row number column, which wasn't in the
hashes yielded by Dataset#each.
* Sequel can now parse primary key information on Microsoft SQL
Server. Previously, the only adapter that supported this was the
jdbc adapter, which uses the generic JDBC support. The shared
mssql adapter now supports parsing the information directly from
the database system tables. This means that if you are using
Model objects with a Microsoft SQL Server database using the
tinytds, odbc, or ado adapters, the model primary key
information will be set automatically.
* Sequel's prepared statement support no longer defines singleton
methods on the prepared statement objects.
* StringMethods#like is now case sensitive on SQLite and Microsoft
SQL Server, making it more similar to other databases.
* Sequel now works around an SQLite column naming bug if you select
columns qualified with the alias of a subselect without providing
an alias for the column itself.
* Sequel now handles more bound variable types when using bound
variables outside of prepared statements on SQLite.
* Sequel now works around a bug in certain versions of the
JDBC/SQLite driver when emulating alter table support for
operations such as drop_column.
* Sequel now emulates the add_constraint and drop_constraint
alter table operations on SQLite, though the emulation has
issues.
* Sequel now correctly handles composite primary keys when
emulating alter_table operations on SQLite.
* Sequel now applies the correct PRAGMA statements by default when
connecting to SQLite via the amalgalite and swift adapters.
* Sequel now supports using savepoints inside prepared transactions
on MySQL.
* Sequel now closes JDBC ResultSet objects as soon as it is done
using them, leading to potentially lower memory usage in the JDBC
adapter, and fixes issues if you try to drop a table before
GC has collected a related ResultSet.
* Sequel can now correctly insert all default values into a table
on DB2. Before, this didn't work correctly if the table had more
than one column.
* Another type of disconnection error is now recognized in the
mysql2 adapter.
* Sequel now uses better error messages if you attempt to execute a
prepared statement without a name using the postgres, mysql, and
mysql2 adapters.
* Some small fixes have been made that allow Sequel to run better
when $SAFE=1. However, Sequel is not officially supported using
$SAFE > 0, so there could be many issues remaining.
* Sequel's core and model specs were cleaned up by using the mock
adapter to eliminate a lot of redundant code.
* Sequel's integration tests were sped up considerably, halving
the execution time on some adapters.
= Backwards Compatibility
* Because Model.load is now an alias for .call, plugins should no
longer override load. Instead, they should override .call.
* Loading model objects from the database no longer calls
Model#initialize. Instead, it calls Model.allocate,
Model#set_values, and Model#after_initialize. So if you were
overriding #initialize and expecting the changes to affect model
objects loaded from the database, you need to change your code.
Additionally, @new is no longer set to false for objects retrieved
from the database, since setting it to false hurts performance.
Model#new? still returns true or false, so this only affects you
if you are checking the instance variables directly.
* Dataset#<< no longer returns the autogenerated primary key for the
inserted row. As mentioned above, it now returns self to allow for
chaining. If you were previously relying on the return value,
switch from #<< to #insert.
* Dataset#map no longer calls the row_proc if given an argument, and
Dataset#to_hash no longer calls the row_proc if given two arguments.
This should only affect your code if you were using a row_proc that
modified the content of the hash (e.g. Model#after_initialize). If
you were relying on the old behavior, switch:
dataset.map(:foo)
# to
dataset.map{|r| r[:foo]}
dataset.to_hash(:foo, :bar)
# to
h = {}
dataset.each{|r| h[r[:foo]] = r[:bar]}
h
* Model classes now need to have a dataset before you can define
associations on them.
* Model classes now pass their dataset to Database#schema, instead of
their table name.
* The :eager_block association option (which defaults to the
association's block argument) is now called before the :eager_graph
association option has been applied, instead of after.
* The many_to_many association reflection :qualified_right_key entry
is now a method named qualified_right_key. Switch any
code using association_reflection[:qualified_right_key] to use
association_reflection.qualified_right_key.
* If you are using like on SQLite and Microsoft SQL Server and want
it to be case insensitive, switch to using ilike:
# Case sensitive
DB[:foos].where(:name.like('bar%'))
# Case insensitive
DB[:foos].where(:name.ilike('bar%'))
Sequel now sets the case_sensitive_like PRAGMA to true by default
on SQLite. To set it to false instead, pass the
:case_sensitive_like=>false option to the database when creating it.
* Sequel's alter table emulation on SQLite now renames the current
table then populates the replacement table, instead of
populating the replacement table at a temporary name, dropping
the current table, and then renaming the replacement table.
* The strings 'n' and 'no' (case insensitive) when typecasted to
boolean are now considered false values instead of true.
* The transaction internals had extensive changes, if you have any
code that depended on the transaction internals, it will probably
require changes.
* Using the Sequel::MySQL module settings for convert_tinyint_to_bool
and convert_invalid_date_time now only affects future Database
objects. You should switch to using the per-Database methods
if you are currently using the Sequel::MySQL module methods.
* The customized transaction support in the do (DataObjects) adapter
was removed. All three subadapters (postgres, mysql, sqlite) of
the do adapter implement their own transaction support, so this
should have no effect unless you were using the do adapter with
a different database type.
* The oracle support changed dramatically, so if you were relying
on the internals of the oracle support, you should take extra
care when upgrading.
= Advance Notice
* The next release of Sequel will contain significant changes to
how a dataset is literalized into an SQL string. If you have
a custom plugin, extension, or adapter that overrides a
method containing "literal", "sql", or "quote", or you make
other modifications or extensions to how Sequel currently
literalizes datasets to SQL, your code will likely need to
be modified to support the next release.
---
### Doc Release Notes 3.3.0 (`doc/release_notes/3.3.0.txt`)
New Features
------------
* An association_proxies plugin has been added. This is not a
full-blown proxy implementation, but it allows you to write code
such as:
artist.albums.filter{num_tracks > 10}
Without the plugin, you have to call filter specifically on the
association's dataset:
artist.albums_dataset.filter{num_tracks > 10}
The plugin works by proxying array methods to the array of
associated objects, and all other methods to the association's
dataset. This results in the following behavior:
# Will load the associated objects (unless they are already
# cached), and return the length of the array
artist.albums.length
# Will issue an SQL query with COUNT (even if the association
# is already cached), and return the result
artist.albums.count
* The add_*/remove_*/remove_all_* association methods now take
additional arguments that are passed down to the
_add_*/_remove_*/_remove_all_* methods. One of the things this
allows you to do is update additional columns in join tables for
many_to_many associations:
class Album
many_to_many :artists
def _add_artist(artist, values={})
DB[:albums_artists].
insert(values.merge(:album_id=>id,
:artist_id=>artist.id))
end
end
album = Album[1]
artist1 = Artist[2]
artist2 = Artist[3]
album.add_artist(artist1, :relationship=>'composer')
album.add_artist(artist2, :relationship=>'arranger')
* The JDBC adapter now accepts a :convert_types option to turn off
Java type conversion. The option is true by default for
backwards compatibility and correctness, but can be set to false
to double performance. The option can be set at the database
and dataset levels:
DB = Sequel.jdbc('jdbc:postgresql://host/database',
:convert_types=>false)
DB.convert_types = true
ds = DB[:table]
ds.convert_types = false
* Dataset#from_self now takes an option hash and respects an
:alias option, giving the table alias to use.
* Dataset#unlimited was added, similar to unfiltered and unordered.
* SQL::WindowFunction is now a subclass of SQL::GenericExpression,
so you can alias it and treat it like any other SQL::Function.
Other Improvements
------------------
* Microsoft SQL Server support is much, much better in Sequel 3.3.0
than in previous versions. Support is pretty good with the ODBC,
ADO, and JDBC adapters, close to the level of support for
PostreSQL, MySQL, SQLite, and H2. Improvements are too numerous
to list, but here are some highlights:
* Dataset#insert now returns the primary key (identity field), so
it can be used easier with models.
* Transactions can now use savepoints (except on ADO).
* Offsets are supported when using SQL Server 2005 or 2008, using
a ROW_NUMBER window function. However, you must specify an
order for your dataset (which you probably are already doing if
you are using offsets).
* Schema parsing has been implemented, though it doesn't support
primary key parsing (except on JDBC, since the JDBC support is
used there).
* The SQL syntax Sequel uses is now much more compatible, and
most schema modification methods and database types now work
correctly.
* The ADO and ODBC adapters both work much better now. The ADO
adapter no longer attempts to use transactions, since I've found
that ADO does not give a stable native connection (and hence
transactions weren't possible). I strongly recommend against
using the ADO adapter in production.
* The H2 JDBC subadapter now supports rename_column, set_column_null,
set_column_type, and add_foreign_key.
* Altering a columns type, null status, or default is now supported
on SQLite. You can also add primary keys and unique columns.
* Both the ADO and ODBC adapters now catch the native exception
classes and raise Sequel::DatabaseErrors.
* Model classes now default to associating to other classes in the
same scope. This makes it easier to use namespaced models.
* The schema parser and schema dumper now support the following
types: nchar, nvarchar, ntext, smalldatetime, smallmoney, binary,
and varbinary.
* You can now specify the null status for a column using :allow_null
in addition to :null. This is to make it easier to use the
table creation methods with the results of the schema parser.
* Renaming a NOT NULL column without a default now works on MySQL.
* Model class initialization now raises an exception if there is a
problem connecting to the database.
* Connection pool performance has been increased slightly.
* The literal_time method in the ODBC adapter has been fixed.
* An unlikely but potential bug in the MySQL adapter has been fixed.
Backwards Compatibility
-----------------------
* The convert_tinyint_to_bool setting moved from the main Sequel
module to the Sequel::MySQL module. The native MySQL adapter is
the only adapter that converted tinyint columns to booleans when
the rows are returned, so you can only use the setting with the
native MySQL adapter.
Additionally, the setting's behavior has changed. When parsing
the schema, now only tinyint(1) columns are now considered as
boolean, instead of all tinyint columns. This allows you to use
tinyint(4) columns for storing small integers and tinyint(1)
columns as booleans, and not have the schema parsing support
consider the tinyint(4) columns as booleans. Unfortunately,
due to limitations in the native MySQL driver, all tinyint
column values are converted to booleans upon retrieval, not just
tinyint(1) column values.
Unfortunately, the previous Sequel behavior was to use the
default tinyint size (tinyint(4)) when creating boolean columns
(using the TrueClass or FalseClass generic types). If you were
using the generic type support to create the columns, you should
modify your database to change the column type from tinyint(4) to
tinyint(1).
If you use MySQL with tinyint columns, these changes have the
potential to break applications. Care should be taken when
upgrading if these changes apply to you.
* Model classes now default to associating to other classes in the
same scope. It's highly unlikely anyone was relying on the
previous behavior, but if you have a model inside a module that
you are associating to a model outside of a module, you now need
to specify the associated class using the :class option.
* Model#save no longer includes the primary key fields in the SET
clause of the UPDATE query, only in the WHERE clause. I'm not
sure if this affects backwards compatibility of production code,
but it can break tests that expect specific SQL.
* Behavior to handle empty identifiers has now been standardized.
If any database adapter returns an empty identifier, Sequel will
use 'untitled' as the identifier. This can break backwards
compatibility if the adapter previously used another default and
you were relying on that default. This was necessary to fix any
possible "interning empty string" exceptions.
* On MSSQL, Sequel now uses the datetime type instead of the
timestamp type for generic DateTimes. It now uses bit for the
TrueClass and FalseClass generic types, and image for the File
generic type.
* Sequel now unescapes URL parts:
Sequel.connect(ado:///db?host=server%5cinstance)
However, this can break backward compatibility if you previously
expected it not to be unescaped.
* The columns_for private SQLite Database method has been removed.
---
### Doc Release Notes 3.30.0 (`doc/release_notes/3.30.0.txt`)
= Dataset Literalization Refactoring
* As warned about in the 3.29.0 release notes, dataset literalization
has been completely refactored. It now uses an append-only design
which is faster in all cases, about twice as fast for large objects
and deeply nested structures, and over two orders of magnitude
faster in some pathological cases.
This change should not affect applications, but may affect custom
extensions or adapters that dealt with literalization of objects.
Most literalization methods now have a method with an _append
suffix that does the actual literalization, which takes the sql
string to append to as the first argument. If you were overriding
a literalization method, you now probably need to override the
_append version instead. If you have this literalization method:
def foo_sql(bar)
"BAR #{literal(bar.baz)}"
end
You need to change the code to:
def foo_sql_append(sql, bar)
sql << "BAR "
literal_append(sql, bar.baz)
end
def foo_sql(bar)
sql = ""
foo_sql_append(sql, bar)
sql
end
If you have questions about modifying your custom adapter or
extension, please ask on the Google Group or the IRC channel.
= New Features
* Model#set_server has been added to the base support (it was
previously only in the sharding plugin), which allows you to
set the shard on which to save/delete the model instance:
foo1.set_server(:server_a).save
foo2.set_server(:server_a).destroy
* Model#save now accepts a :server option that uses set_server
to set the shard to use. Unlike most other #save options, this
option persists past the end of the save. Previously, the
:server option only affected the transaction code, it now
affects the INSERT/UPDATE statement as well.
* When initiating a new dataset graph, any existing selected
columns is assumed to be the columns to select for the graph from
the current/master table. Before, there was not a way to specify
the columns to select from the current/master table.
* A :graph_alias_base association option has been added, which is
used to set the base alias name to use when eager graphing. This
is mostly useful when cascading eager graphs to dependent
associations, where multiple associations with the same name in
different models are being graphed simultaneously.
* You can now specify nanoseconds and a timezone offset
when converting a hash or array to a timestamp. The nanoseconds
and offset are the 7th and 8th entries in the array, and the :nanos
and :offset entry in the hash.
* The postgres adapter now respects a :connect_timeout option if you
are using the pg driver.
= Other Improvements
* Type conversion of Java to Ruby types in the JDBC adapter has been
made much faster, as conversion method lookup is now
O(number of columns) instead of
O(number of columns*number of rows).
* Sequel::SQL::Blob literalization is now much faster on adapters that
use hex encoding, by switching to String#unpack('H*').
* Database#after_commit and after_rollback now respect the :server
option to set the server/shard to use.
* Symbol splitting (e.g. for table__column) is now slightly faster.
* All adapters now pass the dataset :limit/:offset value through
Dataset#literal instead of using it verbatim. Note that
Dataset#limit already called to_i on input strings, so this isn't
a security issue. However, the previous code broke if you
provided a Sequel-specific object (e.g. Sequel::SQL::Function) as
the :limit/:offset value.
* Calling graph and eager_graph on an already graphed dataset no
longer modifies the receiver.
* Model#set_server now correctly handles the case where @this is
already loaded.
* Dataset#destroy for model datasets now uses the dataset's shard
for transactions.
* When emulating offset support using ROW_NUMBER (on Microsoft SQL
Server, DB2, and Oracle), explicitly order by the ROW_NUMBER
result, as otherwise the results are not guaranteed to be ordered.
* Explicitly force a case insensitive collation when emulating ILIKE
on Microsoft SQL Server. Previously, ILIKE could be case sensitive
on Microsoft SQL Server if case sensitive collation was the
database default.
* Using on_duplicate_key_update with prepared statements on MySQL now
works correctly.
* The tinytds adapter now works correctly if the
identifier_output_method is nil.
* The plugin/extension specs were cleaned up using the mock adapter.
= Backwards Compatibility
* In addition to the previously mentioned dataset literalization
changes, any custom adapters that overrode *_clause_methods
methods need to be modified to add a method that adds the
SELECT/UPDATE/INSERT/DELETE. Previously, this was done by default,
but due to common table expressions and the dataset literalization
changes, a separate method is now needed.
* Dataset#on_duplicate_key_update_sql has been removed from the shared
mysql adapter.
* The :columns dataset option used when inserting is no longer
literalized in advance.
* Dataset#as_sql no longer takes an expression, it just takes the
alias, and only adds the alias part.
---
### Doc Release Notes 3.31.0 (`doc/release_notes/3.31.0.txt`)
= New Features
* The serialization plugin can now support custom serialization
formats, by supplying a serializer/deserializer pair of
callable objects. You can also register custom deserializers
via Sequel::Plugins::Serialization.register_format, so that
they can be referenced by name. Example:
Sequel::Plugins::Serialization.register_format(:reverse,
lambda{|v| v.reverse},
lambda{|v| v.reverse})
class User < Sequel::Model
serialize_attributes :reverse, :password
end
* Dataset#import and #multi_insert now support a
:return=>:primary_key option. When this option is used, the
methods return an array of primary key values, one for each
inserted row. Usage of this option on MySQL requires that a
separate query be issued per row (instead of the single
query for all rows that MySQL would usually use).
* PostgreSQL can now use Dataset#returning in conjunction with
import/multi_insert to set a custom column to return.
* Microsoft SQL Server can now use Dataset#output in conjunction with
import/multi_insert to set a custom column to return.
* Dataset#import and #multi_insert now respect a :server option to
set the server/shard on which to execute the queries.
Additionally, options given to this method are also passed to
Dataset#transaction.
* Dataset#insert_multiple now returns an array of inserted primary
keys.
* Model.def_column_alias has been added to make it easy to create
alias methods for columns. This is useful if you have a legacy
database and want to create friendly method names for the
underlying columns. Note that this alias only affects the setter
and getter methods. This does not affect the dataset level, so you
still need to use the actual column names in dataset filters.
* many_to_one associations can now have the same name as the related
foreign key column, using the :key_column option. Use of this
feature is not recommended, as it is much better to either rename
the column or rename the association. Here's an example of usage:
# Example schema:
# albums artists
# :id /--> :id
# :artist --/ :name
# :name
class Album < Sequel::Model
def_column_alias(:artist_id, :artist)
many_to_one :artist, :key_column=>:artist
end
* The mock adapter can now mock out database types, by providing a
shared adapter name as the host (e.g. mock://postgres). This
emulation is not perfect, but in most cases it allows you to see
what SQL Sequel would generate on a given database without needing
to install the required database driver.
* Sequel now supports creating full text indexes on Microsoft SQL
Server. Before using it, you must have previously setup a default
full text search catalog, and you need to provide a :key_index
option with an index name symbol.
* Dataset#group_rollup and #group_cube methods have been added for
GROUP BY ROLLUP and GROUP BY CUBE support. These features are in
a recent SQL standard, and they are supported to various degrees on
Microsoft SQL Server, DB2, Oracle, MySQL, and Derby.
* Dataset#full_text_search on Microsoft SQL Server now supports
multiple search terms.
* The jdbc adapter now supports a :login_timeout option, giving the
timeout in seconds.
= Other Improvements
* Dataset#exists can now be used with prepared statement
placeholders.
* Dataset#full_text_search can now be used with prepared statement
placeholders on PostgreSQL, MySQL, and Microsoft SQL Server.
* If tables from two separate schema are detected when parsing the
schema for a table on PostgreSQL, an error is now raised.
Previously, no error was raised, which led to weird errors later,
such as duplicate columns in a model's primary_key.
* RETURNING is now supported with UPDATE/DELETE on PostgreSQL 8.2+.
Previously, Sequel only supported it on 9.1+, but PostgreSQL
introduced support for it in 8.2.
* The shared postgres adapter now correctly handles the return value
for Dataset#insert if you provide a separate column array and value
array on PostgreSQL < 8.2.
* Handle case in the PostgreSQL adapter where the server version
cannot be determined via a query.
* H2 clob types are now treated as string instead of as blob.
Treating clob as blob breaks on H2, as it doesn't automatically
hex-unescape the input for clobs as it does for blobs.
* Dataset#empty? now works correctly when the dataset has an offset
and offset support is being emulated.
* The mock adapter no longer defaults to downcasing identifiers on
output.
= Backwards Compatibility
* Dataset#exists now returns a PlaceholderLiteralString instead of a
LiteralString, which could potentially break some code. If you
would like a String returned, you can pass the returned object to
Dataset#literal:
dataset.literal(dataset.exists)
* Dataset#from no longer handles :a__b__c___d as "a.b.c AS d". This
was not the intended behavior, and nowhere else in Sequel is a
symbol treated that way. Now, Dataset#from is consistent with the
rest of Sequel, using "a.b__c AS d". This should only affect
people in very rare cases, as most databases don't use three level
qualified tables. One exception is Microsoft SQL Server, which can
use three level qualified tables for cross-database access.
* Previously, Dataset#insert_multiple returned an array of hashes, now
it returns an array of primary key values.
* Dataset#EXRACT_CLOSE in the shared sqlite adapter has been renamed to
Dataset#EXTRACT_CLOSE.
* Dataset::StoredProcedureMethods::SQL_QUERY_TYPE and
Dataset::ArgumentMapper::SQL_QUERY_TYPE constants have been removed,
as have related sql_query_type private methods.
* The serialization plugin was significantly refactored.
Model.serialization_map now contains a callable object instead of a
Symbol, and Model.serialization_format has been removed.
Model.define_serialized_attribute_accessors private method now takes
two callable objects before the columns, instead of a single symbol.
---
### Doc Release Notes 3.32.0 (`doc/release_notes/3.32.0.txt`)
= New Features
* Prepared statements now support :map and :to_hash prepared
statement types. The main reason for this is that certain
extensions (e.g. sequel_pg) optimize map/to_hash calls, and
there previously was not a way to use prepared statements
with the map/to_hash optimizations.
* Sequel.empty_array_handle_nulls has been added to change how
IN/NOT IN operations with an empty array are handled. See
the Backwards Compatibility section for details.
* 5 new association options have been added that allow you to
define associations where the underlying columns clash with
standard ruby method names:
many_to_one :primary_key_method
one_to_many :key_method
one_to_many :primary_key_column
many_to_many :left_primary_key_column
many_to_many :right_primary_key_method
Using these new options, you can now define associations
that work correctly when the underlying primary/foreign key
columns clash with existing ruby method names. See the RDoc
for details.
* A use_after_commit_rollback setting has been added to models.
This defaults to true, but can be set to false for performance
or to allow models to be used in prepared transactions
(which don't support after_commit/after_rollback).
* Dataset#update_ignore has been added when connecting to MySQL,
enabling use of the UPDATE IGNORE syntax to skip updating a row
if the update would cause a unique constraint to be violated.
* Database#indexes is now supported when connecting to Microsoft
SQL Server.
* On Microsoft SQL Server, the :include option is now supported
when creating indexes, for storing column values in the index,
which can be used by the query optimizer.
= Other Improvements
* The filtering/excluding by associations code now uses qualified
identifiers instead of unqualified identifiers, which allows it
to avoid ambiguous column names if you are doing your own joins.
* Virtual row blocks that return arrays are now handled correctly
in Dataset#select_map/select_order_map.
* Dataset#select_map/select_order_map can now take both a block
argument as well as a regular argument.
* Dataset#select_order_map now handles virtual row blocks that
return ordered expressions.
* Database#table_exists? should no longer generate false negatives
if you only have permission to retrieve some column values but
not all. Note that if you lack permission to SELECT from the
table itself, table_exists? can still generate false negatives.
* The active_model plugin now supports ActiveModel 3.2, by adding
support for to_partial_path.
* The serialization_modification_detection plugin now handles
changed_columns correctly both for new objects and after saving
objects.
* The serialization plugin now clears the deserialized values when
it does the automatic refresh after saving a new object, mostly for
consistency. You can use the skip_create_refresh plugin to skip
refreshing when creating a new model object.
* Column default values are now wrapped in parentheses on SQLite,
which fixes some cases such as when the default is an SQL function
call.
* Alter table emulation now works correctly on SQLite when foreign
keys reference the table being altered. The emulation requires
a renaming/deleting the existing table and creating a new table,
which can break foreign key references. Sequel now disables the
foreign key PRAGMA when altering tables, so SQLite won't track
the table renames and break the foreign key relationships.
* The set_column_type table alteration method no longer modifies
default values and NULL/NOT NULL settings on Microsoft SQL
Server, H2, and SQLite.
* On MySQL, Time/DateTime columns now use the timestamp type if the
default value is Sequel::CURRENT_TIMESTAMP, since it is currently
impossible for MySQL to have a non-constant default for a
datetime column (without using a workaround like a trigger).
* Metadata methods such as tables, views, and view_exists? are now
handled correctly on Oracle if custom identifier input methods
are used.
* Sequel now ignores errors that occur when attempting to get
information on column defaults in Oracle (which can happen if you
lack permission to the appropriate table). Previously, such errors
would cause the schema parser to raise an error, now, the schema
information is just returned without default information.
* Database#indexes now skips the primary key index when connecting to
DB2, Derby, HSQLDB, and Oracle via the jdbc adapter.
* Database#indexes now works correctly on DB2.
* The progress adapter has been fixed, it had been broken since the
dataset literalization refactoring.
* Dataset#naked! now works correctly. Previously, it just returned
the receiver unmodified.
* Dataset#paginate! has been removed, as it was broken.
* The query extension no longer breaks Dataset#clone if an argument
is not given.
* Transaction related queries are no longer logged twice in the mock
adapter.
= Backwards Compatibility
* Sequel's default handling of NOT IN operators with an empty array
of values has changed, which can change which rows are returned for
such queries.
Previously, Sequel was inconsistent in that it tried to handle NULL
values correctly in the IN case, but not in the NOT IN case. Now,
it defaults to handling NULL values correctly in both cases:
# 3.31.0
DB[:a].where(:b=>[])
# SELECT * FROM a WHERE (b != b)
DB[:a].exclude(:b=>[])
# SELECT * FROM a WHERE (1 = 1)
# 3.32.0
DB[:a].where(:b=>[])
# SELECT * FROM a WHERE (b != b)
DB[:a].exclude(:b=>[])
# SELECT * FROM a WHERE (b = b)
The important change in behavior is that in the NOT IN case, if
the left hand argument is NULL, the filter returns NULL instead
of true. This has the potential to change query results.
"Correct" here is really an opinion and not a fact, as there are
valid arguments for the alternative behavior:
DB[:a].where(:b=>[])
# SELECT * FROM a WHERE (1 = 0)
DB[:a].exclude(:b=>[])
# SELECT * FROM a WHERE (1 = 1)
The difference is that the "correct" NULL behavior is more
consistent with the non-empty array cases. For example, if b is
NULL:
# "Correct" NULL handling
# Empty array: where(:b=>[])
WHERE (b != b) # NULL
WHERE (b = b) # NULL
# Non-empty array: where(:b=>[1, 2])
WHERE (b IN (1, 2)) # NULL
WHERE (b NOT IN (1, 2)) # NULL
# Static boolean handling
# Empty array: where(:b=>[])
WHERE (1 = 0) # false
WHERE (1 = 1) # true
# Non-empty array: where(:b=>[1, 2])
WHERE (b IN (1, 2)) # NULL
WHERE (b NOT IN (1, 2)) # NULL
Sequel chooses to default to behavior consistent with the non-empty
array cases (similar to SQLAlchemy). However, there are two
downsides to this handling. The first is that some databases with
poor optimizers (e.g. MySQL) might do a full table scan with the
default syntax. The second is that the static boolean handling may
be generally preferable, if you believe that IN/NOT IN with an
empty array should always be true or false and never NULL even if
the left hand argument is NULL.
As there really isn't a truly correct answer in this case, Sequel
defaults to the "correct" NULL handling, and allows you to switch
to the static boolean handling via:
Sequel.empty_array_handle_nulls = false
This is currently a global setting, it may be made Database or
Dataset specific later if requested. Also, it is possible the
default will switch in the future, so if you care about a specific
handling, you should set your own default.
* Database#table_exists? now only rescues Sequel::DatabaseErrors
instead of StandardErrors, so it's possible it will raise errors
instead of returning false on custom adapters that don't wrap
their errors correctly.
---
### Doc Release Notes 3.33.0 (`doc/release_notes/3.33.0.txt`)
= New Features
* A server_block extension has been added that makes Sequel's
sharding support easier to use by scoping database access inside
the block to a given server/shard:
Sequel.extension :server_block
DB.extend Sequel::ServerBlock
DB.with_server(:shard_1) do
# All of these will execute against shard_1
DB.tables
DB[:table].all
DB.run 'SOME SQL'
end
* An arbitrary_servers extension has been added that extends
Sequel's sharding support so that you can use arbitrary
connection options instead of referencing an existing, predefined
server/shard:
Sequel.extension :arbitrary_servers
DB.pool.extend Sequel::ArbitraryServers
DB[:table].server(:host=>'foo', :database=>'bar').all
You can use this extension in conjunction with the server_block
extension:
DB.with_server(:host=>'foo', :database=>'bar') do
DB.synchronize do
# All of these will execute on host foo, database bar
DB.tables
DB[:table].all
DB.run 'SOME SQL'
end
end
The combination of these two extensions makes it pretty easy to
write a thread-safe Rack middleware that scopes each request
to an arbitrary database.
* The sqlite adapter now supports an integer_booleans setting
for using 1/0 for true/false values, instead of the the 't'/'f'
values used by default. As SQLite recommends using integers to
store booleans, converting your existing database and enabling
this setting is recommended, but for backwards compatibility it
is set to false. You can convert you existing database by doing
the following for each table/column that has booleans:
DB[:table].update(:boolean_column=>{'t'=>1}.
case(0, :boolean_column))
The integer_booleans default setting may change in a future
version of Sequel, so you should set it manually to false if you
prefer the current default.
* You can now disable transaction use in migrations, in one of two
ways. You generally only need to do this if you are using an
SQL query inside a migration that is specifically not supported
inside a transaction, such as CREATE INDEX CONCURRENTLY on
PostgreSQL.
The first way to disable transactions is on a per-migration basis
by calling the no_transaction method inside the Sequel.migration
block:
Sequel.migration do
no_transaction
change do
# ...
end
end
That will make it so that a transaction is not used for that
particular migration. The second way is passing the
:use_transactions=>false option when calling Migrator.run (using
the API), which will completely disable transactions for all
migrations during the migrator run.
* The postgres adapter now respects an :sslmode option when using
pg as the underlying driver, you can set the value of this option to
disable, allow, prefer, or require.
* Database#create_schema and #drop_schema are now defined when
connecting to PostgreSQL.
* Database#supports_savepoints_in_prepared_transactions? has been
added for checking if savepoints are supported inside prepared
transactions. This is true if both savepoints and prepared
transactions are both supported, except on MySQL > 5.5.12 (due to
MySQL bug 64374).
= Other Improvements
* The mysql and mysql2 adapters now both provide an accurate number
of rows matched, so Sequel::Model usage on those adapters will now
raise a NoExistingObject exception by default if you attempt to
delete or update an instance that no longer exists in the database.
* Foreign key creation now works correctly without specifying the
:key option when using MySQL with the InnoDB table engine. InnoDB
requires that you list the column explicitly, even if you are
referencing the primary key of the table, so if the :key option is
not given, the database schema is introspected to find the primary
key for the table. If you are attempting to create a table with
a self-referential foreign key, it introspects the generator to
get the primary key for the table.
* The sqlite adapter will now return 1/0 stored in boolean columns as
true/false. It will convert dates stored as Integers/Floats to
Date objects by assuming they represent the julian date. It will
convert times stored as Integers/Floats to Sequel::SQLTime objects
by assuming they represent a number of seconds. It will convert
datetimes stored as Integers by assuming they represent a unix
epoch time integer, and datetimes stored as Floats by assuming the
represent the julian date (with fractional part representing the
time of day). These changes make Sequel handle SQLite's
recommendations for boolean/date/time storage.
* The instance_hooks plugin's (before|after)_*_hook methods now return
self so they can be used in a method chain.
* The list plugin now automatically adds new entries to the end of the
list when creating the entries, if the position field is not
specifically set.
* An identifier_output_method is now respected in the mysql2 adapter.
* NaN/Infinity Float values are now quoted correctly for input on
PostgreSQL, and the postgres adapter correctly handles them on
retrieval from the database.
* The :collate column option is now respected when creating tables or
altering columns on MySQL.
* You can now force use of the TimestampMigrator when the
IntegerMigrator would be used by default by calling
TimestampMigrator.apply or .run.
* Mock adapter usage with a specific SQL dialect now uses the
appropriate defaults for quoting identifiers.
* You can now disable the use of sudo in the rake install/uninstall
tasks using the SUDO='' environment variable.
* A very misleading error message has been fixed when attempting
to constantize an invalid string in the model inflector.
= Backwards Compatibility
* The sqlite adapter now typecasts columns that SQLite stores as
INTEGER/REAL. Previously, it only typecasted columns that
SQLite stored as TEXT/BLOB. For details about SQLite storage, see
http://www.sqlite.org/datatype3.html.
Any custom type conversion procs used with the sqlite adapter should
be modified to work with Integer/Float objects in addition to String
objects.
---
### Doc Release Notes 3.34.0 (`doc/release_notes/3.34.0.txt`)
= New PostgreSQL Extensions
* A pg_array extension has been added, supporting PostgreSQL's
numeric and string array types. Both single dimensional and
multi-dimensional array types are supported. Array values are
returned as instances of Sequel::Postgres::PGArray, which is a
delegate class of Array. You can turn an existing array into
a PGArray using Array#pg_array.
If you are using arrays in model objects, you need to load
support for that:
DB.extend Sequel::Postgres::PGArray::DatabaseMethods
This makes schema parsing and typecasting of array columns work
correctly.
This extension also allows you to use PGArray objects and arrays
in bound variables when using the postgres adapter with pg.
* A pg_hstore extension has been added, supporting PostgreSQL's hstore
type, which is a simple hash with string keys and string or NULL
values. hstore values are retrieved as instances of
Sequel::Postgres::HStore, which is a delegate class of Hash. You
can turn an existing hash into an hstore using Hash#hstore.
If you are using hstores in model objects, you need to load
support for that:
DB.extend Sequel::Postgres::HStore::DatabaseMethods
This makes schema parsing and typecasting of hstore columns work
correctly.
This extension also allows you to use HStore objects and hashes
in bound variables when using the postgres adapter with pg.
* A pg_array_ops extension has been added, making it easier to call
PostgreSQL array operators and functions using plain ruby code.
Examples:
a = :array_column.pg_array
a[1] # array_column[1]
a[1][2] # array_column[1][2]
a.push(1) # array_column || 1
a.unshift(1) # 1 || array_column
a.any # ANY(array_column)
a.join # array_to_string(array_column, '', NULL)
If you are also using the pg_array extension, you can turn
a PGArray object into a query object, which allows you to run
operations on array literals:
a = [1, 2].pg_array.op
a.push(3) # ARRAY[1,2] || 3
* A pg_hstore_ops extension has been added, making it easier to call
PostgreSQL hstore operators and functions using plain ruby code.
Examples:
h = :hstore_column.hstore
h['a'] # hstore_column -> 'a'
h.has_key?('a') # hstore_column ? 'a'
h.keys # akeys(hstore_column)
h.to_array # hstore_to_array(hstore_column)
If you are also using the pg_hstore extension, you can turn
an HStore object into a query object, which allows you to run
operations on hstore literals:
h = {'a' => 'b'}.hstore.op
h[a] # '"a"=>"b"'::hstore -> 'a'
* A pg_auto_parameterize extension has been added for automatically
using bound variables for all queries. For example, it can take
code such as:
DB[:table].where(:column=>1)
and do:
SELECT * FROM table WHERE column = $1; -- [1]
Note that automatically parameterizing queries is not generally
faster unless the bound variables are large (i.e. long text/bytea
values). Also, there are multiple corner cases when automatically
parameterizing queries, though most can be worked around by
adding explicit casts.
* A pg_statement_cache extension has been added that works with the
pg_auto_parameterize extension for automatically caching prepared
statements and reusing them when using the postgres adapter with
pg. The combination of these two extensions makes it possible to
take an entire Sequel application and turn most or all of the
queries into prepared statements.
Note that these two extensions do not necessarily improve
performance. For simple queries, they actually hurt performance.
They do help for complex queries, but in all cases, it's faster
to use Sequel's prepared statements API manually.
= Other New Extensions
* A query_literals extension has been added that makes the select,
group, and order methods operate similar to the filter methods in
that if they are given a regular string as their first argument,
they treat it as a literal string, with additional arguments, if
any, used as placeholder values. This extension allows you to
write code such as:
DB[:table].select('a, b, ?' 2).group('a, b').order('c')
# Without query_literals:
# SELECT 'a, b, ?', 2 FROM table GROUP BY 'a, b' ORDER BY 'c'
# With query_literals:
# SELECT a, b, 2 FROM table GROUP BY a, b ORDER BY c
Sequel's default handling in this case is to use literal strings,
which is generally not desired and on some databases not even
valid syntax. In general, you'll probably want to use this
extension for all of a database's datasets, which you can do via:
Sequel.extension :query_literals
DB.extend_datasets(Sequel::QueryLiterals)
The next major version of Sequel (4.0.0) will probably integrate
this extension into the core library.
* A select_remove extension has been added that adds
Dataset#select_remove, for removing selected columns/expressions
from a dataset:
ds = DB[:table]
# Assume table has columns a, b, and c
ds.select_remove(:c)
# SELECT a, b FROM table
# Removal by column alias
ds.select(:a, :b___c, :c___b).select_remove(:c)
# SELECT a, c AS b FROM table
# Removal by expression
ds.select(:a, :b___c, :c___b).select_remove(:c___b)
# SELECT a, b AS c FROM table
This method makes it easier to select all columns except for the
columns given. This is common in cases where a table has a few
large columns that are expensive to retrieve. This method does
have some corner cases, so read the documentation before using it.
* A schema_caching extension has added that makes it possible for
Database instances to dump the cached schema metadata to a
marshalled file, and load the cached schema metadata from the file.
This can be significantly faster than reparsing the schema from the
database, especially for databases with high latency.
bin/sequel -S has been added to dump the schema for the given
database to a file, and DB.load_schema_cache(filename) can be used
to populate the schema cache inside your application. This should
be done after creating the Database object but before loading your
model files.
Note that Sequel does no checking to ensure that the cached schema
currently reflects the state of the database. That is up to the
application.
* A null_dataset extension has been added, which adds
Dataset#nullify for creating a dataset that will not issue a
database query. It implements the null object pattern for
datasets, and is probably most useful in methods that must return
a dataset, but can determine that such a dataset will never return
a row.
= New Plugins
* A static_cache plugin has been added, allowing you to cache a model
statically. This plugin is useful for models whose tables do not
change while the application is running, such as lookup tables.
When using this plugin, the following methods will no longer require
queries:
* Primary key lookups (e.g. Model[1])
* Model.all calls
* Model.each calls
* Model.map calls without an argument
* Model.to_hash calls without an argument
The statically cached model instances are frozen so they are not
accidentally modified.
* A many_to_one_pk_lookup plugin has been added that changes the
many_to_one association retrieval code to do a simple primary
key lookup on the associated class in most cases. This results
in significantly better performance, especially if the
associated model is using a caching plugin (either caching
or static_cache).
= Core Extension Replacements
* Most of Sequel's core extensions now have equivalent methods defined
on the Sequel module:
:column.as(:alias) -> Sequel.as(:column, :alias)
:column.asc -> Sequel.asc(:column)
:column.desc -> Sequel.desc(:column)
:column.cast(Integer) -> Sequel.cast(:column, Integer)
:column.cast_numeric -> Sequel.cast_numeric(:column)
:column.cast_string -> Sequel.cast_string(:column)
:column.extract(:year) -> Sequel.extract(:year, :column)
:column.identifier -> Sequel.identifier(:column)
:column.ilike('A%') -> Sequel.ilike(:column, 'A%')
:column.like('A%') -> Sequel.like(:column, 'A%')
:column.qualify(:table) -> Sequel.qualify(:table, :column)
:column.sql_subscript(1) -> Sequel.subscript(:column, 1)
:function.sql_function(1) -> Sequel.function(:function, 1)
'some SQL'.lit -> Sequel.lit('some SQL')
'string'.to_sequel_blob -> Sequel.blob('string')
{:a=>1}.case(0) -> Sequel.case({:a=>1}, 0)
{:a=>1}.sql_negate -> Sequel.negate(:a=>1)
{:a=>1}.sql_or -> Sequel.or(:a=>1)
[[1, 2]].sql_value_list -> Sequel.value_list([[1, 2]])
[:a, :b].sql_string_join -> Sequel.join([:a, :b])
~{:a=>1} -> Sequel.~(:a=>1)
:a + 1 -> Sequel.+(:a, 1)
:a - 1 -> Sequel.-(:a, 1)
:a * 1 -> Sequel.*(:a, 1)
:a / 1 -> Sequel./(:a, 1)
:a & 1 -> Sequel.&(:a, 1)
:a | 1 -> Sequel.|(:a, 1)
* You can now wrap any object in a Sequel expression using
Sequel.expr. This is similar to the sql_expr extension, but
without defining the sql_expr method on all objects:
1.sql_expr -> Sequel.expr(1)
The sql_expr extension now just has Object#sql_expr call
Sequel.expr.
* Virtual Rows now have methods defined that handle the standard
mathematical operators:
select{|o| o.+(1, :a)} # SELECT (1 + a)
the standard inequality operators:
where{|o| o.>(2, :a)} # WHERE (2 > a)
and the standard boolean operators:
where{|o| o.&({:a=>1}, o.~(:b=>1))} # WHERE ((a = 1) AND (b != 1))
Additionally, there is now direct support for creating literal
strings in instance_evaled virtual row blocks using `:
where{a > `some crazy SQL`} # WHERE (a > some crazy SQL)
This doesn't override Kernel.`, since virtual rows use a BasicObject
subclass. Previously, using ` would result in calling the SQL
function named ` with the given string, which probably isn't valid
syntax on most databases.
* You can now require 'sequel/no_core_ext' to load Sequel without the
core extensions. The previous way of setting the
SEQUEL_NO_CORE_EXTENSIONS constant or environment variable before
loading Sequel still works.
* The core extensions have been moved from Sequel's core library into
an extension that is loadable with Sequel.extension. This extension
is still loaded by default for backwards compatibility. However,
the next major version of Sequel will no longer load this extension
by default (though it will still be available to load manually).
* You can now check if the core extensions have been loaded by using
Sequel.core_extensions?.
= Foreign Keys in the Schema Dumper
* Database#foreign_key_list has been added that gives an array of
foreign key constraints on the table. It is currently implemented
on MySQL, PostgreSQL, and SQLite, and may be implemented on other
database types in the future. Each entry in the return array is
a hash, with at least the following keys present:
:columns :: An array of columns in the given table
:table :: The table referenced by the columns
:key :: An array of columns referenced (in the table specified by
:table), but can be nil on certain adapters if the primary
key is referenced.
The hash may also contain entries for:
:deferrable :: Whether the constraint is deferrable
:name :: The name of the constraint
:on_delete :: The action to take ON DELETE
:on_update :: The action to take ON UPDATE
* The schema_dumper extension now dumps foreign key constraints on
databases that support Database#foreign_key_list. On such
databases, dumping a schema migration will dump the tables in
topological order, such that referenced tables always come before
referencing tables.
In case there is a circular dependency, Sequel breaks the
dependency and adds separate foreign key constraints at the end
of the migration. However, when a circular dependency is broken,
the migration can probably not be migrated down.
Foreign key constraints can also be dumped as a separate migration
using Database#dump_foreign_key_migration, similar to how
Database#dump_indexes_migration works.
* When using bin/sequel -C to copy databases, foreign key constraints
are now copied if the source database supports
Database#foreign_key_list.
= Other New Features
* Dataset#to_hash_groups and #select_hash_groups have been added.
These methods are similar to #to_hash and #select_hash in that they
return a hash, but hashes returned by *_hash_groups methods have
arrays of all matching values, unlike the *_hash methods which
just use the last matching value. Example:
DB[:table].all
# => [{:a=>1, :b=>2}, {:a=>1, :b=>3}, {:a=>2, :b=>4}]
DB[:table].to_hash(:a, :b)
# => {1=>3, 2=>4}
DB[:table].to_hash_groups(:a, :b)
# => {1=>[2, 3], 2=>[4]}
* Model#set_fields and #update_fields now accept :missing=>:skip and
:missing=>:raise options, allowing them to be used in more cases.
:missing=>:skip skips missing entries in the hash, instead of
setting the field to the default hash value. :missing=>:raise
raises an error for missing fields, similar to
strict_param_setting = true. It's recommended that these options
be used in new code in preference to #set_only and #update_only.
* Database#drop_table? has been added, for dropping tables if they
already exist. This uses DROP TABLE IF EXISTS on the databases that
support it. Database#supports_drop_table_if_exists? has been added
for checking whether the database supports that syntax.
* Database#create_join_table has been added that allows easy
creation of many_to_many join tables:
DB.create_join_table(:album_id=>:albums, :artist_id=>:artists)
This uses real foreign keys for both of the columns, uses a
composite primary key of both of the columns, and adds an
additional composite index of the columns in reverse order. The
primary key and additional index should ensure that almost all
operations on the join table can benefit from an index.
In terms of customization, the values in the hash can be hashes
themselves for column specific options, and an additional options
hash can also be given to override some of the default settings.
Database#drop_join_table also exists and takes the same options
as create_join_table. It mostly exists to make it easy to
reverse migrations that use create_join_table.
* Model#freeze has been added that freezes a model such that it
works correctly in a read-only state. Before, it used the standard
Object#freeze, which broke some things that should work, and
allowed changes that shouldn't be allowed (like modifying the
instance's values).
* ConnectionPool#all_connections has been added, which yields each
available connection in the pool to the block. For threaded pools,
it does not yield connections that are currently being used by
other threads. When using this method, it is important to only
operate on the yielded connection objects, and not make any
modifications to the pool itself. The pool is also locked until
the method returns.
* ConnectionPool#after_connect= has been added, allowing you to
change a connection pool's after_connect proc after instantiating
the pool.
* ConnectionPool#disconnection_proc= has been added, allowing you to
change a connection pool's disconnection_proc after instantiating the
pool.
* A Model.cache_anonymous_models accessor has been added, and can be
set to false to disable the caching of classes created by
Sequel::Model(). This caching is only useful if you want to reload
the model's file without getting a superclass mismatch. This
setting is true by default for backwards compatibility, but may be
changed to false in a later version, so you should manually set it to
true if you are using code reloading.
* Model.instance_dataset has been added for getting the dataset used
for model instances (a naked dataset restricted to a single row).
* Dataset#with_sql_delete has been added for running the given SQL
string as a delete and returning the number of rows modified. It's
designed as a replacement for with_sql(sql).delete, which is slower
as it requires cloning the dataset.
* The :on_update and :on_delete entries for foreign_key now accept
string arguments which are used literally.
* Prepared statement objects now have a log_sql accessor that can be
turned on to log the entire SQL statement instead of just the
prepared statement name.
* Dataset#multi_replace has been added on MySQL. This is similar to
multi_insert, but uses REPLACE instead of INSERT.
* Dataset#explain has been added to MySQL. You can use an
:extended=>true option to use EXPLAIN EXTENDED.
* A Database#type_supported? method has been added on PostgreSQL to
check if the database supports the given type:
DB.type_supported?(:hstore)
* Database#reset_conversion_procs has been added to the postgres
adapter, for use by extensions that modify the default conversion
procs and want to have the database use the updated defaults.
* A Database#convert_infinite_timestamps accessor has been added to
the postgres adapter, allowing you to return infinite timestamps as
nil, a string, or a float.
* SQL::PlaceholderLiteralString objects can now use a placeholder
array, where placeholder values are inserted between array elements.
This is about 2.5-3x faster than using a string with ? placeholders,
and allows usage of ? inside the array:
Sequel.lit(["(", " ? ", ")"], 1, 2) # (1 ? 2)
* SQL::Subscript#[] has been added for accessing members of a
multi-dimensional array:
Sequel.subscript(:column, 1)[2][3] # column[1][2][3]
* SQL::Wrapper has been added for wrapping arbitrary objects in a
Sequel expression object.
* SQL::QualifiedIdentifier objects can now contain arbitrary Sequel
expressions. Before, they could only contain a few expression
types. This makes it easier to add extensions to support
PostgreSQL row-valued types.
= Performance Improvements
* Model.[] when called with a primary key has been made about 110%
faster for most models by avoiding cloning datasets.
* Model.[] when called without arguments or with a single nil argument
is much faster as it now returns nil immediately instead of issuing
a database query.
* Model#delete and Model#destroy have been made about 75% faster for
most models by using a static SQL string.
* Model.new is now twice as fast when passed an empty hash.
* Model#set is now four times as fast when passed an empty hash.
* Model#this has been made about 85% faster by reducing the number of
dataset clones needed from 3 to 1.
* Some proc activations have been removed, giving minor speedups when
running on MRI.
= Other Improvements
* Database#uri and #url now return the connection string given
to Sequel.connect. Previously, they tried to reconstruct the
url using the database's options, but that didn't work well in
corner cases.
* Database#inspect now shows the URL and/or options given when
connecting to the database. Previously, it showed the URL, or
all of the databases options if constructing the URL raised an
error.
* Sequel no longer checks for prepared transactions support when
using transactions unless a prepared transaction is specifically
requested.
* The schema utility dataset cached in the Database object is now
reset if you use Database#extend_datasets, ensuring that the new
value will use the given extension.
* The prepared_statements* plugins now log the full SQL by default.
Since the user doesn't choose the name of the prepared statements,
it was often difficult to determine what SQL was actually run if
you were only looking at a subsection of the SQL log.
* The nested_attributes plugin's delete/remove support now works
correctly when a false value is given for _delete/_remove and
strict_param_setting is true.
* The hook_class_methods and validation_class_methods plugins
now work correctly when subclassing if the subclass attempts to
create instances inside Model.inherited.
* The caching plugin has been refactored. Model.cache_get_pk and
cache_delete_pk have been added for retrieving/deleting from the
cache by primary key. Model.cache_key is now a public method.
* The typecast_on_load plugin now works correctly when saving
new model objects when insert_select is supported.
* In the sql_expr extension, nil.sql_expr is no longer treated as
a boolean value. It is now treated as a value with generic type.
* The postgres adapter no longer issues a query to map type names to
type oids if no named conversion procs have been registered.
* The postgres adapter now works around issues in ruby-pg by
supporting fractional seconds for Time/DateTime values, and
supporting SQL::Blob (bytea) values with embedded "\0" characters.
* The postgres adapter now supports pre-defining the PG_NAMED_TYPES
and PG_TYPES constants. This is so extensions can define them,
so they don't have to load the postgres adapter file first. If
extensions need to use these constants, they should do:
PG_NAMED_TYPES = {} unless defined?(PG_NAMED_TYPES)
PG_TYPES = {} unless defined?(PG_TYPES)
That way they work whether they are loaded before or after the
postgres adapter.
* PostgreSQL 8.2-9.0 now correctly add the RETURNING clause when
building queries. Sequel 3.31.0 added support for returning values
from delete/update queries in PostgreSQL 8.2-9.0, but didn't change
the literalization code to use the RETURNING clause on those
versions.
* The jdbc/postgres adapter now converts Java arrays
(Java::OrgPostgresqlJdbc4::Jdbc4Array) to ruby arrays.
* Tables and schemas with embedded ' characters are now handled
correctly when parsing primary keys and sequences on PostgreSQL.
* Identifiers are now escaped on MySQL and SQLite. Previously they
were quoted, but internal ` characters were not doubled.
* Fractional seconds for the time type are now returned correctly on
jdbc (assuming they are returned as java.sql.Time values by JDBC).
* Multiple changes were made to ensure that Sequel works correctly
when the core extensions are not loaded.
* Composite foreign key constraints are now retained when emulating
alter_table operations on SQLite. Previously, only single
foreign key constraints were retained.
* An error is no longer raised when no indexes exist when calling
Database#indexes on jdbc/sqlite.
* A possible SystemStackError has been fixed in the SQLite adapter,
when trying to delete a dataset that uses a having clause and no
where clause.
* ROLLUP/CUBE support now works correctly on Microsoft SQL Server
2005.
* Unsigned tinyint types are now recognized in the schema dumper.
* Using primary_key :column, :type=>Bignum now works correctly on H2.
Previously, the column created was not autoincrementing.
* Using a bound variable for a limit is now supported in the ibmdb
adapter on ruby 1.9.
* Connecting to PostgreSQL via the swift adapter has been fixed when
using newer versions of swift.
* The mock adapter now handles calling the Database#execute methods
directly (instead of via a dataset).
* The mock adapter now has the ability to have per-shared adapter
specific initialization code executed. This has been used to fix
some bugs when using the shared postgres adapter.
* The pretty_table extension has been split into two extensions, one
that adds a method to Dataset and one that just adds the
PrettyTable class. Also, PrettyTable.string has been added to get
a string copy of the table.
* A spec_model_no_assoc task has been added for running model specs
without the association plugin loaded. This is to check that the
SEQUEL_NO_ASSOCIATIONS setting works correctly.
= Deprecated Features to be Removed in Sequel 3.35.0
* Ruby <1.8.7 support is now deprecated.
* PostgreSQL <8.2 support is now deprecated.
* Dataset#disable_insert_returning on PostgreSQL is now deprecated.
Starting in 3.35.0, RETURNING will now always be used to get the
primary key value when inserting.
* Array#all_two_pairs? is now deprecated. It was part of the core
extensions, but the core extensions have been refactored to no
longer require it. As it doesn't specifically relate to creating
Sequel expression objects, it is being removed. The private
Array#sql_expr_if_all_two_pairs method is deprecated as well.
= Other Backwards Compatibility Issues
* The generic Bignum type now uses bigint on SQLite, similar to
other databases. The integer type was previously used. The only
exception is for auto incrementing primary keys, which still use
integer for Bignum as SQLite doesn't support autoincrementing
columns other than integer.
* On SQLite, Dataset#explain now returns a string, similar to
PostgreSQL (and now MySQL).
* When using the JDBC adapter, Java::OrgPostgresqlUtil::PGobject
objects are converted to ruby strings if the dataset is set to
convert types (the default setting). This is to support the
hstore extension, but it could have unforeseen effects if custom
types were used.
* For PostgreSQL connection objects, #primary_key and #sequence now
require their arguments are provided as already literalized
strings. Note that these methods are being removed in the next
version because they will not be needed after PostgreSQL <8.2
support is dropped.
* Database#uri and #url now return a string or nil, but never raise
an exception. Previously, they would either return a string
or raise an exception.
* The Model @simple_pk and @simple_table instance variables should
no longer be modified directly. Instead, the setter methods should
be used.
* Model.primary_key_lookup should no longer be called with a nil
value.
* Logging of prepared statements on some adapters has been changed
slightly, so log parsers might need to be updated.
* Dataset#identifier_append and #table_ref_append no longer treat
literal strings and blobs specially. Previously, they were treated
as identifiers.
* Dataset#qualified_identifier_sql_append now takes 3 arguments, so
any extensions that override it should be modified accordingly.
* Some internally used constants and private methods have been
deleted:
Database::CASCADE
Database::NO_ACTION
Database::SET_DEFAULTS
Database::SET_NULL
Database::RESTRICT
Dataset::COLUMN_ALL
or moved:
MySQL::Dataset::AFFECTED_ROWS_RE -> MySQL::Database
MySQL::Dataset#affected_rows -> MySQL::Database
* The sql_expr extension no longer creates the
Sequel::SQL::GenericComplexExpression class.
---
### Doc Release Notes 3.35.0 (`doc/release_notes/3.35.0.txt`)
= New Features
* A dirty plugin has been added, which saves the initial value of
the column when the column is changed, similar to
ActiveModel::Dirty:
artist.name # => 'Foo'
artist.name = 'Bar'
artist.initial_value(:name) # 'Foo'
artist.column_change(:name) # ['Foo', 'Bar']
artist.column_changes # {:name => ['Foo', 'Bar']}
artist.column_changed?(:name) # true
artist.reset_column(:name)
artist.name # => 'Foo'
artist.column_changed?(:name) # false
artist.update(:name=>'Bar')
artist.column_changes # => {}
artist.previous_changes # => {:name=>['Foo', 'Bar']}
* Database#create_table now respects an :as option to create a
database based on the results of a query. The :as option value
should either be an SQL string or a dataset.
DB.create_table(:new_foos, :as=>DB[:foos].where(:new=>true))
* The json_serializer and xml_serializer plugins can now serialize
arbitrary arrays of model objects by passing an :array option
to the to_json class method. This works around an issue in
ruby's JSON library where Array#to_json does not pass arguments
given to it to the members of the array.
Artist.to_json(:array=>[Artist[1]], :include=>:albums)
* You can now use the % (modulus) operator in the same way you
can use the bitwise operators in Sequel:
:column.sql_number % 1 # (column % 1)
* On PostgreSQL, you can now provide :only, :cascade, and :restart
options to Dataset#truncate to use ONLY, CASCADE, and
RESTART IDENTITY. Additionally, you can now truncate multiple
tables at the same time:
DB.from(:table1, :table2).truncate(:cascade=>true)
* The :index option when creating columns in the schema generator
can now take a hash of index options:
DB.create_table(:foo){Integer :bar, :index=>{:unique=>true}}
* A Database#cache_schema accessor has been added, it can be set
to false to have the Database never cache schema results. This
can be useful in Rails development mode, so that you don't need to
restart a running server to have models pick up the new schema.
* Database#log_exception has been added for easier instrumentation.
It is called with the exception and SQL query string for all
queries that raise an exception.
* The Sequel.migration DSL now has a transaction method that forces
transaction use for the given migration.
= Other Improvements
* Many theoretical thread-safety issues have been fixed for ruby
implementations that don't use a global interpreter lock.
Previously, Sequel relied on MRI's global interpreter lock for
part of its thread safety, now it does manually locking in more
places to avoid thread-safety issues on JRuby (and other ruby
implementations without a global interpreter lock).
No Sequel user ever reported a production error related to the
previous thread-safety issues, and most of the issues fixed
were so difficult to hit that even tests specifically designed
to raise errors were unable to do so.
* Sequel.single_threaded = true now disables the mutex
synchronization that enforces thread safety for additional
performance in single threaded mode.
* Sequel's migrators now only attempt to use transactions by
default if the underlying database supports transactional DDL.
SQLite does support transactional DDL, but Sequel will not
use transactions for SQLite migrations as it causes issues
when emulating alter_table operations for tables with foreign
keys.
* Errors that occur when rolling back database transactions are
now handled correctly. Previously, the underlying exception was
raised, it wasn't correctly wrapped in a Sequel::DatabaseError,
and if it was due to a database disconnection, the connection
wasn't removed from the pool.
* Sequel no longer sets ruby instance variables on java objects,
fixing warnings on JRuby 1.7 and attempting to be forward
compatible with JRuby 2.0.
* Sequel now uses date and timestamp formats that are multilanguage
and not DATEFORMAT dependent on Microsoft SQL Server.
* Sequel now correctly escapes backslash-carriage return-line feed
on Microsoft SQL Server.
* Parsing the column default values in the oracle adapter no longer
requires database superuser privileges.
* Sequel now correctly handles parsing schema for tables in other
databases on MySQL. Previously, it would always look in the
current database.
* Sequel no longer doubles backslashes in strings by default. It
now only does so on MySQL, since that is the only database that
appears to use backslashes for escaping. This fixes issues with
backslashes being doubled on some of the less commonly used
adapters.
* The pg_auto_parameterize extension now works correctly when
using cursors.
* Dataset#truncate now raises an Error if you attempt to do so
on a dataset that uses HAVING. Previously, it only checked for
WHERE.
* The schema dumper now recognized the identity type.
= Backwards Compatibility
* Association reflections now store cached information in a
separate subhash due to the thread-safety changes. Any code
accessing an association reflection should always call the
related method to get the cached data instead of checking
for a specific location in the hash.
* Association reflection internals for many_through_many associations
changed significantly, any code that accesses the edge information
in the reflection will need to be changed to use the new methods
instead of accessing the old values directly.
* The features deprecated in 3.34.0 have now been removed:
* Ruby <1.8.7 support
* PostgreSQL <8.2 support
* Dataset#disable_insert_returning on PostgreSQL
* Array#all_two_pairs? and #sql_expr_if_all_two_pairs
---
### Doc Release Notes 3.36.0 (`doc/release_notes/3.36.0.txt`)
= New Features
* An eager_each plugin has been added, which automatically makes
eagerly loaded datasets do eager loading if you call #each (or
another Enumerable method) instead of #all. By default, if you
call #each on an eager dataset, it will not do eager loading,
and if you call #each on an eager_graph dataset, you will
get plain hashes with columns from all joined tables instead of
model objects. With this plugin, #each on both eager and
eager_graph datasets will do eager loading.
* The nested attributes plugin now supports composite primary keys
in associated records. Additionally, it now deals better with
natural primary keys in associated records. There is a new
:unmatched_pk option that can be set to :create if you want to
create new associated records when the input hash contains
primary key information that doesn't match one of the existing
associated objects.
The nested attributes plugin now also supports a :transform option.
If given, this option is called with the parent object and the
input hash given for each associated record passed into the
nested attributes setter. The callable should return the hash
of attributes to use.
* Model#from_json in the json_serializer plugin now takes an options
hash and recognizes the :fields option. If the :fields option is
given, it should be an array of field names, and set_fields is
called with the array instead of using set. This allows you to
easily filter which fields in the hash are set in the model
instance. The entire options hash is also passed to set_fields
if :fields is present, so you can additionally use the :missing =>
:raise or :missing => :skip options that set_fields supports.
* The Dataset#to_json method in the json_serializer plugin now
respects :root=>:collection and :root=>:instance options. If
:root=>:collection is given, only the collection is wrapped in a
hash, and if :root=>:instance is given, only the instances are
wrapped in a hash. For backwards compatibility, both the
instances and collection are wrapped in a hash:
Model.to_json(:root=>true)
# {"models":[{"model":{"id":1}}]}
Model.to_json(:root=>:collection)
# {"models":[{"id":1}]}
Model.to_json(:root=>:instance)
# [{"model":{"id":1}}]
Wrapping both the collection and instance in a root by default
is probably an undesired behavior, so the default for :root=>true
may change in the next major version of Sequel. Users who want
the current behavior should switch to using :root=>:both.
* The schema_dumper extension now respects an :index_names option
when dumping. This option can be set to false to never dump the
index names. It can also be set to :namespace, in which case if
the database does not have a global index namespace, it will
automatically prefix the name of the index with the name of the
table.
Database#global_index_namespace? was added to check if the
database uses a global index namespace. If false, index names are
probably namespaced per table (MySQL, MSSQL, Oracle).
* :each is now a valid prepared statement type. This prepared
statement type requires a block when you call the statement, and
iterates over the records of the statement a row at a time.
Previously, there wasn't a way to iterate over the records of a
prepared statement a row at a time, since the :select and :all
types collect all rows into an array before iterating over them.
* A :connection_handling=>:queue option is now respected for
database objects, and changes the threaded connection pools to use
a queue instead of a stack as the data structure for storing
available connections. A queue does not perform as well as a
stack, but reduces the likelihood of stale connections.
It is possible that Sequel will change in the future from using a
stack by default to using a queue by default, so any users who
specifically desire a stack to be used should specify the
:connection_handling=>:stack option.
* Sequel::Migrator now supports is_current? class method to check
if there are no outstanding migrations to apply. It also supports
a check_current class method, which raises an exception if there
are outstanding migrations to apply.
* A pg_json extension has been added, supporting PostgreSQL's 9.2
json type, similarly to the pg_array and pg_hstore extensions.
Note that with the current PostgreSQL json code, the root object
can be a string or number, but ruby's json library requires the
root json value to be an object or array. So you will probably
get an exception if you attempt to retrieve a PostgreSQL json
value that ruby's JSON library won't parse.
* A pg_inet extension has been added, which automatically typecasts
PostgreSQL inet and cidr types to ruby IPAddr objects on retrieval.
* Database#transaction on PostgreSQL now recognizes :read_only and
:deferrable options, and can use them to set the READ ONLY and
DEFERRABLE transaction flags. A :synchronous option is also
recognized, which can be set to true, false, :local, or
:remote_write, and sets the value of synchronous_commit just for
that transaction.
* When adding and dropping indexes on PostgreSQL, a :concurrently
option can be used to create or drop the index CONCURRENTLY, which
doesn't require a full write table lock.
* When dropping indexes on PostgreSQL, :if_exists and :cascade options
are now recognized.
* When using alter_table set_column_type on PostgreSQL, the :using
option is respected, and can be used to force a specific conversion
from the previous value to the new value with the USING syntax.
* On MySQL, you can now set an :sql_mode option when connecting. This
can be a string or symbol or an array of them, and each should match
one of MySQL's sql_modes. MySQL's default SQL mode is fairly loose,
and using one of the strict sql modes is recommended, but for
backwards compatibility, Sequel will not set a specific SQL mode by
default. However, that may change in the next major version of
Sequel, so to be forwards compatible you should set :sql_mode=>nil
if you do not desire a strict SQL mode to be set automatically.
* Partial indexes are now supported on Microsoft SQL Server 2008
(SQL Server refers to them as filtered indexes). Attempting to
use a partial index on an earlier version of SQL Server will
result in the database raising an exception.
* A jdbc/progress adapter has been added, supporting the Progress
database via the jdbc adapter.
= Other Improvements
* Dataset#get now works correctly if you pass it a nil or false
argument. Previously, it ignored the argument and used the block
instead. If you want to use the block argument, you should not
pass in a regular argument.
* Database#call now passes any blocks given to it to the underlying
prepared statement object. Before, a passed block was ignored.
* Sequel::Model.db is no longer set automatically when creating
an anonymous class with an associated database object. This fixes
cases where a library would create namespaced models, and the
database used by the library would be set as the default for the
user's application code.
* Model *_to_one association setters are now no-ops if you pass a
value that is the same as the cached value. This fixes issues with
reciprocal associations getting reordered, and is better
for performance.
For cases where the old behavior is desired, the
set_associated_object_if_same? method can be overridden to return
true for object. If you are manually setting objects in the
associations cache before calling the setter method, you may want
to set that.
* The dirty plugin no longer affects the return value of refresh
and lock!. Internal changes should now help ensure that plugins
don't affect the return values of these methods.
* Sequel now supports JRuby 1.7's new exception handling, fixing
exception handling when connecting in the jdbc adapter.
* When dumping unsigned integer types in the schema dumper, if the
unsigned values could overflow a 32-bit signed integer type,
the generic Bignum class is used as the type. This should fix
issues when copying a database containing an unsigned 32-bit
integer column with values between 2^31 and 2^32-1.
* In the optimistic_locking plugin, attempting to refresh and
save after a failed save now works correctly. Before, the second
save would never modify a row.
* Time types on jdbc/postgres are now typecasted accurately on
retrieval, before they could be off by up to a millisecond due to
floating point issues.
* Disconnect detection in the mysql2 adapter has been improved.
* The jdbc/mysql, do/mysql, and swift/mysql adapters all now support
the :timeout option to set the MySQL wait_timeout.
* Savepoints in prepared transactions are now supported on MySQL
5.5.23+, since the bug that caused them to be unsupported starting
in 5.5.13 has been fixed.
* Parsing foreign key metadata for tables with an explicit
schema now works correctly on PostgreSQL.
* bin/sequel -C now namespaces indexes automatically when copying
from a database without a global index namespace to a database
with a global index namespace.
* Indexes are now dropped in reverse order that they were added in
the schema_dumper.
* The Model typecasting code works around bugs in objects where
object.==('') would raise an exception instead of returning false.
* A better error message is used if an invalid JDBC URL is
provided and the JDBC driver's new.connect method returns NULL.
* A document describing Sequel's object model has been added,
describing the objects Sequel uses to represent SQL concepts.
* Most adapter specific options to Database methods are now mentioned
in the main Database method RDoc.
= Backwards Compatibility
* The nested_attributes plugin internals changed significantly. If
you were overriding one of the nested_attributes* private methods
and calling super to get the default behavior, you may have to
update your code.
* Database#case_sensitive_like has been removed on SQLite. This
method never worked correctly, it always returned false even if
the case_sensitive_like PRAGMA was set. That's because SQLite
doesn't offer a getter for this PRAGMA, only a setter. Note that
Database#case_sensitive_like= still exists and works correctly.
* Database#single_value has been removed from the native SQLite
adapter. This method was designed for internal use, and hasn't
been used for some time. Any current users of the method should
switch to Dataset#single_value.
* The private Database#defined_columns_for method in the SQLite
adapter no longer takes an options hash.
* A couple jdbc/postgres adapter methods are now private. Previously,
the jdbc/postgres adapter overrode some private superclass methods
but left the methods public.
* When using the optimistic_locking plugin, refreshing inside a
before_update method after calling super will now result in the
lock checking being skipped.
* The private Model#_refresh no longer returns self, so external
plugins should no longer rely on that behavior.
---
### Doc Release Notes 3.37.0 (`doc/release_notes/3.37.0.txt`)
= New Features
* Database#extension and Dataset#extension have been added and
make it much easier to use extensions that just define modules,
where you previously had to manually extend a Database or
Dataset object with the module to get the extension's behavior.
These methods operate similarly to model plugins, where you just
specify the extension symbol, except that you can specify multiple
extensions at once:
DB.extension(:pg_array, :pg_hstore)
For databases, these modify the Database itself (and
potentially all of its datasets). Dataset#extension operates
like other dataset methods, returning a modified clone of
the dataset with the extension added:
dataset = dataset.extension(:columns_introspection)
Dataset#extension! has also been added for modifying the
receiver instead of returning a clone.
Not all extensions are usable by Database#extension or
Dataset#extension, the extension has to have specific support
for it. The following extensions support both
Database#extension and Dataset#extension:
* columns_introspection
* query_literals
* split_array_nil
The following extensions support just Database#extension:
* arbitrary_servers
* looser_typecasting
* pg_array
* pg_auto_parameterize
* pg_hstore
* pg_inet
* pg_interval
* pg_json
* pg_range
* pg_statement_cache
* server_block
Any user that was loading these extensions with Sequel.extension
and then manually extending objects with the extension's module
is encouraged to switch to Database#extension and/or
Dataset#extension.
* Dataset join methods now respect a :qualify=>:deep option
to do deep qualification of expressions, allowing qualification
of subexpressions in the expression tree. This can allow you
to do things like:
DB[:a].join(:b, {:c.cast(Integer)=>:d.cast(Integer)},
:qualify=>:deep)
# SELECT * FROM a INNER JOIN b
# ON (CAST(b.c AS INTEGER) = CAST(a.d AS INTEGER))
For backwards compatibility, by default Sequel will only do
automatic qualification if the arguments are simple symbols.
This may change in a future version, if automatic qualification
of only symbols is desired, switch to using :qualify=>:symbol.
You can also choose to do no automatic qualification using the
:qualify=>false option.
* All of Sequel's model associations now work with key expressions
that are not simple column references, without creating a fully
custom association. So you can create associations where the
primary/foreign key values are stored in PostgreSQL array or
hstore columns, for example.
* The pg_array extension has now been made more generic, so that it
is easy to support array types for any scalar type that is
currently supported. All scalar types that Sequel's postgres
adapter supports now have corresponding array types supported in
the pg_array extension. So if you load the pg_array extension and
return a date array column, the returned values will be arrays of
ruby Date objects.
Other pg_* extensions that add support for PostgreSQL-specific
scalar types now support array versions of those types if the
pg_array extension is loaded first.
* A pg_range extension has been added, making it easy to deal
with PostgreSQL 9.2+'s range types. As ruby's Range class does
not support all PostgreSQL range type values (such as empty ranges,
unbounded ranges, or ranges with an exclusive beginning), range
types are returned as instances of Sequel::Postgres::PGRange, which
has an API similar to Range. You can turn a PGRange into a Range
using PGRange#to_range, assuming that the range type value does not
use features that are incompatible with ruby's Range class.
The pg_range extension supports all range types supported by
default in PostgreSQL 9.2, and makes it easy to support custom
range types.
* A pg_range_ops extension has been added, which adds DSL support for
PostgreSQL range operators and functions, similar to the
pg_array_ops and pg_hstore_ops extensions.
* A pg_interval extension has been added, which makes Sequel return
PostgreSQL interval types as instances of ActiveSupport::Duration.
This is useful if you want to take the interval value and use it in
calculations in ruby (assuming you load the appropriate parts of
ActiveSupport).
* A split_array_nil extension has been added, which changes how Sequel
compiles IN/NOT IN expressions with arrays with nil values.
where(:col=>[1, nil])
# Default:
# WHERE (col IN (1, NULL))
# with split_array_nil extension:
# WHERE ((col IN (1)) OR (col IS NULL))
exclude(:col=>[1, nil])
# Default:
# WHERE (col NOT IN (1, NULL))
# with split_array_nil extension:
# WHERE ((col NOT IN (1)) AND (col IS NOT NULL))
* The nested_attributes plugin now allows the :fields option to
be a proc, which is called with the associated object and should
return an array of allowable fields.
* You can now specify the graph alias base when using eager_graph on
a per-call basis. Previously, it could only be set on a per
association basis. This is helpful if you have multiple
associations to the same class, and are cascading the eager graph to
dependent associations of that class for both of the associations.
Previously, there was no way to manually give descriptive names to
the tables in the cascaded associations, but you can now do so
by passing the association as an Sequel::SQL::AliasedExpression
instance instead of a plain Symbol. Here's a usage example:
ds = Game.eager_graph(:winner=>:players.as(:winning_players),
:loser=>:players.as(:losing_players)).
where(:winning_players__name=>'A',
:losing_players__name=>'B')
* many_through_many associations now differentiate between column
references and method references, by supporting the
:left_primary_key_column and :right_primary_key_method options that
many_to_many associations support.
* Custom :eager_loader procs that accept a single hash argument now
have an additional entry passed in the hash, :id_map, which is
easier to use than the :key_hash entry (which is still present for
backwards compatibility). Anyone with custom :eager_loader procs is
encouraged to switch from using :key_hash to :id_map.
* You can now override the create_table/alter_table schema generators
per database/adapter. This allows for database specific generator
subclasses, which have methods for unique features for that
database.
* You can now setup exclusion constraints on PostgreSQL using the
create_table and alter_table schema generators:
DB.create_table(:t) do
...
exclude([[:col1, '&&'], [:col2, '=']])
# EXCLUDE USING gist (col1 WITH &&, col2 WITH =)
end
One common use for exclusion constraints is to make sure that no two
rows have overlapping values/ranges/circles.
* When adding foreign key constraints to an existing table on
PostgreSQL, you can use the :not_valid option to mark the constraint
as not yet valid. This will make it so that future changes to the
table need to respect the foreign key constraint, but existing rows
do not. After cleaning up the existing data, you can then use the
alter_table validate_constraint method to mark the constraint as
valid.
* An eval_inspect extension has been added that attempts to do
do the following for Sequel::SQL::Expression instances:
eval(obj.inspect) == obj # => true
There are a lot of cases that this extension does not handle, but
it does a decent job in most cases. This is currently only used
internally in a specific case in the schema_dumper extension.
= Other Improvements
* The filter by associations support now respects the method
reference vs column reference distinction that other parts of the
association code have respected since 3.32.0.
* In the nested_attributes plugin, new one_to_one associated
values are saved once instead of twice. Previously it attempted to
save them before they were associated to the current model object,
which can violate some validations/constraints.
* When saving an associated object in the one_to_one association
setter method, Sequel no longer adds an unnecessary filter
condition when nullifying the foreign key for existing rows
in the associated table.
* The list plugin's before_create method now calls super, which
fixes usage when other plugins that define before_create are loaded
before it.
* In the pg_array extension, when typecasting an Array to PGArray,
a recursive map is done on the input array to convert each value
in the input array to the expected type, using the typecasting
method that would be used for the scalar value. For example, for
model objects, where ids is an integer array column:
model.set(:ids=>['1', '2']).ids.to_a # => [1, 2]
* The pg_array extension now correctly handles bytea arrays used
in bound variables.
* The pg_array extension no longer uses the JSON-based parser for
floating point types, since it doesn't handle NaN and Infinity
values correctly.
* When typecasting in the pg_array extension, PGArray values are
only returned verbatim if they have a matching database type.
Otherwise, the underlying array is rewrapped in a new PGArray
value with the correct database type.
* H2 clob types are now recognized as strings instead of blobs.
Previously the code attempted to do this, but it didn't do so
correctly.
* The jdbc/postgres adapter now converts scalar values of
the array to the appropriate type. Previously, if you retrieved
a date array, you got back a ruby array of JavaSQL::SQL::Date
instances. Now, you get back a ruby array of ruby Date instances.
* The schema_dumper extension now dumps migrations as change
migrations, instead of separate up/down migrations, resulting in
simpler code.
* When dumping non-integer foreign keys in the schema dumper, an
explicit type is now used. Previously, the column would have been
dumped as an integer column.
* When dumping unsigned integer columns in the schema dumper, add a
column > 0 constraint in the dumped migration.
* On Microsoft SQL Server, when updating a dataset with a limit,
the limit is now respected.
* When emulating offset using the ROW_NUMBER window function,
do not require that the dataset be ordered. If an order is
not provided, default to ordering on all of the columns in
the dataset. If you want to override the default order used
in such a case, you need to override the default_offset_order
method for the dataset.
* On SQLite, casting to Date/Time/DateTime now calls an SQLite
date/datetime function instead of using a cast, as SQLite treats
such a cast as a cast to integer.
* When using JRuby 1.6 in ruby 1.9 mode and typecasting a time
column, workaround a bug where Time#nsec is 0 even though
Time#usec is not.
* The odbc/mssql adapter now correctly handles the case where
SCOPE_IDENTITY returns NULL after an insert.
* bin/sequel now accepts multiple -l options for logging to multiple
output files.
* In addition to Sequel's rigorous pre-push testing, Sequel now
also uses TravisCI for continuous integration testing across
a wider range of ruby implementations.
= Backwards Compatibility
* The keys in the :key_hash entry passed to the :eager_loader proc
are now method references instead of column references. For most
associations, they are the same thing, but for associations using
the :key_column/:primary_key_column/:left_primary_key_column
options, the values could be different. If you were using one
of those options and had a custom eager_loader, you should switch
from indexing into the :key_hash option to just using the :id_map
option.
* The :key_hash entry passed to the :eager_loader proc is now no
longer guaranteed to contain key maps for associations other than
the one currently being eagerly loaded. Previously, it contained
key maps for all associations that were being eagerly loaded. If
you have a custom :eager_loader proc that accessed a key map for
a separate association that was being loaded concurrently, you'll
now have to build the key map manually if it doesn't exist.
* If you previously explicitly specified an :eager_loader_key option
when defining an association, you may need to change it so that it
is a method reference instead of a column reference, or possibly
just omit the option.
* If you have a custom :eager_loader proc for an association where
the default :eager_loader_key option references a method that
the model does not respond to (or raises an exception), you may
need to specify the :eager_loader_key=>nil option.
* In the pg_auto_parameterize extension, String values are no longer
automatically casted to text. This is because the default type of
a string literal in PostgreSQL is unknown, not text. This makes it
much less likely to require manual casts, but has the potential to
break existing code relying on the automatic cast to text. As a
work around, any query that can no longer be automatically
parameterized after this query just needs to add manual casting
to text.
* Sequel now raises an exception if you attempt to clone associations
with different types, except if one type is one_to_many and the
other is one_to_one. Cloning from other types was usually a bug,
and raising an exception early will make it much easier to track
such bugs down.
* When running the plugin/extension and PostgreSQL adapter specs,
a json library is now required.
* The json/postgres adapter array typecasting internals have been
modified, if you were relying on the internals, you may need to
update your code.
* The pg_array extension internals changed significantly. PGArray
no longer has any subclasses by default, as parsing is now done
in separate objects. Anyone relying on the pg_array internals
will need to update their code.
* The postgres adapter no longer sets up type conversion of int2vector
and money types, since in both cases the conversion was incorrect in
most cases. These types will now be returned as strings. If you are
relying on the conversion, you'll need to add your own custom type
procs.
---
### Doc Release Notes 3.38.0 (`doc/release_notes/3.38.0.txt`)
= New Features
* A pg_row extension has been added that supports PostgreSQL's
row-valued/composite types. You can register support for
specific row types:
DB.register_row_type(:address)
Then you can create values of that row type:
ad = DB.row_type(:address, ['555 Foo St.', 'Bar City', '98765'])
# or
ad = DB.row_type(:address, :street=>'555 Foo St.',
:city=>'Bar City', :zip=>'98765')
Which you can use in your datasets:
DB[:people].insert(:name=>'Me', :address=>ad)
If you are using the native postgres adapter, when retrieving
row type values, they will be returned as instances of the row
type, which are hash-like objects:
ad = DB[:people].get(:address)
ad[:street] # => '555 Foo St.'
ad[:city] # => 'Bar City'
ad[:zip] # => '98765'
If you are also using the pg_array extension, then arrays of
composite types are supported automatically. Composite
types can also include arrays of other types as well as other
composite types, though recursive composite types are not
allowed by PostgreSQL.
Using arrays and composite types brings one of the benefits
of document databases to PostgreSQL, allowing you to store
nested structures inside a single row.
* A pg_row_ops extension has been added that adds DSL support
for accessing members of row-valued/composite types. You
first create a row op:
r = Sequel.pg_row_op(:row_column)
Then you can get DSL support for accessing members of that
row_column via the #[] method:
r[:a] # (row_column).a
This works with composite types containing composite types:
r[:a][:b] # ((row_column).a).b
When used in conjunction with the pg_array_ops extension,
there is support for composite types that include arrays,
as well as arrays of composite types:
r[1][:a] # (row_column[1]).a
r[:a][1] # (row_column).a[1]
The extension offers additional support for referencing
a table's type when it contains a column with the same
name, see the RDoc for details.
* A pg_row plugin has been added, that works with the pg_row
extension, and allows you to represent row-valued types as
Sequel::Model objects (instead of the hash-like objects
they use by default). In your model class, you load the
plugin:
class Address < Sequel::Model(:address)
plugin :pg_row
end
Then you can use Address instances in your datasets:
ad = Address.new(:street=>'555 Foo St.',
:city=>'Bar City', :zip=>'98765')
DB[:people].insert(:name=>'Me', :address=>ad)
And if you are using the native postgres adapter, the dataset
will return the type as a model instance:
ad = DB[:people].get(:address)
ad.street # => '555 Foo St.'
ad.city # => 'Bar City'
ad.zip # => '98765'
* A pg_typecast_on_load plugin has been added. This plugin is
designed for use with the jdbc/postgres, do/postgres, and
swift/postgres adapters, and it is similar to the
typecast_on_load plugin. However, while the typecast_on_load
plugin uses setter methods, the pg_typecast_on_load plugin
uses the same code that the native postgres adapter uses for
typecasting.
* The tinytds adapter now supports a :textsize option to override
the default TEXTSIZE setting. The FreeTDS default is fairly
small (~64k), so if you want to use large blob or text columns,
you should probably set this to a value larger than the
largest text/blob you want to use.
* Sequel.expr when called with a symbol now splits the symbol and
returns an Identifier, QualifiedIdentifier, or AliasedExpression,
depending on the content of the symbol. Previously, it only
wrapped the symbol using a Wrapper.
* Identifier#* and QualifiedIdentifier#* when called without any
argument now represent a selection of all columns from the
represented table:
Sequel.expr(:table).* # table.*
Sequel.expr(:schema__table).* # schema.table.*
This makes it easier to represent the selection of all columns
in a table without using the core extensions.
* Model#values now has a Model#to_hash alias.
* SQL::Blob values now have as, cast, and lit methods even if the
core extensions are not loaded.
= Other Improvements
* When loading multiple pg_* extensions into a Database instance,
the conversion procs are only reset once instead of once per
extension.
* All adapters that access PostgreSQL now store type conversion
procs, similar to the native postgres adapter. This has been
added to make it easier to write extensions that support
advanced PostgreSQL types.
* Database#schema output on PostgreSQL now includes the type oid
for each column.
* You can now register custom array types to specific Database
instances, using the :type_procs and :typecast_methods_module
options, so it is now possible to have custom array types
without affecting global state.
* Dropping of columns with defaults now works correctly on
Microsoft SQL Server. Before, it would fail as the related
constraint was not dropped first.
* The MySQL type "double(x,y)" is now recognized as a float type.
* The jdbc/jtds and jdbc/derby adapters now handle nil prepared
statement values in more cases.
* Blob prepared statement arguments are now handled correctly on
jdbc/db2 and jdbc/oracle.
* Sequel now works around a Time#nsec bug in JRuby 1.6 ruby 1.9 mode
when using Time values in prepared statements in the jdbc adapter.
* Java::JavaUtil::UUID types are now returned as ruby strings
when converting types in the jdbc adapter.
* Real boolean literals are now used on derby 10.7+. On derby <10.7
Sequel still uses (1 = 1) and (1 != 1) for true and false. This
allows you to use boolean columns with a true/false default on
derby 10.7+.
* Clobs are now treated as string types instead of blobs on derby,
since treating clob as blob doesn't work there.
* The swift adapter now supports an output identifier method.
* The swift adapter now returns blobs as SQL::Blob instances.
* The schema_dumper extension no longer produces code that requires
the core extensions.
* All of Sequel's specs now run without the core extensions loaded,
ensuring that none of the internals depend on the core extensions.
The only exception is the specs for the core extensions themselves.
= Backwards Compatibility
* The pg_* extensions no longer modify core classes if the
core_extensions extension is not loaded. All methods they added now
have equivalent methods on the main Sequel module:
Sequel.pg_array
Sequel.pg_array_op
Sequel.hstore
Sequel.hstore_op
Sequel.pg_json
Sequel.pg_range
Sequel.pg_range_op
* The Sequel::SQL::IdentifierMethods module has been removed. This
module was only included in Symbol if the core_extensions were
enabled. Since it only defined a single method, now the core
extensions just define that method directly on Symbol.
* The swift adapter now requires swift-db-{postgres,mysql,sqlite3}
gems instead of the swift gem. swift/postgres requires
swift-db-postgres 0.2.0+, swift/sqlite requires swift-db-sqlite
0.1.2+, and swift/mysql requires swift-db-mysql.
* Sequel will no longer typecast a string to a PostgreSQL array
or hstore column in a model column setter. This is because the
parsers that Sequel uses were designed to support only
PostgreSQL's output format. It's unlikely that a user would
provide that format for typecasting, and while there aren't known
security issues with the parsers, they were not designed to handle
arbitrary user input, so typecasting from string is no longer
allowed and will now raise an error.
The only reason such typecasting was allowed in the first place
was to work around issues in the jdbc/postgres, do/postgres, and
swift/postgres adapters, using the the typecast_on_load plugin.
If you were previously using the typecast_on_load plugin for
hstore or array columns, you need to switch to using the new
pg_typecast_on_load plugin.
* The private get_conversion_procs method in the postgres adapter
no longer accepts an argument.
* The Sequel::Postgres::PGArray::DatabaseMethods singleton
define_array_typecast_method method has been removed. This
method was designed for internal use.
* The change to make Sequel.expr split symbols can cause the
following type of code to break:
Sequel.expr(:column___alias).desc
This is because expr now returns an AliasedExpression, which
doesn't support the desc method. However, as you can't
apply an order to an aliased expression, nobody should be
relying on this.
---
### Doc Release Notes 3.39.0 (`doc/release_notes/3.39.0.txt`)
= New Features
* A constraint_validations extension and plugin have been added,
which allow you to define validations when creating tables,
which are enforced by database constraints, and have those
validations be automatically discovered and used by your
Sequel::Model classes.
The extension is designed to be used in your migrations/schema
modification code:
DB.extension(:constraint_validations)
DB.create_constraint_validations_table
DB.create_table(:foos) do
primary_key :id
String :name
validate do
min_length 5, :name
end
end
This creates a database CHECK constraint that ensures that the
minimum length for the column is 5 characters. It also adds
metadata about the validation to the
sequel_constraint_validations table.
To have the model class automatically create validations, just
include the plugin in the model:
class Foo < Sequel::Model
plugin :constraint_validations
end
Note that MySQL does not enforce CHECK constraints (it parses
but ignores them), so using the extension on MySQL does not
actually enforce constraints at the database level, though it
still does support the automatic model validations if the plugin
is used.
* Dataset#count now takes an argument or a virtual row block,
allowing you to do:
DB[:table].count(:column_name)
DB[:table].count{function_name(column1, column2)}
When count is given an argument, instead of returning the total
number of rows, it returns the number of rows where the
argument has a non-NULL value.
* Database#copy_into has been added to the postgres adapter when
the pg driver is being used, and can be used for very fast
inserts into tables if you already have the input preformatted
in PostgreSQL text or CSV format.
* set_table_not_null has been added to the alter table generator,
for a nicer API:
alter_table(:t){set_column_not_null :col}
# instead of
alter_table(:t){set_column_allow_null :col, false}
Additionally, set_column_allow_null now defaults the second
argument to true for a nicer API:
alter_table(:t){set_column_allow_null :col}
# instead of
alter_table(:t){set_column_allow_null :col, true}
* Database#supports_regexp? has been added for checking if the
database supports Regexp in filters. Currently, only MySQL and
PostgreSQL support Regexps.
Attempting to use a Regexp on a database that doesn't support it
now raises an error when attempting to generate the SQL, instead
of sending invalid SQL to the database.
* Sequel.char_length has been added for a cross platform
char_length function (emulated when char_length is not supported
natively by the database).
* Sequel.trim has been added for a cross platform trim function
(emulated when trim is not supported natively by the database).
* ValidationFailed and HookFailed exceptions now have a model method
that returns the model instance related to the exception. This
makes it possible to use Model.create inside a begin/rescue block
and get access to the underlying instance if there is a validation
or before/around hook error.
* The subclasses plugin now accepts a block, which is called with
each model class created. This is useful if you want to apply
changes to classes created in the future instead of just existing
classes.
* The validates_unique validation in the validation_helpers plugin
now accepts a :where option for a custom uniqueness filter. Among
other things this makes it easy to implement a case insensitive
uniqueness validation on a case sensitive column.
* The threaded connection pools now support a
:connection_handling=>:disconnect option, which makes them disconnect
connections after use instead of returning them to the pool. This
makes it possible to completely control connection lifetime using
Database#synchronize.
* The pg_row_op extension now has support for PGRowOp#*, for referencing
the members of the composite type as separate columns.
* MySQL's set type and default value are now recognized.
* bin/sequel now accepts a -c argument for running an arbitrary
code string instead of using an IRB prompt.
= Other Improvements
* Sequel now parses current date/timestamp column defaults when
parsing the schema for a table. The values will be returned
as Sequel::CURRENT_DATE for date columns and
Sequel::CURRENT_TIMESTAMP for timestamp columns.
The schema_dumper extension will work with these defaults, so
if you dump the schema for a table with a column that uses
a current timestamp default, the dumped schema will include
the default.
The defaults setter plugin also works with these changes, so
that when new model objects are instantiated, they get the
current Date/Time/DateTime values set.
* On MySQL and PostgreSQL, Sequel will now by default attempt
to combine multiple alter_table operations into a single
query where it believes it can do so correctly. This can
potentially improve performance ~N times, where N is the number
of alter table operations.
This can change the SQL used for old migrations (though it
shouldn't change the result), and is a potentially risky
change. This may be disabled by default in future versions
if it causes problems.
* The defaults_setter plugin now correctly sets false default
values.
* The schema_dumper plugin now preserves fractional seconds
in timestamp column defaults when dumping.
* Time->DateTime and DateTime->Time typecasts now retain
fractional seconds on ruby 1.8.
* Array arguments passed to most PGArrayOp methods are now
automatically wrapped in a PGArray. If you want to use this
support, you need to make sure to load both the pg_array
and pg_array_op extensions.
* Sequel now does a better job of finding the sequence for a
given table on PostgreSQL, handling more corner cases. A small
side effect of this is sometimes sequence names will be quoted.
* Some potential thread-safety issues when using Sequel with
PostgreSQL on a non-GVL ruby implementation have been fixed.
* Sequel now correctly caches the server version query on MySQL.
* Sets of alter_table operations on MySQL and Microsoft SQL Server
that require parsing the current database schema, where later
alter_table operations depend on earlier ones, should now work
correctly.
* You can now drop check constraints on tables on SQLite, though
doing so drops all check constraints on the table, not only the
specific check constraint given.
* The identity_map plugin no longer breaks if used with a model
without a primary key.
* Sequel::SQL::NegativeBooleanConstant now inherits from Constant
instead of BooleanConstant. This means that
Sequel::NULL == Sequel::NOTNULL
is now false instead of true.
* You can now override the convert_tinyint_to_bool settings on a
per-Dataset basis in the mysql and mysql2 adapters, though
the overriding is different depending on the adapter. Check the
commit log for details.
* timestamp(N) types are now recognized as datetime, which should
fix certain cases on Oracle.
* Dataset#insert now handles a single model instance argument
as a single value if the model uses the pg_row plugin.
* When joining a model dataset using a model class as the table
argument, a subselect is used unless the model is a simple select
from the underlying table.
* The specs now cleanup after themselves, dropping the tables that
they create for testing.
= Backwards Compatibility
* The defaults_setter plugin's behavior changed due to the
current date/timestamp support. Previously, it would not set
a value for the column, since the default wasn't recognized.
Therefore, the database would use the default value on insert,
which would be the database's current timestamp.
Now, the value is set to the current Date/Time/DateTime on
model object instantiation, so the database wouldn't use the
column default. Instead of the database's current timestamp
on insert, the column value will be the application's
current timestamp on model instantiation.
Users who don't want this behavior can remove the default values
in the model:
Model.default_values.delete(:column_name)
* Plain (non-model) datasets no longer allow insert to accept
a single model instance argument. Also, they no longer call
values on a single argument if the object responds to it.
* Plain (non-model) datasets no longer accept model classes as
tables in the join/graph methods. Also, they no longer call
table_name on the argument if the object responds to it.
* The schema_dumper extension now requires the eval_inspect
extension, which changes inspect output for
Sequel::SQL::Expression objects.
* Custom adapters that override Database#alter_table_sql_list now
need to make sure it returns an already flattened array.
* The identity_map_key method in the identity_map plugin now returns
nil instead of a random string if the given pk is nil.
---
### Doc Release Notes 3.4.0 (`doc/release_notes/3.4.0.txt`)
New Plugins
-----------
* A nested_attributes plugin was added allowing you to modify
associated objects directly through a model object, similar to
ActiveRecord's Nested Attributes.
Artist.plugin :nested_attributes
Artist.one_to_many :albums
Artist.nested_attributes :albums
a = Artist.new(:name=>'YJM',
:albums_attributes=>[{:name=>'RF'}, {:name=>'MO'}])
# No database activity yet
a.save # Saves artist and both albums
a.albums.map{|x| x.name} # ['RF', 'MO']
It takes most of the same options as ActiveRecord, as well as a
a few additional options:
* :destroy - Allow destruction of nested records.
* :limit - For *_to_many associations, a limit on the number of
records that will be processed, to prevent denial of service
attacks.
* :remove - Allow disassociation of nested records (can remove the
associated object from the parent object, but not destroy the
associated object).
* :strict - Set to false to not raise an error message if a primary
key is provided in a record, but it doesn't match an existing
associated object.
If a block is provided, it is passed each nested attribute hash.
If the hash should be ignored, the block should return anything
except false or nil.
* A timestamps plugin was added for automatically adding
before_create and before_update hooks for setting values on
timestamp columns. There are a couple of existing external
plugins that handle timestamps, but the implementations are
suboptimal. The new built-in plugin supports the following
options (with the default in parentheses):
* :create - The field to hold the create timestamp (:created_at)
* :force - Whether to overwrite an existing create timestamp
(false)
* :update - The field to hold the update timestamp (:updated_at)
* :update_on_create - Whether to set the update timestamp to the
create timestamp when creating (false)
* An instance_hooks plugin was added for adding hooks to specific
w
model instances:
obj = Model.new
obj.after_save_hook{do_something}
obj.save # calls do_something after the obj has been saved
All of the standard hooks are supported, except for
after_initialize. Instance level before hooks are executed in
reverse order of addition before calling super. Instance level
after hooks are executed in order of addition after calling super.
If any of the instance level before hook blocks return false, no
more instance level before hooks are called and false is returned.
Instance level hooks are cleared when the object is saved
successfully.
* A boolean_readers plugin was added for creating attribute? methods
for boolean columns. This can provide a nicer API:
obj = Model[1]
obj.active # Sequel default column reader
obj.active? # Using the boolean_readers plugin
You can provide a block when loading the plugin to change the
criteria used to determine if the column is boolean:
Sequel::Model.plugin(:boolean_readers) do |c|
db_schema[c][:db_type] =~ /\Atinyint/
end
This may be useful if you are using MySQL and have some tinyint
columns that represent booleans and others that represent integers.
You can turn the convert_tinyint_to_bool setting off and use the
attribute methods for the integer value and the attribute? methods
for the boolean value.
Other New Features
------------------
* Sequel now has support for converting Time/DateTime to local or UTC
time upon storage, retrieval, or typecasting.
There are three different timezone settings:
* Sequel.database_timezone - The timezone that timestamps use in
the database. If the database returns a time without an offset,
it is assumed to be in this timezone.
* Sequel.typecast_timezone - Similar to database_timezone, but used
for typecasting data from a source other than the database. This
is currently only used by the model typecasting code.
* Sequel.application_timezone - The timezone that the application
wants to deal with. All Time/DateTime objects are converted into
this timezone upon retrieval from the database.
Unlike most things in Sequel, these are only global settings, you
cannot change them per database. There are only three valid
timezone settings:
* nil (the default) - Don't do any timezone conversion. This is
the historical behavior.
* :local - Convert to local time/Consider time to be in local time.
* :utc - Convert to UTC/Consider time to be in UTC.
So if you want to store times in the database as UTC, but deal with
them in local time in the application:
Sequel.application_timezone = :local
Sequel.database_timezone = :utc
If you want to set all three timezones to the same value:
Sequel.default_timezone = :utc
There are three conversion methods that are called:
* Sequel.database_to_application_timestamp - Called on time objects
coming out of the database. If the object coming out of the
database (usually a string) does not have an offset, assume it is
already in the database_timezone. Return a Time/DateTime object
(depending on Sequel.datetime_class), in the application_timezone.
* Sequel.application_to_database_timestamp - Used when literalizing
Time/DateTime objects into an SQL string. Converts the object to
the database_timezone before literalizing them.
* Sequel.typecast_to_application_timestamp - Called when
typecasting objects for model datetime columns. If the object
being typecasted does not already have an offset, assume it is
already in the typecast_timezone. Return a Time/DateTime object
(depending on Sequel.datetime_class), in the
application_timezone.
Sequel does not yet support named timezones or per thread
modification of the timezone (for showing all timestamps in the
current user's timezone). Extensions to support both features are
planned for a future version.
* Dataset#truncate was added for truncating tables. Truncate allows
for fast removal of all rows in a table.
* Sequel now supports typecasting a hash to date, time, and datetime
types. This allows easy usage of Sequel with forms that split
the entry of these database types into separate from fields.
With this code, you can just have field names like:
date[year]
date[month]
date[day]
Rack will parse that into:
{'date'=>{'year'=>?, 'month'=>?, 'day'=>?}}
So then you can do:
obj.date = params['date']
# or
obj.set(params)
* validates_unique now takes a block that can be used to scope the
uniqueness constraint. This allows you to easily set up uniqueness
validations that are only necessary in a given scope. For example,
a validation on username, but only for active users (as inactive
users are soft deleted but remain in the table). You just pass a
block to validates_unique:
validates_unique(:name){|ds| ds.filter(:active)}
* The serialization plugin now supports json.
* Sequel now supports generic concepts of
CURRENT_{DATE,TIME,TIMESTAMP}. Most databases support these SQL
concepts, but not all, and some implementations act differently.
The Sequel::SQL::Constants module holds the three constants,
which are instances of SQL::Constant, an SQL::GenericExpression
subclass. This module is included in Sequel, so you can reference
the constants more easily (e.g. Sequel::CURRENT_TIMESTAMP).
It's separated out into a separate module so that you can just
include that module in the top level scope, allowing you to
reference the constants directly (e.g. CURRENT_TIMESTAMP).
DB[:events].filter{date < ::Sequel::CURRENT_DATE}
# or:
include Sequel::SQL::Constants
DB[:events].filter{date < ::CURRENT_DATE}
* Database#run was added for executing arbitrary SQL on a database.
It's an alias for Database#<<, but it allows for a nicer API inside
migrations, since you can now do:
run 'SQL'
instead of:
self << 'SQL'
You can also provide a :server option to run the SQL on the
given server/shard:
run 'SQL', :server=>:shard1
* Sequel::Model() can now take a database argument in addition to
a symbol or dataset argument. If a database is given, it'll create
an anonymous subclass attached to the given database. Other changes
were made to allow the following code to work:
class Item < Sequel::Model(DB2)
end
That will work correctly assuming a table named items in DB2.
* Dataset#ungrouped was added for removing a grouping from an
existing dataset. Also, Dataset#group when called with no arguments
or with a nil argument also removes any existing grouping instead
of resulting in invalid SQL.
* Model#modified? was added, letting you know if the model has been
modified. If the model hasn't been modified, calling
Model#save_changes will do nothing.
* SQL::OrderedExpression now supports #asc, #desc, and #invert.
Other Improvements
------------------
* The serialization and lazy_attribute plugins now add accessor
methods to a module included in the class, instead of to the
model class itself. This allows the methods to be overridden
in the class and work well with super, as well for the plugins
to work together on the same column. Make sure the
lazy_attributes accessor is setup before the serialization
accessor if you want to have a lazy serialized column.
* Calling the add_* method for many_to_many association now saves the
record if the record is new. This makes it operate more similarly
to one_to_many associations. Previously, it raised an Error.
* Dataset#import now works correctly when called with a dataset.
Previously, it generated incorrect SQL.
* The JDBC adapter now converts byte arrays to/from SQL::Blob.
* The JDBC adapter now attempts to bind unknown types using
setObject instead of raising, so it can work with native Java
objects. It also binds boolean parameters correctly.
* Using multiple emulated ALTER TABLE statements (such as
drop_column) in a single alter_table block now works correctly
on SQLite.
* Database#indexes now works on JDBC for tables in a non-default
schema. It also now properly detects unique indexes on MSSQL.
* Database#schema on JDBC now accepts a :schema option. Also,
returned schema hashes now include a :column_size entry specifying
the maximum length/precision for the column, since the
:db_type entry doesn't have contain the information on JDBC.
* Datasets without tables now work correctly on Oracle, so things
like DB.get(...) now work.
* A descriptive error message is given if you attempt to use
Sequel with the mysql.rb driver (which Sequel doesn't support).
* The postgres adapter now works correctly with a modified
postgres-pr that raises PGErrors instead of RuntimeErrors
(e.g. http://github.com/jeremyevans/postgres-pr).
* You now get a Sequel::InvalidOperation instead of a NoMethodError
if you attempt to update a dataset without a table.
* The inflection support has been modified to reduce code
duplication.
Backwards Compatibility
-----------------------
* Sequel now includes fractional seconds in timestamps for all
adapters except MySQL. It's possible that this may break
timestamp columns for databases that are not regularly tested.
* Sequel now includes timezone values in timestamps on Microsoft
SQL Server, Oracle, PostgreSQL and SQLite. The modification for
SQLite is probably the biggest cause for concern, since SQLite
stores times as text. If you have an SQLite database that uses
timestamps and is accessed by something other than Sequel, you
should make sure that it works with the timestamp format that
Sequel now uses.
* The default timestamp format used by Sequel now uses a space
instead of 'T' between the date and time parts, which could
possibly affect some databases that are not regularly tested.
* Attempting to insert into a grouped dataset or a dataset that
selects from multiple tables will now raise an Error. Previously,
it would ignore any GROUP or JOIN settings and generate bad SQL if
there were multiple FROM tables.
* Database#<< now always returns nil. Before, the return value was
adapter dependent.
* ODBC::Time and ODBC::DateTime values are now converted to the
Sequel.datetime_class. Before, ODBC::Time used Time and
ODBC::DateTime used DateTime regardless of the
Sequel.datetime_class setting.
* The default inflections were modified, fixing some obvious errors
and possibly changing some existing inflections. Further changes
to the default inflections are unlikely.
---
### Doc Release Notes 3.40.0 (`doc/release_notes/3.40.0.txt`)
= New Features
* Sequel now has vastly improved support for Microsoft Access.
* Sequel now supports the CUBRID database, with a cubrid adapter
that uses the cubrid gem, and a jdbc/cubrid adapter for accessing
CUBRID via JDBC on JRuby.
* The association_pks plugin now supports composite keys.
* Database#transaction now accepts a :disconnect=>:retry option,
in which case it will automatically retry the block if it
detects a disconnection. This is potentially dangerous, and
should only be used if the entire block is idempotent. There
is also no checking against an infinite retry loop.
* SQL::CaseExpression#with_merged_expression has been added, for
converting a CaseExpression with an associated expression to
one without an associated expression, by merging the expression
into each condition.
= Other Improvements
* Sequel now quotes arguments/columns in common table expressions.
* Sequel now handles nil values correctly in the pg_row extension.
* Sequel::Postgres::HStore instances can now be marshalled.
* Sequel now uses clob for String :text=>true types on databases that
don't support a text type.
* On PostgreSQL, Sequel now quotes channel identifier names when using
LISTEN/NOTIFY.
* On PostgreSQL, Sequel now correctly handles the case where named
type conversion procs have been added before the Database object is
instantiated.
* On DB2, Sequel now explicitly sets NOT NULL for unique constraint
columns instead of foreign key columns. DB2 does not allow columns
in unique constraints to be NULL, but does allow foreign key columns
to be NULL.
* In the oracle adapter, clob values are now returned as ruby strings
upon retrieval.
* Sequel now detects more types of disconnections in the postgres,
mysql, and mysql2 adapters.
* If a database provides a default column value that isn't a ruby
string, it is used directly as the ruby default, instead of causing
the schema parsing to fail.
= Backwards Compatibility
* Code using Sequel's oracle adapter that expected clob values to be
returned as OCI8::CLOB instances needs to be modified to work with
ruby strings.
* Because Sequel now quotes column names in common table expressions,
those names are now case sensitive, which could break certain poorly
coded queries. Similar issues exist with the quoting of channel
identifier names in LISTEN/NOTIFY on PostgreSQL.
* The private Database#requires_return_generated_keys? method
has been removed from the jdbc adapter. Custom jdbc subadapters
relying on this method should override the private
Database#execute_statement_insert method instead to ensure that
RETURN_GENERATED_KEYS is used for insert statements.
* The private Dataset#argument_list and #argument_list_append methods
have been removed.
---
### Doc Release Notes 3.41.0 (`doc/release_notes/3.41.0.txt`)
= New Features
* A connection_validator extension has been added, which
automatically determines if connections checked out from the pool
are still valid. If they are not valid, the connection is
disconnected and another connection is used automatically,
transparent to user code.
Checking if connections are valid requires a query, so this
extension causes a performance hit. For that reason, connections
are only checked by default if they have been inactive for more than
a configured amount of time (1 hour by default). You can choose to
validate connections on every checkout via:
DB.pool.connection_validation_timeout = -1
However, this can cause a substantial performance hit unless you are
purposely using coarse connection checkouts via manual calls to
Database#synchronize (for example, in a Rack middleware). Using
coarse checkouts can greatly reduce the amount of concurrency that
Sequel supports (for example, limiting the number of concurrent
requests to the number of database connections), so this method is
not without its tradeoffs.
* Sequel.delay has been added for a generic form of delayed
evaluation. This method takes a block and delays evaluating it
until query literalization. By default, Sequel evaluates most
arguments immediately:
foo = 1
ds = DB[:bar].where(:baz=>foo)
# SELECT * FROM bar WHERE (baz = 1)
foo = 2
ds
# SELECT * FROM bar WHERE (baz = 1)
Using Sequel.delay, you can delay the evaluation:
foo = 1
ds = DB[:bar].where(:baz=>Sequel.delay{foo})
# SELECT * FROM bar WHERE (baz = 1)
foo = 2
ds
# SELECT * FROM bar WHERE (baz = 2)
* Sequel now supports the :unlogged option when creating tables on
PostgreSQL, to create an UNLOGGED table.
* On SQLite, Database#transaction now supports a :mode option for
setting up IMMEDIATE/EXCLUSIVE SQLite transactions. Sequel also
supports a Database#transaction_mode accessor for setting the
default transaction mode on SQLite.
* Most pg_* extension objects (e.g. PGArray) now support the #as
method for creating an SQL::AliasedExpression object.
* The single_table_inheritance plugin now supports non-bijective
mappings. In lay terms, this means that a one-to-one mapping
of column values to classes is no longer required. You can now
have multiple column values that map to a single class in the
:model_map option, and specify a :key_chooser option to choose
which column value to use for the given model class.
* The touch plugin now handles the touching of many_to_many
associations, and other associations that use joined datasets.
* ConnectionPool#pool_type has been added. It returns a symbol
representing the type of connection pool in use (similar to
Database#database_type).
* Database#valid_connection? has been added for checking if a given
connection is still valid.
* Database#disconnect_connection is now part of the public API, and
can be used to disconnect a given connection.
= Other Improvements
* Uniqueness validation now correctly handles nil values.
Previously, it checked the underlying table for other rows where
the column IS NULL, but that is incorrect behavior. Sequel's new
(correct) behavior is to skip the uniqueness check if the column
is nil.
* Foreign key parsing is now supported on Microsoft SQL Server.
* Dataset#reverse and #reverse_order now accept virtual row blocks.
* Changing the name of the primary key column, and possibly other
schema changes on the primary key column, are now supported on
MySQL.
* Primary key columns are now specifically marked as NOT NULL on
SQLite, as non-integer primary keys on SQLite are not considered
NOT NULL by default.
* Failure to create a native prepared statement is now handled
better in the postgres, mysql, and mysql2 adapters.
* Firebird now emulates selecting data without an underlying table
(e.g. DB.get(1)).
* Finding the name of the constraint that sets column defaults on
Microsoft SQL Server now works correctly on JRuby 1.7.
* An additional type of disconnect error is now recognized in the
jdbc/sqlserver adapter.
* Many adapters have been fixed so that they don't raise an exception
if trying to disconnect an already disconnected connection.
* Many adapters have been fixed so that
Database#log_connection_execute logs and executes the given SQL
on the connection.
* Many adapters have been fixed so that
Database#database_error_classes returns an array of database
exception classes for that adapter.
* Database#log_exception now handles a nil exception message.
* Dataset#limit(nil, nil) now resets offset in addition to limit, but
you should still use Dataset#unlimited instead.
* A bin/sequel usage quide has been added to the documentation.
= Backwards Compatibility
* Sequel now treats clob columns as strings instead of blobs
(except on DB2 when use_clob_as_blob = true). This can make it
so the values are returned as strings instead of SQL::Blob values.
Since SQL::Blob is a String subclass, this generally will
not affect user code unless you are passing the values as input
to a separate blob column.
* The Database <-> ConnectionPool interface was completely changed.
Sequel no longer supports custom connection procs or disconnection
procs in the connection pools. The :disconnection_proc Database
option is no longer respected, and blocks passed to Database.new
are now ignored.
This change should not be user-visible, but if you had any code
that was monkeying with the connection pool internals, you may
need to modify it.
* Code that was using the uniqueness check to also check for presence
should add a separate check for presence. Such code was broken,
as it only worked if there was already a NULL column value in the
table. If you were relying on this broken behavior, you should
clean up the NULL data in the column and then mark the database
column as NOT NULL.
* If you have code that specifically abuses the fact that non-integer
primary keys on SQLite allow NULL values by default, it will no
longer work.
---
### Doc Release Notes 3.42.0 (`doc/release_notes/3.42.0.txt`)
= New Features
* Dataset#avg, #interval, #min, #max, #range, and #sum now
accept virtual row blocks, allowing you to more easily get
aggregate values of expressions based on the table:
DB[:table].sum{some_function(column1, column2)} # => 134
# SELECT sum(some_function(column1, column2)) FROM table
* Database#do has been added on PostgreSQL for using the DO
anonymous code block execution statement.
* Model.dataset_module now uses a Module subclass, which allows
you to call subset inside a dataset_module block, making
it easier to consolidate dataset method code:
class Album < Sequel::Model
dataset_module do
subset(:gold){copies_sold > 500000}
end
end
* Database#copy_table and #copy_into are now supported on
jdbc/postgres.
* Sequel now supports deferred constraints on constraint types other
than foreign keys. The only databases that appear to implement
this are Oracle and PostgreSQL.
* Sequel now supports INITIALLY IMMEDIATE deferred constraints via
the :deferrable=>:immediate constraint/column option.
* Sequel now supports setting the default size of string columns,
via the default_string_column_size option or accessor. In some
cases, Sequel's default string column size of 255 is too large
(e.g. MySQL with utf8mb4 character set), and this allows you to
change it.
= Other Improvements
* Dataset#count and other methods now use a subselect in the case
where the dataset has an offset but no limit.
* If an error occurs while attempting to commit a transaction, Sequel
now attempts to rollback the transaction. Some databases do this
automatically, but not all. Among other things, this fixes issues
with deferred foreign key constraint violations on SQLite.
* When extending a model's dataset, the model's instance_dataset is
reset, insuring that it will also be extended with the module.
* When passing an invalid argument to Dataset#filter, the exception
message now includes the argument.
* The force_encoding plugin now works with frozen string values.
* Public methods added to a model dataset_module now have model
class methods created for them even if the method was added outside
of a dataset_module block.
* On PostgreSQL, Database#indexes now includes a :deferrable entry
for each index hash, which will be true for unique indexes where
the underlying constraint is deferrable.
* On Microsoft SQL Server 2000, Dataset#update no longer includes a
limit (TOP), allowing it to work correctly.
= Backwards Compatibility
* Model.dataset_methods has been removed. This was used to store
blocks for methods created via def_dataset_method and subset.
The internals have been changed so that a dataset_module is
always used in these cases, therefore there was no longer a reason
for this method.
---
### Doc Release Notes 3.43.0 (`doc/release_notes/3.43.0.txt`)
= New Features
* A core_refinements extension has been added, which offers
refinement versions of Sequel's core extensions. This requires
the new experimental refinement support added in ruby 2.0, and
allows you to use the Sequel DSL methods in a file without
actually modifying the Symbol, String, Array, and Hash classes.
* A date_arithmetic extension has been added for performing
database-independent date calculations (adding/subtracting an
interval to/from a date):
Sequel.extension :date_arithmetic
e = Sequel.date_add(:date_column, :years=>1, :months=>2, :days=>3)
DB[:table].where(e > Sequel::CURRENT_DATE)
In addition to providing the interval as a hash, you can also
provide it as an ActiveSupport::Duration object. This extension
is supported on 11 database types.
* Dataset#get can now take an array of multiple expressions to get
an array of values, similar to map/select_map:
value1, value2 = DB[:table].get([:column1, :column2])
* Sequel can now handle [host.]database.schema.table qualified
tables on Microsoft SQL Server. To implement this support,
the split_qualifiers method has been added to Database and
Dataset for taking a possibly qualified identifier and splitting
it into an array of identifier strings.
* The string_stripper plugin now offers the ability to manually
specify which columns to skip stripping for via
Model.skip_string_stripping.
= Other Improvements
* The jdbc adapter now works with the new jdbc-* gems, which require
a manual load_driver step that the older jdbc-* gems did not
require.
* The string_stripper plugin no longer strips blob columns or values.
* Database#copy_into in both the postgres and jdbc/postgres adapters
has been fixed to better handle exceptions.
* Dataset#hash and Model#hash are now significantly faster.
* Lambda procs with 0 arity can now be used as virtual row blocks
on ruby 1.9. Previously, attempting to use a lambda proc with
0 arity as a virtual row block on ruby 1.9 would raise an exception.
* Schema-qualified composite types are now handled correctly in
the pg_row extension.
* Database#reset_primary_key_sequence on PostgreSQL now works
correctly when a default_schema is set.
* tinyint(1) unsigned columns on MySQL are now parsed as booleans
instead of integers on MySQL if converting tinyint to boolean.
* The jdbc adapter now supports the jdbc-hsqldb gem, so you can
now install that instead of having to require the .jar manually.
* Blobs are now casted correctly on DB2 when the use_clob_as_blob
setting is false.
* Oracle timestamptz types are now handled correctly in the
jdbc/oracle adapter.
* Sequel now defaults to :prefetch_rows = 100 in the oracle
adapter, which can significantly improve performance.
* Sequel now defines respond_to_missing? where method_missing? is
defined and the object also responds to respond_to?.
* Sequel::BasicObject now responds to instance_exec on ruby 1.8.
= Backwards Compatibility
* The meta_def method that was defined on Database, Dataset, and
Model classes and instances has been moved to an extension named
meta_def, and is no longer loaded by default. This method was
previously used internally, and it wasn't designed for external
use. If you have code that uses meta_def, you should now load the
extension manually:
Sequel.extension :meta_def
* The private _*_dataset_helper model association methods are no
longer defined. The AssociationReflection#dataset_helper_method
public method is also no longer defined.
* Dataset#schema_and_table now always returns strings (or nil).
Before, in some cases it would return symbols.
* Using a conditions specifier array with Dataset#get no longer
works due to the new multiple values support in Database#get.
So code such as:
DB[:table].get([[:a, 1], [:b, 2]])
should be changed to:
DB[:table].get(Sequel.expr([[:a, 1], [:b, 2]]))
---
### Doc Release Notes 3.44.0 (`doc/release_notes/3.44.0.txt`)
= New Features
* Dataset#paged_each has been added, for processing entire datasets
without keeping all rows in memory, even if the underlying driver
keeps all query results in memory. This is implemented using
limits and offsets, and requires an order (model datasets use a
default order by primary key). It defaults to fetching 1000
rows at a time, but that can be changed via the :rows_per_fetch
option.
This method is drop-in compatible for each. Previously, the
pagination extension's each_page method could be used for a
similar purpose, but users of each_page are now encouraged to
switch to paged_each.
* Sequel now recognizes constraint violation exceptions on most
databases, and will raise specific exceptions for different
types of constraint violations, instead of the generic
Sequel::DatabaseError:
* Sequel::ConstraintViolation (generic superclass)
* Sequel::CheckConstraintViolation
* Sequel::NotNullConstraintViolation
* Sequel::ForeignKeyConstraintViolation
* Sequel::UniqueConstraintViolation
* Sequel::Postgres::ExclusionConstraintViolation
* The :dataset association option can now take accept an optional
association reflection option. Instead of doing:
Album.one_to_many :artists,
:dataset=>{Artist...}
you can now do:
Album.one_to_many :artists,
:dataset=>{|r| r.associated_dataset...}
This second form will perform better.
* Temporary views are now supported on PostgreSQL and SQLite using
the :temp option to create_view.
= Other Improvements
* Row fetching speed in the tinytds adapter has been increased by
up to 60%.
* Row fetching speed in the mysql2 adapter when using an identifier
output method has been increased by up to 50%.
* On databases where offsets are emulated via the ROW_NUMBER window
function (Oracle, DB2, Microsoft SQL Server), using an offset in
a subselect is now supported. For example, the following code
previously didn't work correctly with emulated offsets:
# Second 5 rows ordered by column2 of the second 10 rows ordered
# by column 1.
DB[:table].order(:column1).limit(10, 10).
from_self.order(:column2).limit(5, 5)
Row processing speed has been increased slightly for all adapters
that supported databases where offsets are emulated.
* Association method performance has improved by caching an
intermediate dataset. This can close to triple the performance
of the association_dataset method, and increase the performance
of the association method by close to 30%.
* Virtual Row performance has increased about 30% in the typical
case by using a shared VirtualRow instance.
* Database#create_or_replace_view is now emulated on databases that
don't support it directly by dropping the view before attempting
to create it.
* The columns_introspection extension can now introspect for simple
select * queries from subselects, and it can now use the cached
schema information in the database for simple select * queries
from tables.
* The identity_map plugin now works correctly with many-to-many
right-side composite keys.
* Dataset#last for Model datasets now works even if you don't specify
an order explicitly, giving the last entry by primary key. Note
that Dataset#first for model datasets still does not order by
default.
* The eager_each plugin no longer uses Object#extend at runtime.
* Database#remove_cached_schema is now thread-safe on non-GVL ruby
implementations.
* Connection errors in the jdbc adapter now provide slightly more
helpful messages.
* Sequel now uses the standard offset emulation code in the
jdbc/as400 adapter, instead of custom offset emulation code
specific to that adapter.
* Database#create_view with a dataset now works correctly when using
the pg_auto_parameterize extension.
* Database#columns no longer calls the row_proc.
* Dataset#schema_and_table no longer turns a literal string into a
non-literal string.
* The oracle adapter now works with a :prefetch_rows=>nil option,
which explicitly disables prefetching.
* The mock mssql adapter now sets a server_version so that more
parts of it work.
= Backwards Compatibility
* Offset emulation via ROW_NUMBER works by moving the query to a
subselect that also selects from the ROW_NUMBER window function,
and filtering on the ROW_NUMBER in the main query. Previously, the
ROW_NUMBER was also present in the output columns, and some
adapter code was needed to hide that fact. Now, the outer select
selects all of the inner columns in the subselect except for the
ROW_NUMBER, reducing the adapter code needed. This has the side
effect of potentially requiring a query (or multiple queries for
multiple subselects) to determine the columns to use. The
columns_introspection extension may reduce the number of queries
needed.
* The correlated_subquery eager limit strategy is no longer supported
on Microsoft SQL Server for many_*_many associations. As the
window_function eager limit strategy is supported there, there is
no reason to use the correlated_subquery strategy.
* The public AssociationReflection#_dataset_method method has been
removed.
* The private _*_dataset methods for associations (e.g.
_albums_dataset) have been removed.
* The private Dataset#offset_returns_row_number_column? method has
been removed.
* :conditions options for associations are now added to the
association dataset before the foreign key filters, instead of
after. This should have no effect unless you were introspecting
the dataset's opts or sql and acting on it.
* The added abilities in the columns_introspection plugin to use
cached schema for introspection can now cause it to return
incorrect results if the table's schema has changed since it was
cached by Sequel.
---
### Doc Release Notes 3.45.0 (`doc/release_notes/3.45.0.txt`)
= New Features
* Database#transaction now recognizes a :retry_on option, which
should contain an exception class or array of exception classes.
If the transaction raises one of the given exceptions, Sequel
will automatically retry the transaction block. It's a bad idea to
use this option if the transaction block is not idempotent.
By default, Sequel only retries the block 5 times by default,
to protect against infinite looping. You can change the number
of retries with the :num_retries option.
Users of the :disconnect=>:retry option are encouraged to switch
to :retry_on=>Sequel::DatabaseDisconnectError.
* Dataset#escape_like has been added for escaping LIKE
metacharacters. This is designed for the case where part of
the LIKE pattern is based on user input that should not treat the
metacharacters specially.
* Serialization failures/deadlocks are now raised as
Sequel::SerializationFailure exception instances. This exception
class is a good candidate for the transaction :retry_on option.
* On PostgreSQL, you can now provide the :force_standard_strings
and :client_min_messages Database options to override the defaults
on a per-instance basis.
* On PostgreSQL, Database#tables and #views now recognizes a
:qualify option, which if true will return qualified identifiers
instead of plain symbols.
* Transaction isolation levels are now supported on Oracle, DB2,
and all jdbc subadapters using the JDBC transaction support.
* Dataset.def_mutation_method now accepts a :module option for
the module in which to define the methods (defaulting to self).
* An unlimited_update plugin has been added. It's sole purpose is to
eliminate a MySQL warning in replicated environments, since by
default Sequel::Model uses a LIMIT clause when updating on MySQL.
* The named_timezones extension now adds a
Sequel.tzinfo_disambiguator accessor to automatically handle
TZInfo::AmbiguousTime exceptions. This should be a callable object
that accepts two arguments, a DateTime instance and an array of
timezone periods, and returns the timezone period to use.
= Other Improvements
* Sequel now handles JSON securely, specifying the
:create_additions=>false option when using JSON.parse. If you
really want to get the old vulnerable behavior back, override
Sequel.parse_json.
* The json_serializer and xml_serializer plugins are now secure
by default. Before, the default behavior of these plugins
allowed for round tripping, such that:
Album.from_xml(album.to_xml) == album
Unfortunately, that requires that the deserialization allow
the setting of any column. Since the plugins also handle
associations, you could also set any column in any associated
object, even cascading to associated objects of those objects.
The new default behavior only allows deserialization to set
the same columns that mass-assignment would set, and not to
handle associated objects at all by default. The following
additional options are supported:
:fields :: The specific fields to set (this was already supported
by the json_serializer plugin).
:associations :: The specific associations to handle.
:all_columns :: The previous behavior of setting all columns.
:all_associations :: The previous behavior of setting all
associations.
Since JSON parsing no longer deserializes into arbitrary ruby
instances, from_json and array_from_json class methods have been
added to the json_serializer plugin, for deserializing into model
instances. These mirror the from_xml and array_from_xml class
methods in the xml_serializer plugin.
Note that the :all_columns and :all_associations methods were
only added to make backwards compatibility easier. It is
likely they will be removed in Sequel 4, along with the
json_create class method.
* Sequel now attempts to use database specific error codes or
SQLState codes instead of regexp parsing to determine if a more
specific DatabaseError subclass should be used. This should make
error handling faster and more robust.
* Sequel now uses ESCAPE '\' when using LIKE, for similar behavior
across databases. Previously, no ESCAPE clause was used, so
behavior differed across databases, with most not using escaping,
and PostgreSQL, MySQL, and H2 defaulting to backslash as the escape
character.
* The query extension has been reimplemented and now uses a proxy
object instead of Object#extend.
* The :pool_timeout Database option now supports fractional seconds.
* Database#quote_identifier is now a public method.
* Metadata parsing (schema, indexes, foreign_key_list) on PostgreSQL
now correctly handles the case where an unqualified table name is
used and tables with that name exist in multiple schemas. It now
picks the first matching table in the schema_search_path, instead of
failing or returning results from all tables.
* Sequel::Model instances no longer attempt to typecast the money
type on PostgreSQL, since the previous typecast didn't work
correctly, and correct typecasting is locale-dependent.
* Sequel no longer picks up foreign keys for tables in other
databases when using Database#foreign_key_list on MySQL.
* A warning when using the mysql2 3.12 beta has been eliminated.
* A warning has been eliminated when using the jdbc/oracle adapter
on JRuby 1.7.
* Sequel's ilike emulation should now work by default on databases
without specific syntax support.
* Dataset#from_self! no longer creates a self referential dataset.
* Coverage testing now uses simplecov instead of rcov on ruby 1.9+.
= Backwards Compatibility
* The switch to using JSON.parse :create_additions=>false means
that if your app expected JSON to deserialize into arbitrary
ruby objects, it is probably broken. You should update your
application code to manually convert the deserialized hashes
into the ruby objects you want.
Note that it's not just this new version of Sequel that will
cause that, older versions of Sequel will break in the same
way if you update your JSON library to a version that is not
vulnerable by default.
This potentially affects the pg_json extension and serialization
plugin if you were expecting the JSON stored in the database
to be deserialized into arbitrary ruby objects.
See the json_serializer/xml_serializer changes mentioned in
the Other Improvements section.
* The reimplemented query extension is not completely backwards
compatible. For example, inside a query block, self refers to the
proxy object instead of a dataset, and calling methods that return
rows no longer raises an exception.
* The metadata parsing methods on PostgreSQL no longer work with
unqualified tables where the table is not in the schema search
path. This makes metadata parsing consistent with how datasets
operate. For tables outside the schema search path, you must
qualify it before use now.
Additionally, using a nonexistent table name will raise an
exception instead of returning empty results in some cases.
* The Dataset#def_mutation_method instance method has been removed.
This method added mutation methods directly on the dataset instance,
which is generally not desired. Using the def_mutation_method class
method with the :module option is now the recommended approach.
* The switch to using ESCAPE for LIKE characters is backwards
incompatible on databases that don't use escaping by default,
when backslash is used in a LIKE pattern as a regular character.
Now you have to double the backslash in the pattern.
* Database#database_error_regexps private method now can return any
enumerable yielding regexp/exception class pairs, it is no longer
specified to return a hash.
---
### Doc Release Notes 3.46.0 (`doc/release_notes/3.46.0.txt`)
= New Features
* Dataset#first! has been added. This is identical to #first,
except where #first would return nil due to no row matching,
#first! raises a Sequel::NoMatchingRow exception. The main
benefit here is that a standard exception class is now used,
so external libraries can deal with these exceptions appropriately
(such as web applications returning a 404 error).
* Dataset#with_pk! has been added to model datasets. Similar to
#first!, this raises a Sequel::NoMatchingRow exception instead of
returning nil if there is no matching row.
* A drop_foreign_key method has been added to the alter_table
generator:
alter_table(:tab){drop_foreign_key :col}
This relies on foreign_key_list working and including the name
of the foreign key. Previously, you'd have to drop the foreign key
constraint before dropping the column in some cases.
* Column constraints can now be named using :*_constraint_name
options:
create_table(:tab) do
primary_key :id, :primary_key_constraint_name=>:pk_name
foreign_key :t_id, :t, :foreign_key_constraint_name=>:fk_name,
:unique=>true, :unique_constraint_name=>:uk_name
end
This makes it easier to name constraints, which has always been
recommended as it makes it easier to drop such constraints in the
future.
* On Microsoft SQL Server, Dataset#cross_apply and #outer_apply have
been added to use CROSS/OUTER APPLY. These are useful if you
want to join a table to the output of a function that takes the
table as an argument.
= Other Improvements
* The connection pools are now faster when using the
:connection_handling=>:queue option.
* External connection pool classes can now be loaded automatically by
the :pool_class option.
* Database#each_server now raises if not given a block. Previously,
it just leaked Database references.
* On Microsoft SQL Server, ] characters are now escaped correctly in
identifiers.
* On PostgreSQL, infinite dates are also handled when using
Database#convert_infinite_timestamps. Previously, infinite dates
were incorrectly converted to 0000-01-01.
* The associations, composition, serialization, and dirty plugins
now clear caches stored in the instance in some additional cases,
such as when saving model instances when the dataset supports
insert_select.
* Model#validates_type in the validation_helpers plugin now handles
false values correctly.
* The string_stripper plugin has been fixed to not change the result
of Model.set_dataset.
* You can now drop primary key constraints on H2, using:
alter_table(:tab){drop_constraint :foo, :type=>:primary_key}
* The jdbc/as400 adapter has been fixed, it was broken starting in
Sequel 3.44.0.
* A Security guide has been added explaining various security issues
to think about when using Sequel.
= Backwards Compatibility
* The change to make associations, composition, serialization, and
dirty now clear caches after saving when the dataset supports
insert_select can break code that expected the previous behavior.
For example:
artist = Artist[1]
artist.has_albums # => false
album = Album.new(:artist=>artist)
def album.after_create
super
artist.update(:has_albums=>true)
end
album.save
artist.has_albums # => false
Such code should either refresh the artist after saving the album,
or use album.artist.has_albums. You already had to do that if
the dataset did not support insert_select; the impetus for this
change was to make the behavior consistent.
* Decimal/numeric columns are now strictly typecast by default,
similar to integer and real/double precision columns. If you want
the previous loose typecasting to for decimal/numeric columns,
use the looser_typecasting extension.
* External adapters that called Database.set_adapter_scheme with a
string should change to using a symbol.
* Dataset#select_map, #select_order_map, and #get now raise an
exception if they are passed a plain string inside an array.
If you do want to use a plain string, you now need to alias it:
dataset.get([Sequel.as('string', :some_alias)])
= Sequel 4 Implementation Planning
* Sequel 4 implementation planning has begun. If you want to view
and/or provide feedback on the implementation plan, see
https://github.com/jeremyevans/sequel-4-plans
---
### Doc Release Notes 3.47.0 (`doc/release_notes/3.47.0.txt`)
= New Plugins
* An auto_validations plugin has been added, which automatically
adds not null, type, and unique validations based on information
obtained from parsing the database schema. If you don't
require customization of the validation error message per
column, this can significantly DRY up validation code. Currently
this plugin requires the database support index parsing; that
restriction will be removed in Sequel 4.
* An input_transformer plugin has been added, for automatically
running a transformation proc on all model column setter
input before use. This is a generalization of the
string_stripper plugin, allowing arbitrary modifications
to the input.
* An error_splitter plugin has been added, for splitting validation
errors applying to multiple columns into a separate validation
error per column. This is useful if you want to to include such
errors when using Errors#on to get all errors on the column. In
general, only uniqueness errors apply to multiple columns, so
those are the only errors likely to be affected.
= Other New Features
* Database.extension has been added, allowing you to load an
extension into all future databases. This is similar to loading a
plugin into Sequel::Model itself. For example, if you want all
Database instances to use the query_literals extension, run the
following before creating your Database instances:
Sequel::Database.extension :query_literals
* Database.after_initialize has been added for running a hook
on all new databases created.
* Model.default_set_fields_options has been added, allowing you
to set the default options for the #set_fields and #update_fields
methods. This is useful if you want to make :missing=>:raise
or :missing=>:skip the default behavior.
* The :setter, :adder, :remover, and :clearer association options
have been added. These allow you to override the default
implementation used to modify the association. :setter affects
the *_to_one setter method, :adder the *_to_many add_* method,
:remover the *_to_many remove_* method, and :clearer the
*_to_many remove_all_* method.
Previously, you had to override a private method to get the same
behavior, this just offers a nicer API for that.
* A :keep_reference Database option has been added. When set to
false, a reference to the Database instance is not kept in
Sequel::DATABASES. This is designed for Database instances
created by libraries, so they don't accidentally get chosen as
the default Sequel::Model database.
* Model#modified! now accepts a column and marks that column
as changed. This is useful if you plan on mutating the column
value as opposed to reassigning it.
* Model#modified? now accepts a column and returns whether the
column has been changed.
* The migrators now support an :allow_missing_migration_files
option, which makes them silently ignore errors related to
missing migration files.
* validates_schema_types has been added to validation_helpers,
which validates that the column values are instances of the
expected ruby type for the given database schema type. This
is a more robust version of the validates_not_string
extension, and users of validates_not_string are encouraged
to switch soon, as validates_not_string is going away in
Sequel 4.
validates_schema_type has been added to validation_class_methods,
which performs the same validation, but it requires the columns
be listed explicitly.
validates_type in validation_helpers has been expanded to
accept an array of allowable classes.
Related to this is the addition of Database#schema_type_class for
returning the type class(es) for the given schema type symbol.
* validates_not_null has been added to the validation_helpers
plugin. This is similar to the validates_presence validation,
but only checks for nil values, allowing empty/blank strings.
* In the caching plugin, when the :ignore_exceptions option is true,
exceptions raised when deleting an object from the cache are now
ignored correctly.
* On PostgreSQL, Sequel now supports a :search_path Database
option to automatically set the client connection search_path.
This allows you to control which schemas do no require
qualification, and in which order to check schemas when
referencing unqualified objects. If you were using the
default_schema setting, it is recommended that you switch
to using :search_path instead.
* The pg_array extension can now register array types on a
per-Database basis via Database#register_array_type. Previously,
only global registration of array types was allowed. Additionally,
when registering array types on a per-Database basis, the oids can
be looked up automatically, making it possible to register array
types with just a type name:
DB.register_array_type(:interval)
* The pg_array extension now automatically creates conversion
procs for array types of all named types used by the
database. This means that if you use the pg_array and
pg_hstore extensions, the hstore[] type is now handled
correctly.
* The postgres adapter now supports :use_iso_date_format and
:convert_infinite_timestamps Database options. Previously,
use_iso_date_format was only a global setting, and
convert_infinite_timestamps could only be set after
initialization.
* Database#supports_schema_parsing? has been added to check
if schema parsing via the Database#schema method is
supported.
= Other Improvements
* A race condition related to prepared_sql for newly prepared
statements has been fixed.
* Dataset#get now works correctly if given an array with multiple
columns if there were no returned rows.
* The plugins that ship with Sequel now handle frozen model instances
correctly.
* Freezing of model instances now works correctly for models without
primary keys.
* Database constraints added with the constraint_validations
plugin now handle NULL values correctly if the :allow_nil=>true
setting is used.
* The pagination, pretty_table, query, schema_caching,
schema_dumper, and select_remove extensions can now be
loaded by Database#extension. If you are loading them
globally via Sequel.extension, switch to using
Database#extension, since that will be required starting
in Sequel 4.
* The lazy_attributes plugin no longer uses the identity_map plugin
internally, and eager loading lazy attributes now works correctly
without an active identity map.
* The many_to_one_pk_lookup plugin now handles many more corner
cases, and should be safe to enable by default.
* The static_cache plugin now has optimized implementations of
Model.map, .to_hash, and .to_hash_groups which work without a
database query. Model.count without arguments has also been
optimized to not require a database query.
* Fetching new records has been made faster when using the
update_primary_key plugin, since it was changed to cache the primary
key values lazily.
* When using the update_primary_key plugin, if the primary key
changes, clear the associations cache of all non-many_to_one
associations (since those will likely be based on the primary
key).
* The pg_typecast_on_load plugin no longer errors if given a
column that doesn't have a matching oid conversion proc.
* Handling of domain types on PostgreSQL has been significantly
improved. Domain type columns now have correct model
typecasting, and the pg_row extension correctly sets up
conversion procs for domain types inside composite types.
* Postgres::HStoreOp#- now automatically casts string input to
text, so that PostgreSQL doesn't assume the string is an
hstore.
* Postgres::PGRangeOp#starts_before and #ends_after have been
renamed to #ends_before and #starts_after. The previous
names were misleading. The old names are still available
for backwards compatibility, but they will be removed in the
Sequel 4.
* The pg_row plugin now handles aliased tables correctly.
* Model#validate in the validation_class_methods plugin no
longer skips validate methods in superclasses or previously
loaded plugins.
* Loading the touch plugin into a model subclass after it has
been loaded into a model superclass no longer ignores
inherited touched associations.
* Sequel no longer resets the conversion procs for the
Database instance when using Database#extension to load a
pg_* extension that adds global conversion procs. Instead,
the global conversion procs are added to the instance-specific
conversion procs. The result of this is that manually added
conversion procs will not be lost if an extension is loaded
afterward.
* The jdbc adapter now references the driver class before loading
subadapter specific code, which can fix issues if the database
tries to connect on initialization (such as the jdbc/postgres
adapter if the pg_hstore extension is loaded previously).
* A guide describing Sequel's support for advanced PostgreSQL
features has been added.
= Backwards Compatibility
* If you have already used the constraint_validations plugin to
create validations with the :allow_nil=>true option, you should
drop and regenerate those constraints to ensure they handle NULL
values correctly.
* The change to make PostgreSQL automatically handle domain
types can break previous code that set up special conversions
and typecasts per domain type. In the schema parsing, if you
want to get the domain type information, it will be contained
in the :db_domain_type and :domain_oid schema entries.
* Sequel::Postgres.use_iso_date_format is now only defined if
you are using the postgres adapter. Previously, it could
be defined when using other adapters with a pg_* extension,
even though the setting had no effect in that case.
* The validation_class_methods plugin now copies validations into
the subclass upon inheritance, instead of recursing into the
superclass on validation. This makes it more similar to how
all the other Sequel plugins work. However, it also means that
if you add validations to a superclass after creating a
subclass, the subclass won't have those validations. Additionally
if you skip superclass validations in a child class after creating
a grandchild class, the grandchild class could still have the
parent class's validations.
* The validates_unique validation in validation_helpers no longer
attempts to do the uniqueness query if the underlying columns
have validation errors. The reasoning behind this is that if the
underlying columns are not valid, the uniqueness query can cause
a DatabaseError.
* If you were passing strings in hstore format to
Postgres::HStoreOp#-, you should manually cast them to hstore:
hstore_op - Sequel.cast('a=>b', :hstore)
* The default validation error message for validates_type has been
modified.
* Database#schema_column_type was made public accidentally by an
adapter and a few extensions. That has been fixed, but if you
were calling it with an explicit receiver and it happened to
work by accident before, you'll need to update your code.
= Sequel 4 Implementation Planning
* Sequel 4 implementation work will begin shortly. All Sequel users
are encouraged to read about the proposed changes and provide
feedback on the implementation plan. For details, see
https://github.com/jeremyevans/sequel-4-plans.
---
### Doc Release Notes 3.48.0 (`doc/release_notes/3.48.0.txt`)
= Deprecation Warnings
The main change in Sequel 3.48.0 is the deprecation of Sequel
features that will be modified, moved, or removed in Sequel 4.
For the reasoning behind these changes, please review the
commits logs at
https://github.com/jeremyevans/sequel-4-plans/commits/master
== Deprecation Logging
If you use a deprecated method or feature, Sequel will by default
print a deprecation message and 10 lines of backtrace to stderr
to easily allow you to figure out which code needs to be
updated. You can change where the deprecation messages go and how
many lines of backtrace are given using the following:
# Log deprecation information to a file
Sequel::Deprecation.output = File.open('deprecated.txt', 'wb')
# Turn off all deprecation logging
Sequel::Deprecation.output = nil
# Use 5 lines of backtrace when logging deprecation messages
Sequel::Deprecation.backtrace_filter = 5
# Use all backtrace lines when logging deprecation messages
Sequel::Deprecation.backtrace_filter = true
# Don't include backtraces in the deprecation logging
Sequel::Deprecation.backtrace_filter = false
# Select which backtrace lines to output
Sequel::Deprecation.backtrace_filter = \
lambda{|line, line_no| line_no < 3 || line =~ /my_app/}
== Major Change
* The core extensions will no longer be loaded by default. You will
have to use `Sequel.extension :core_extensions` to load the core
extensions.
* The Symbol#[] and Symbol#{<,>,<=,>=} methods will no longer be
provided by the core extensions on ruby 1.8. You will have to
use `Sequel.extension :ruby18_symbol_extensions` to use them.
== Core Behavior Changes
* Dataset#filter becomes an alias for #where, and #exclude
becomes an alias for #exclude_where. You will have to
use `DB.extension :filter_having` to get the previous behavior.
Dataset#and and #or will also only affect the WHERE clause.
* Dataset#and, #or, and #invert will not raise errors for no existing
filter.
* Dataset#select_more becomes an alias for #select_append.
* Dataset#select and #from will not longer consider a hash argument as
an alias specification. You will have to use
`DB.extension :hash_aliases` to get the previous behavior.
* Database#dataset and Dataset.new will not take an options hash.
* Database#transaction :disconnect=>:retry option will be removed.
* Calling Dataset#add_graph_aliases before #graph or #set_graph_aliases
will raise an Error.
* Datasets will have a frozen options hash by default.
* Dataset#set_overrides and #set_defaults will move to the
set_overrides extension.
* Sequel.empty_array_handle_nulls will be removed. To get the
empty_array_handle_nulls = false behavior, you will have to
use `DB.extension :empty_array_ignore_nulls`.
* The second argument to Dataset #union, #intersect, and #except must
be an options hash if it is given.
* The fourth argument to Dataset #join_table must be an options
hash if it is given.
* Using a mismatched number of placeholders and arguments in a
placeholder literal string will raise an error.
* Dataset#graph_each will move to the graph_each extension.
* Database#default_schema will be removed.
* Dataset#[]= will be moved to the sequel_3_dataset_methods
extension.
* Dataset#insert_multiple will be moved to the
sequel_3_dataset_methods extension.
* Dataset#set will be moved to the sequel_3_dataset_methods
extension.
* Dataset#to_csv will be moved to the sequel_3_dataset_methods
extension.
* Dataset#db= and #opts= setters will be moved to the
sequel_3_dataset_methods extension.
* Dataset#qualify_to and #qualify_to_first_source will be moved to
the sequel_3_dataset_methods extension.
* Remove default methods that raise Sequel::NotImplemented:
Database#connect, #execute, #foreign_key_list, #indexes, #tables,
and #views, and Dataset#fetch_rows.
* Sequel::SQL::Expression#to_s will be removed.
* All Dataset methods in Dataset::PUBLIC_APPEND_METHODS except for
#literal, #quote_identifier, and #quote_schema_table will be
removed.
* All Dataset methods in Dataset::PRIVATE_APPEND_METHODS will
be removed.
* Sequel k_require, ts_require, tsk_require, and
check_requiring_thread will be removed.
* Dataset.def_append_methods will be removed.
* Dataset#table_ref_append will be removed.
* Sequel.virtual_row_instance_eval accessor will be removed.
* Database#reset_schema_utility_dataset will be removed.
== Adapter Behavior Changes
* The Database#do method will be removed from the ado, db2, dbi,
informix, odbc, openbase, and oracle adapters.
* The jdbc adapter will raise an error when parsing the schema
for a table if it detects results for the same table name in
multiple schemas.
* The Database#query method will be removed from the informix
adapter.
* Dataset#lock on PostgreSQL will check the given lock mode.
* Sequel will check the client_min_messages setting before
use on PostgreSQL.
* Prepared statement placeholders on PostgreSQL will no longer
support implicit casting via :$x__type.
== Extension Behavior Changes
* The following extensions will no longer make global changes to
the Database and Dataset classes: null_dataset, pagination,
pretty_table, query, schema_caching, schema_dumper,
select_remove, and to_dot. These will be changed to
Database/Dataset specific extensions.
* The pg_auto_parameterize and pg_statement_cache extensions will
be removed.
* Sequel::Dataset.introspect_all_columns will be removed from the
columns_introspection extension.
* PGRangeOp#starts_before and #ends_after will be removed from the
pg_range_ops extension.
== Model Behavior Changes
* Model#initialize will accept only one argument.
* The after_initialize hook will be moved to a plugin.
* Move blacklist-based security methods (#set_except, #update_except,
.set_restricted_columns) to a plugin.
* The :eager_loader and :eager_grapher association option procs will
always be passed a hash.
* Model string column setters will consider array and hash input to
be invalid.
* Remove save taking multiple arguments for the columns to save.
Add Model#save :columns option for saving specific columns.
* Don't automatically choose a reciprocal association with a condition
or block.
* Don't automatically set up reciprocal associations if multiple ones
match.
* Model::Errors#[] will no longer modify the receiver. If you want
autovivification, use the active_model plugin.
* Model.set_primary_key will not longer accept composite keys as
multiple arguments.
* The correlated_subquery eager limit strategy will be removed.
* The following Model class dataset methods will be removed: print,
each_page, paginate, set, add_graph_aliases, insert_multiple, query,
set_overrides, set_defaults, to_csv.
* The Model.{destroy,delete,update} class dataset methods will be
moved to the scissors plugin.
* Model#pk_or_nil will be removed.
* Model#set_values will no longer be called directly by any Sequel
code, and overriding it is deprecated. It will be removed in Sequel
4.1.
* Model.cache_anonymous_models accessor will move to Sequel module.
* Model::InstanceMethods.class_attr_overridable and
.class_attr_reader will be removed.
* The :one_to_one option check for one_to_many associations will
be removed.
== Plugin Behavior Changes
* Public dataset methods will no longer have class methods
automatically added.
* The validates_not_string validation will be removed from the
validation_class_methods and validation_helpers plugin.
* In the json_serializer plugin, the to_json :root=>true option
means :root=>:collection instead of :root=>:both.
* In the json_serializer plugin, the to_json :naked option will
default to true, and there will not be way to add the JSON.create_id
automatically.
* In the json_serializer plugin, from_json will no longer automatically
delete the JSON.create_id key from the input hash.
* The #to_json and #to_xml :all_columns and :all_associations options
in the json_serializer and xml_serializer plugins will be removed.
* The Model.json_create method will be removed from the
json_serializer plugin.
* The validates_type validation will raise validation errors for nil
if :allow_nil=>true is not used.
* auto_validate_presence_columns will be removed from the
auto_validations plugin
* The identity_map plugin will be removed.
== Internal Changes
* The sequel_core.rb and sequel_model.rb files will be removed.
* Dataset#{quote_identifiers,identifier_output_method,
identifier_input_method} will assume Database implements the
methods.
= Forwards Compatibility
Not all changes planned in Sequel 4 have deprecation warnings.
The following changes will be made in Sequel 4 but do not have
deprecation warnings in 3.48.0:
* The threaded connection pools will default to
:connection_handling=>:queue. You can manually set
:connection_handling=>:stack to get the current behavior.
* Dataset#join_table will default to :qualify=>:deep. You can
manually set :qualify=>:symbol to get the current behavior. This
can be set at a global level by overriding
Dataset#default_join_table_qualification.
* Model.raise_on_typecast_failure will default to false. Set this to
true to get the current behavior of raising typecast errors in the
setter methods.
* Model#save will no longer call Model#_refresh or Model#set_values
internally after an insert. Manually refreshes will be treated
differently than after creation refreshes in Sequel 4.
* On SQLite, integer_booleans will be true by default. Set this to
false to get the current behavior of 't' for true and 'f' for false.
* On SQLite, use_timestamp_timezones will be false by default. Set
this to true to get the current behavior with timezone information
in timestamps.
* The default value for most option hash arguments will be an empty
frozen hash. If you are overriding methods and modifying option
hashes, fix your code.
* The defaults_setter plugin will work in a lazy manner instead of
an eager manner. If you must have the values hash contain defaults
for new objects (instead of just getting defaults from getter
methods), you'll need to fork the current plugin.
* Model#set_all will allow setting the primary key columns.
* The many_to_one_pk_lookup plugin will be integrated into the
default associations support.
* The association_autoreloading plugin will be integrated into the
default associations support.
* Plugins will extend the class with ClassMethods before including
InstanceMethods in the class.
* Dataset#get, #select_map, and #select_order_map will automatically
add aliases for unaliased expressions if given a single expression.
* Database#tables and #views on PostgreSQL will check against
the current schemas in the search path.
* Sequel::SQL::SQLArray alias for ValueList will be removed.
* Sequel::SQL::NoBooleanInputMethods will be removed.
* Sequel::NotImplemented will be removed.
* Sequel::Model::EMPTY_INSTANCE_VARIABLES will be removed.
* Sequel will no longer provide a default database for the adapter or
integration specs.
= New Features
* You can now choose which Errors class to use on a per model basis
by overriding Model#errors_class.
* The following Database methods have been added to check for support:
supports_index_parsing?, supports_foreign_key_parsing?,
support_table_listing?, supports_view_listing?.
* The pg_hstore_ops extension now integrates with the pg_array,
pg_hstore, and pg_array_ops extensions, allowing you to pass in
arrays and hashes to be treated as PGArrays and HStores, and
returning ArrayOps for PostgreSQL functions/operators that
return arrays.
* Sequel.object_to_json and Sequel.json_parser_error_class
have been added and all internal json usage uses them, so you
can now override these methods if you want to use an alternative
json library with Sequel.
* The association_proxies plugin now accepts a block allowing the
user control over which methods are proxied to the dataset or
the cached array of instances. You can base the decision on
where to send the method using a variety of factors including
the method name, the method arguments, the state of the current
instance, or the related association. Here's an example of a
simple case just depending on the name of the method;
Model.plugin :association_proxies do |opts|
[:find, :where, :create].include?(opts[:method])
end
If the block returns true, the method is sent to the dataset,
otherwise it is sent to the array of associated objects.
* The auto_validations plugin now accepts a :not_null=>:presence
option, for doing a presence validation instead of a not_null
validation. This is useful for databases with NOT NULL
constraints where you also want to disallow empty strings.
* The auto_validations plugin now validates against explicit nil
values in NOT NULL columns that have defaults.
* The constraint_validations plugin now reflects validations, using
Model.constraint_validation_reflections.
Model.constraint_validation_reflections[:column]
# => [[:presence, {}],
# [:max_length, {:argument=>255, :message=>'just too long'}]]
* The constraint_validations plugin can now be set to pass specific
validations options to the validation_helpers plugin. This can be
useful if using the auto_validations plugin with this plugin to
avoid duplicate error messages for nil values:
Model.plugin :constraint_validations,
:validates_options=>{:presence=>{:allow_nil=>true}}
* The named_timezones extension can now be loaded as a database
extension, which allows for automatic conversions of string
timezones:
DB.extension :named_timezones
DB.timezone = 'America/Los_Angeles'
* Offsets are now emulated by Microsoft Access using a combination
of reverse orders and total counts. This is slow, especially on
large datasets, but probably better than having no support at all.
It is also possible to use the same code to support Microsoft
SQL Server 2000, but as Sequel does not support that (minimum
supported version is 2005), you have to do it manually:
Sequel.require 'adapters/utils/emulate_offset_with_reverse_and_count'
DB.extend_datasets Sequel::EmulateOffsetWithReverseAndCount
= Other Improvements
* Dataset#clone is now faster.
* Database methods that create datasets (fetch, from, select, get)
are now faster.
* Model.with_pk and .with_pk! are now faster.
* Dataset#or now just clones if given an empty argument, similar
to Dataset#where.
* Sequel now correctly frees statements after using them in the
ibmdb adapter. Previously, they weren't freed until GC, which
could result in errors if all available handles are in use.
* Dataset creation is now faster on Microsoft SQL Server.
* The mediumint and mediumtext types are now recognized on MySQL.
* The ado adapter now handles disconnecting an already disconnected
connection.
* The auto_validations plugin now works on databases that don't
support index parsing. However, it will not set up automatic
uniqueness validations on such databases.
* The validation_helpers is more strict in some cases when checking
for nil values, using a specific nil check instead of general
falsely check.
* The table inheritance plugins now correctly handle usage of
set_dataset in a subclass.
* The bin/sequel command line tool now has specs.
= Backwards Compatibility
* Sequel now uses aliases for many internal Dataset#get calls, such
as those used by table_exists? and max.
* Sequel now no longer uses class variables internally. Instead,
instance variables of the Sequel::Database class are used.
* Sequel now sets up the identifier mangling methods on Database
initialization instead of on first use.
* The private Database#adapter_initialize method has been added for
per adapter configuration. All internal adapters have been switched
to use this method instead of overriding initialize, and all
external adapters should as well. This makes sure that Database
instances are not added to Sequel::DATABASES until they have been
completely initialized.
* Virtual row blocks no longer convert their return values to an array.
Among other things, this means that having a virtual row block return
a hash works as expected.
* The private Dataset#hash_key_symbol method now only takes a single
argument.
* Database#constraint_validations in the constraint_validations plugin
now returns raw hash rows, instead of arrays of validation method
call arguments.
* Dataset#count now uses a lowercase count function in the SQL.
* Passing a non-String or Hash as the first argument to an adapter
method (e.g. Sequel.postgres(1)) now raises an error. Before, this used
to work on some adapters that implicitly converted the database
name to a string.
* The stats and dcov rake tasks were removed.
---
### Doc Release Notes 3.5.0 (`doc/release_notes/3.5.0.txt`)
New Plugins
-----------
* A class_table_inheritance plugin has been added, supporting model
inheritance in the database using a table-per-model-class approach.
Each table stores only attributes unique to that model or subclass
hierarchy.
For example, with this hierarchy:
Employee
/ \
Staff Manager
|
Executive
the following database schema may be used (table - columns):
* employees - id, name, kind
* staff - id, manager_id
* managers - id, num_staff
* executives - id, num_managers
The class_table_inheritance plugin assumes that the main table
(e.g. employees) has a primary key field (usually
autoincrementing), and all other tables have a foreign key of the
same name that points to the same key in their superclass's table.
For example:
* employees.id - primary key, autoincrementing
* staff.id - foreign key referencing employees(id)
* managers.id - foreign key referencing employees(id)
* executives.id - foreign key referencing managers(id)
When using the class_table_inheritance plugin, subclasses use joined
datasets:
Employee.dataset.sql # SELECT * FROM employees
Manager.dataset.sql # SELECT * FROM employees
# INNER JOIN managers USING (id)
Executive.dataset.sql # SELECT * FROM employees
# INNER JOIN managers USING (id)
# INNER JOIN executives USING (id)
This allows Executive.all to return instances with all attributes
loaded. The plugin overrides deleting, inserting, and updating
in the model to work with multiple tables, by handling each table
individually.
This plugin allows and encourages the use of a :key option to mark
a column holding the class name. This allows methods on the
superclass to return instances of specific subclasses.
a = Employee.all # [<#Staff>, <#Manager>, <#Executive>]
This plugin requires the lazy_attributes plugin and uses it to
handle subclass specific attributes that would not be loaded
when calling superclass methods (since those wouldn't join
to the subclass tables). For example:
a.first.values # {:id=>1, name=>'S', :kind=>'Staff'}
a.first.manager_id # Loads the manager_id attribute from the
# database
The class_table_inheritance plugin requires JOIN USING and
therefore is not supported on H2 or Microsoft SQL Server, which do
not support that SQL-92 feature.
* An associations_dependencies plugin was added for deleting,
destroying, or nullifying associated objects when destroying a
model object. This just gives an easy way to add the necessary
before and after destroy hooks. The following association types
support the following dependency actions:
* :many_to_many - :nullify (removes all related entries in join
table)
* :many_to_one - :delete, :destroy
* :one_to_many - :delete, :destroy, :nullify (sets foreign key to
NULL for all associated objects)
This plugin works directly with the association datasets and does
not use any cached association values. The :delete action will
delete all associated objects from the database in a single SQL
call. The :destroy action will load each associated object from the
database and call the destroy method on it.
The plugin call takes a hash of association symbol keys and
dependency action symbol values. Alternatively, you can specify
additional dependencies later using add_association_dependencies:
Business.plugin :association_dependencies, :address=>:delete
# or:
Artist.plugin :association_dependencies
Artist.add_association_dependencies :albums=>:destroy,
:reviews=>:delete, :tags=>:nullify
* A force_encoding plugin was added that forces the encoding of
strings used in model instances. When model instances are loaded
from the database, all values in the hash that are strings are
forced to the given encoding. Whenever you update a model column
attribute, the resulting value is forced to a given encoding if the
value is a string. There are two ways to specify the encoding.
You can either do so in the plugin call itself, or via the
forced_encoding class accessor:
class Album < Sequel::Model
plugin :force_encoding, 'UTF-8'
# or
plugin :force_encoding
self.forced_encoding = 'UTF-8'
end
This plugin only works on ruby 1.9, since strings don't have
encodings in 1.8.
* A typecast_on_load plugin was added, for fixing bad database
typecasting when loading model objects. Most of Sequel's database
adapters don't have complete control over typecasting, and may
return columns that aren't typecast correctly (with correct being
defined as how the model object would typecast the same column
values).
This plugin modifies Model.load to call the setter methods (which
typecast by default) for all columns given. You can either specify
the columns to typecast on load in the plugin call itself, or
afterwards using add_typecast_on_load_columns:
Album.plugin :typecast_on_load, :release_date, :record_date
# or:
Album.plugin :typecast_on_load
Album.add_typecast_on_load_columns :release_date, :record_date
If the database returns release_date and record_date columns as
strings instead of dates, this will ensure that if you access those
columns through the model object, you'll get Date objects instead of
strings.
* A touch plugin was added, which adds Model#touch for updating an
instance's timestamp, as well as touching associations when an
instance is updated or destroyed.
The Model#touch instance method saves the object with a modified
timestamp. By default, it uses the :updated_at column, but you can
set which column to use. It also supports touching of associations,
so that when the current model object is updated or destroyed, the
associated rows in the database can have their modified timestamp
updated to the current timestamp. Example:
class Album < Sequel::Model
plugin :touch, :column=>:modified_on, :associations=>:artist
end
* A subclasses plugin was added, for recording all of a models
subclasses and descendent classes. Direct subclasses are available
via the subclasses method, and all descendent classes are available
via the descendents method:
c = Class.new(Sequel::Model)
c.plugin :subclasses
sc1 = Class.new(c)
sc2 = Class.new(c)
ssc1 = Class.new(sc1)
c.subclasses # [sc1, sc2]
sc1.subclasses # [ssc1]
sc2.subclasses # []
ssc1.subclasses # []
c.descendents # [sc1, ssc1, sc2]
The main use case for this is if you want to modify all models
after the model subclasses have been created. Since mutable
options are copied when subclassing, modifying parent classes
does not affect current subclasses, only future ones. The
subclasses plugin allows you get all subclasses so that you can
easily modify them. The plugin only records subclasses
created after the plugin call, though.
* An active_model plugin was added, giving Sequel::Model an
ActiveModel complaint API, in so much as it passes the
ActiveModel::Lint tests.
New Extensions
--------------
* A named_timezones extension was added, allowing you to use named
timezones such as "America/Los_Angeles" (the default Sequel
timezone support only supports UTC or local time). This extension
requires TZInfo. It also sets the Sequel.datetime_class to
DateTime, so database timestamps will be returned as DateTime
instances instead of Time instances. This is because ruby's
Time class doesn't support timezones other than UTC and local time.
This plugin allows you to pass either strings or TZInfo::Timezone
instance to Sequel.database_timezone=, application_timezone=, and
typecast_timezone=. If a string is passed, it is converted to a
TZInfo::Timezone using TZInfo::Timezone.get.
Let's say you have the database server in New York and the
application server in Los Angeles. For historical reasons, data
is stored in local New York time, but the application server only
services clients in Los Angeles, so you want to use New York
time in the database and Los Angeles time in the application. This
is easily done via:
Sequel.database_timezone = 'America/New_York'
Sequel.application_timezone = 'America/Los_Angeles'
Then, before timestamps are stored in the database, they are
converted to New York time. When timestamps are retrieved from the
database, they are converted to Los Angeles time.
* A thread_local_timezones extension was added. This allows you to
set a per-thread timezone that will override the default global
timezone while the thread is executing. The main use case is for
web applications that execute each request in its own thread, and
want to set the timezones based on the request. The most common
example is having the database always store time in UTC, but have
the application deal with the timezone of the current user. That
can be done with:
Sequel.database_timezone = :utc
# In each thread:
Sequel.thread_application_timezone = current_user.timezone
This extension is designed to work with the named_timezones
extension.
* An sql_expr extension was added that adds .sql_expr methods to
all objects, giving them easy access to Sequel's DSL:
1.sql_expr < :a # 1 < a
false.sql_expr & :a # FALSE AND a
true.sql_expr | :a # TRUE OR a
~nil.sql_expr # NOT NULL
"a".sql_expr + "b" # 'a' || 'b'
Proc#sql_expr uses a virtual row:
proc{[[a, b], [a, c]]}.sql_expr | :x
# (((a = b) AND (a = c)) OR x)
* A looser_typecasting extension was added, for using to_f and to_i
instead of the more strict Kernel.Float and Kernel.Integer when
typecasting floats and integers. To use it, you should extend the
database with the Sequel::LooserTypecasting module after loading
the extension:
Sequel.extension :looser_typecasting
DB.extend(Sequel::LooserTypecasting)
This makes the behavior more like ActiveRecord:
a = Artist.new(:num_albums=>'a')
a.num_albums # => 0
Other New Features
------------------
* Associations now support composite keys. All of the :*key options
options now accept arrays of symbols instead of plain symbols.
Example:
Artist.primary_key # [:name, :city]
Album.many_to_one :artist, :key=>[:artist_name, :artist_city]
Artist.one_to_many :albums, :key=>[:artist_name, :artist_city]
All association types are supported, including the built-in
many_to_many association and the many_through_many plugin. Both
methods of eager loading work with composite keys for all
association types. Setter and add/remove/remove_all methods
also now work with composite keys.
* Associations now respect a :validate option, which can be set to
false to not validate when implicitly saving associated objects.
There isn't a lot of implicit saving in Sequel's association
methods, but this gives the user the control over validation when
the association methods implicitly save an object.
* In addition to the regular association methods, the
nested_attributes plugin was also updated to respect the
:validate_association option. It was also modified to not validate
associated objects twice, once when the parent object was validated
and again when the associated object was saved. Additionally, if
you pass :validate=>false to the save method when saving the parent
object, it will not longer attempt to validate associated objects
when saving them.
* Dataset#insert and #insert_sql were refactored and now support the
following API:
* No arguments - Treat as a single empty hash argument
* Single argument:
* Hash - Use keys as columns and values as values
* Array - Use as values, without specifying columns
* Dataset - Use a subselect, without specifying columns
* LiteralString - Use as the values
* 2 arguments:
* Array, Array - Use first array as keys, second as values
* Array, Dataset - Use a subselect, with the array as columns
* Array, LiteralString - Use LiteralString as the values, with
the array as the columns
* Anything else: Treat all given values an an array of values
* Graphing now works with previously joined datasets. The main use
case of this is when eagerly loading (via eager_graph) model
associations for models backed by joined datasets, such as those
created by the class_table_inheritance plugin.
* Sequel.virtual_row was added allowing you to easily use the
VirtualRow support outside of select, order, and filter calls:
net_benefit = Sequel.virtual_row{revenue > cost}
good_employee = Sequel.virtual_row{num_commendations > 0}
fire = ~net_benefit & ~good_employee
demote = ~net_benefit & good_employee
promote = net_benefit & good_employee
DB[:employees].filter(fire).update(:employed=>false)
DB[:employees].filter(demote).update(:rank=>:rank-1)
DB[:employees].filter(promote).update(:rank=>:rank+1)
* When Sequel wraps exception in its own classes (to provide database
independence), it now keeps the wrapped exception available in
a wrapped_exception accessor. This allows you to more easily
determine the wrapped exception class, without resorting to parsing
the exception message.
begin
DB.run('...')
rescue Sequel::DatabaseError => e
case e.wrapped_exception
when Mysql::Error
...
when PGError
...
end
end
* The MySQL adapter now supports a Dataset#split_multiple_result_sets
method that yields arrays of rows (one per result set), instead of
rows. This allows you to submit multiple statements at the same
time (or call a stored procedure that returns multiple result
sets), and know which rows are related to which result sets.
This violates a lot of Sequel's internal assumptions and should be
used with care. Existing row_procs are modified to work correctly,
but graphing will not work on these datasets.
* The ADO adapter now accepts a :conn_string option and uses that
as the full ADO connection string. This can be used to connect to
any datasource ADO supports, such as Microsoft Excel.
* The Microsoft SQL Server shared adapter now supports a
Database#server_version method.
* The Microsoft SQL Server shared adapter now supports updating and
deleting from joined datasets.
* The Microsoft SQL Server shared adapter now supports a
Dataset#output method that uses the OUTPUT clause.
* Model#_save now calls either Model#_insert or Model#_update for
inserting/updating the row in the database. This allows for easier
overriding when you want to allow creating and updating model
objects backed by a joined dataset.
* Dataset#graph now takes a :from_self_alias option specifying the
alias to use for the subselect created if the receiver is a joined
but not yet graphed dataset. It defaults to the first source table
in the receiver.
Other Improvements
------------------
* Typecasting model attributes is now done before checking existing
values, instead of after. Before, the code for the model attribute
setters would compare the given value to the existing entry. If it
didn't match, the value was typecasted and then assigned. That led
to the following situation:
a = Album[1]
a.num_tracks # => 10
params # => {'num_tracks'=>'10'}
a.set(params)
a.changed_columns # => [:num_tracks]
The new behavior typecasts the value first, and only sets it and
records the column as changed if it doesn't match the typecasted
value.
* Model#modified? is now always true if the record is new. modified?
indicates the instance's status relative to the database, and since
a new object is not yet in the database, and saving the object
would add it, the object is considered modified. A consequence of
this is that Model#save_changes now always saves if the object is
new.
If you want to check if there were changes to columns since the
object was first initialized, you should use
!changed_columns.empty?, which was the historical way to handle
the situation.
* The DataObjects (do) adapter now supports DataObjects 0.10.
* Dataset#select_more and Dataset#order_more no longer affect the
receiver. They are supposed to just return a modified copy of the
receiver instead of modifying the receiver itself. For a few
versions they have been broken in that they modified the receiver
in addition to returning a modified copy.
* Performance was increased for execution of prepared statements
with multiple bound variables on MySQL.
* On MySQL, database errors raised when preparing statements or
setting bound variable values are now caught and raised as
Sequel::DatabaseErrors.
* On MySQL, more types of disconnection errors are detected.
* When altering columns in MySQL, options such as :unsigned,
:elements, and :size that are given in the call are now respected.
* MySQL enum defaults are now handled correctly in the schema dumper.
* The schema dumper no longer attempts to use unparseable defaults
as literals on MySQL, since MySQL does not provide defaults as
valid literals.
* The emulated offset support in the shared Microsoft SQL Server
adapter now works better with model classes (or any datasets with
row_procs).
* Microsoft SQL Server now supports using the WITH clause in delete,
update, and insert calls.
* Parsed indexes when connecting to Microsoft SQL Server via JDBC no
longer include primary key indexes.
* Dataset#insert_select now returns nil if disable_insert_returning
is used in the shared PostgreSQL adapter. This makes it work as
expected with model object creation.
* Calling Model.set_primary_key with an array of symbols to set
a composite primary key is now supported. You can also provide
multiple symbol arguments to do the same thing. Before, specifying
an array of symbols broke the Model.[] optimization.
* Literalization of timezones in timestamps now works correctly on
Oracle.
* __FILE__ and __LINE__ are now used everywhere that eval is called
with a string, which makes for better backtraces.
* The native MySQL adapter now correctly handles returning before
yielding all result sets. Previously, this caused a commands out
of sync error.
* Table names in common table expressions are now quoted.
* The Oracle adapter's Dataset#except now accepts a hash, giving it
the same API as the default Dataset#except.
* When connecting to Microsoft SQL Server via ADO, allow
Dataset#insert to take multiple arguments.
* Fractional timestamps are no longer used on ODBC.
* Schema parsing now works on MSSQL when the database is set to not
quote identifiers.
* Timezone offsets are no longer used on Microsoft SQL Server, since
they only work for the datetimeoffset type.
* Only 3 fractional digits in timestamps are u