ANN: Sequel 3.32.0 Released

Sequel is a lightweight database access toolkit for Ruby.

* Sequel provides thread safety, connection pooling and a concise
  DSL for constructing SQL queries and table schemas.
* Sequel includes a comprehensive ORM layer for mapping records to
  Ruby objects and handling associated records.
* Sequel supports advanced database features such as prepared
  statements, bound variables, stored procedures, savepoints,
  two-phase commit, transaction isolation, master/slave
  configurations, and database sharding.
* Sequel currently has adapters for ADO, Amalgalite, DataObjects,
  DB2, DBI, Firebird, IBM_DB, Informix, JDBC, MySQL, Mysql2, ODBC,
  OpenBase, Oracle, PostgreSQL, SQLite3, Swift, and TinyTDS.

Sequel 3.32.0 has been released and should be available on the gem
mirrors.

= 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 perferable, 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.

Thanks,
Jeremy

* {Website}[http://sequel.rubyforge.org]
* {Source code}[http://github.com/jeremyevans/sequel]
* {Blog}[http://sequel.heroku.com]
* {Bug tracking}[http://github.com/jeremyevans/sequel/issues]
* {Google group}[http://groups.google.com/group/sequel-talk]
* {RDoc}[http://sequel.rubyforge.org/rdoc]

···

--
Posted via http://www.ruby-forum.com/.