File: 3.24.0.txt

package info (click to toggle)
ruby-sequel 5.63.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 10,408 kB
  • sloc: ruby: 113,747; makefile: 3
file content (420 lines) | stat: -rw-r--r-- 16,373 bytes parent folder | download | duplicates (7)
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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
= 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::Indentifier, 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.