1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
|
= New Features
* There have been numerous improvements this release related to
frozen datasets. Frozen datasets now work in almost all cases,
except when calling a dataset mutation method.
When using ruby 2.4, Sequel uses the new support for
clone(:freeze=>false) to actually freeze datasets while allowing
them to copy singleton classes/extended modules from the dataset
calling clone. On earlier versions of ruby, the dataset opts
are now frozen, preventing more types of accidental modification.
The dataset internals were refactored to reduce the number of
instance variables. Now, datasets store all of their state
in opts. Additionally, all datasets now use a thread-safe
cache for storing cached state such as the dataset's columns.
Previously, accessing/setting the columns was not thread-safe,
unless the ruby interpreter used thread-safe methods for
instance variable getting/setting.
Frozen datasets use this new cache to optimize repeated method
calls, resulting in substantial performance speedups. This can
include caching returned and/or intermediate datasets, SELECT and
DELETE SQL generated, as well as internal objects designed to
optimize the building of SQL strings with different arguments.
Even for fairly simple datasets, this can result in up to 10x
performance improvements for dataset methods that don't require
database access, and up to 3x performance improvements for dataset
methods that do require database access.
* A freeze_datasets Database extension has been added which
automatically freezes all datasets for the Database instance.
This also enables dataset caching when creating datasets using
Database#[] and #from using a single symbol, such as
DB[:table_name]. In addition to speeding up the methods
themselves, this also allows code such as:
DB[:foo].for_update.first
To run much faster by avoiding any dataset creation or SQL
string building after the first call.
The freeze_datasets extension makes #dup an alias of #clone,
ensuring that all cloned datasets that were originally created
by the Database instance are frozen.
It is highly recommended that you start using the
freeze_datasets extension in your applications using Sequel,
as this extension will become the default and only behavior
in Sequel 5. Unfrozen datasets and dataset mutation will
not be supported in Sequel 5.
* The dataset methods created by Model#subset and
Model::DatasetModule#subset now cache the returned dataset if the
current dataset is frozen, none of the arguments are Procs, and a
block is not provided. This can result in up to a 3x performance
improvement for method chains that use subsets, such as:
ModelClass.subset1.subset2.subset3.first
* Model::DatasetModule has had the following methods added to it:
distinct, exclude, exclude_having, grep, group, group_and_count,
group_append, having, limit, offset, order, order_append,
order_prepend, select, select_all, select_append, select_group,
where, and server. These methods create dataset methods that
when called call the dataset method with the same name on the
receiver. Example:
class ModelClass < Sequel::Model
dataset_module do
select :with_id_and_name, :id, :name
where :active, :active
order :by_name, :name
end
end
ModelClass.active.by_name.with_id_and_name.all
# SELECT id, name FROM model_classes WHERE active ORDER BY name
# Equivalent to:
ModelClass.
where(:active).
order(:name).
select(:id, :name).
all
In addition to being easier than defining the methods manually, this
also enables caching of the datasets in most cases, so that the
above method chain does not create any additional datasets after the
first call.
* Dataset#with_extend now accepts a block and will create a module
with that block that will be used to extend the object, after any
modules given as arguments have been applied:
DB[:table].with_extend{def foo; 1 end}.foo => 1
* The identifier mangling support for datasets
(identifier_input_method and identifier_output_method) has been
moved to a identifier_mangling database extension, but it is still
loaded by default. You can disable the loading of this extension
by using the :identifier_mangling=>false Database option. Sequel
5 will stop loading of this extension by default, requiring you to
load it manually via Database#extension if you need it.
Sequel's default remains the same as before, to convert identifiers
to uppercase on input and lowercase on output on databases that
fold unquoted identifiers to uppercase (per the SQL standard), and
to not mangle identifiers at all on databases that fold unquoted
identifiers to lowercase (MySQL, PostgreSQL, SQLite). The
identifier_mangling extension just allows you to change the default
behavior.
* On DB2, Dataset#with_convert_smallint_to_bool has been added,
which returns a modified dataset with the
convert_smallint_to_bool setting changed. Previously,
chaging the smallint_to_bool setting required mutating a
dataset.
* The mock adapter now supports Dataset#with_{autoid,fetch,numrows},
allowing mocking of results when using frozen datasets.
= Other Improvements
* Using an eager load callback when eager loading a one_to_one
association that uses an order or offset now works correctly
on databases that do not support window functions.
* Dataset#== and Dataset#hash are now faster as they don't need
to generate SQL. As all internal state is now stored in the
opts, it just considers the class, db, and opts.
* The prepared statement/bound variable internals were heavily
refactored to be simpler and more robust, to more easily
support native prepared statements, and to work with frozen
datasets.
* When emulating alter table operations on SQLite, integer
primary keys now use AUTOINCREMENT, since that is Sequel's
default when creating tables on SQLite.
* On SQLite, Database#schema no longer uses :auto_increment entries
when the table has a composite primary key.
* Most dataset opts values are now frozen to prevent accidental
modification and allow for thread-safe access.
* SQL::Expression subclass instances are now always frozen.
* Dataset::PlaceholderLiteralizer and
Dataset::PlaceholderLiteralizer::Argument instances are now
always frozen.
* Dataset#ungraphed now works on a frozen model dataset.
* Model#set_server now works when the model uses a frozen dataset.
* The pagination and null_dataset extensions now work on frozen
datasets.
* Dataset#server now works for frozen model datasets when the
model uses the sharding plugin.
* Calling eager_graph or association_join on a model dataset
is now deprecated if it would ignore the association's
:conditions option and the :graph_conditions, :graph_block,
or :graph_only_conditions association option is not used.
* Using the :eager_limit dataset option in an eager_load
callback with a singular association now raises an Error.
Previously, the behavior was undefined.
* Calling Dataset#prepare without a name argument is now
deprecated. Previously, it raised an Error in the mysql, mysql2,
and postgres adapters, but was allowed on other adapters.
* The looser_typecasting extension now handles the strict
BigDecimal parsing introduced in ruby 2.4.
* When using the duplicate_columns_handler extension with
:on_duplicate_columns=>:warn, the warning message is now
prepend with the file and line.
* Internally, Sequel uses Dataset#where instead of #filter,
reverse instead of reverse_order, and select_append instead
of select_more to save a method call and array creation.
* Dataset#db= and #opts= in the sequel_3_dataset_methods
extension now raise a RuntimeError if the dataset is frozen.
* Sequel's tests now run without warnings when using Minitest
5.10.
* Sequel now issues a deprecation message instead of a warning
when used with PostgreSQL <8.2.
= Backwards Compatibility
* Any external dataset extensions or adapters that modified or
directly accessed dataset instance variables other than @db and
@opts (such as @columns) needs to be updated to work with the
new dataset internals.
* Any external adapters that implemented native prepared statements/
bound variables need to be updated to work with the new internal
prepared statement API.
* Model.set_dataset and .dataset= now operate on a clone of the
dataset given, instead of mutating the dataset that is passed in.
This allows them to work with frozen datasets, but can change
the behavior if you mutate a dataset after passing it to one
of these methods. Anyone doing that needs to change their code
to get the current copy of the model's dataset, and mutate that,
or better yet, avoid mutating datasets at all.
* Dataset#columns now calls #columns! instead of the other way around,
which may require external plugins/extensions that override #columns
to switch to overriding #columns!.
* External adapters that want to disable identifier mangling by
default need to be updated.
|