Once again, a superb job Jeremy.
Thank you.
Luke
Jeremy Evans wrote:
> Sequel 3.5.0 has been released and should be available on the gem
> mirrors. The 3.5.0 release adds numerous improvements:
>
> 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) adpater 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 used in Microsoft SQL
> Server, since an error is raised if the use the datetime type
> with more than that.
>
> * The integration test suite now has guards for expected failures
> when run on known databases. Expected failures are marked as
> pending.
>
> Backwards Compatibility
> -----------------------
>
> * Graphing to an previously joined (but not graphed) dataset now
> causes the receiver to be wrapped in a subselect, so if you
> graph a dataset to a previously joined dataset, and then filter
> the dataset referring to tables that were in the joined dataset
> (other than the first table), the SQL produced will probably no
> longer be valid. You should either filter the dataset before
> graphing or use the name of the first source of the joined
> dataset (which is what the subselected is aliased to) if filtering
> afterward.
>
> In certain cases, this change can cause tables to be aliased
> differently, so if you were graphing previously joined datasets
> and then filtering using the automatically generated aliases, you
> might need to modify your code.
>
> * The DataObjects (do) adpater no longer supports DataObjects 0.9.x.
>
> * The Dataset#virtual_row_block_call private instance method has
> been removed.
>
> * Sequel's timezone support was significantly refactored, so if you
> had any custom modifications to the timezone support, they might
> need to be refactored as well.
>
> * The SQL generation code was significantly refactored, so if you
> had any custom modifications in that area, you might need to
> refactor as well.
>
> Thanks,
> Jeremy
> >
>
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"sequel-talk" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/sequel-talk?hl=en
-~----------~----~----~----~------~----~------~--~---