sequel 3.5.0 → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/CHANGELOG +108 -0
  2. data/README.rdoc +25 -14
  3. data/Rakefile +20 -1
  4. data/doc/advanced_associations.rdoc +61 -64
  5. data/doc/cheat_sheet.rdoc +16 -7
  6. data/doc/opening_databases.rdoc +3 -3
  7. data/doc/prepared_statements.rdoc +1 -1
  8. data/doc/reflection.rdoc +2 -1
  9. data/doc/release_notes/3.6.0.txt +366 -0
  10. data/doc/schema.rdoc +19 -14
  11. data/lib/sequel/adapters/amalgalite.rb +5 -27
  12. data/lib/sequel/adapters/jdbc.rb +13 -3
  13. data/lib/sequel/adapters/jdbc/h2.rb +17 -0
  14. data/lib/sequel/adapters/jdbc/mysql.rb +20 -7
  15. data/lib/sequel/adapters/mysql.rb +4 -3
  16. data/lib/sequel/adapters/oracle.rb +1 -1
  17. data/lib/sequel/adapters/postgres.rb +87 -28
  18. data/lib/sequel/adapters/shared/mssql.rb +47 -6
  19. data/lib/sequel/adapters/shared/mysql.rb +12 -31
  20. data/lib/sequel/adapters/shared/postgres.rb +15 -12
  21. data/lib/sequel/adapters/shared/sqlite.rb +18 -0
  22. data/lib/sequel/adapters/sqlite.rb +1 -16
  23. data/lib/sequel/connection_pool.rb +1 -1
  24. data/lib/sequel/core.rb +1 -1
  25. data/lib/sequel/database.rb +1 -1
  26. data/lib/sequel/database/schema_generator.rb +2 -0
  27. data/lib/sequel/database/schema_sql.rb +1 -1
  28. data/lib/sequel/dataset.rb +5 -179
  29. data/lib/sequel/dataset/actions.rb +123 -0
  30. data/lib/sequel/dataset/convenience.rb +18 -10
  31. data/lib/sequel/dataset/features.rb +65 -0
  32. data/lib/sequel/dataset/prepared_statements.rb +29 -23
  33. data/lib/sequel/dataset/query.rb +429 -0
  34. data/lib/sequel/dataset/sql.rb +67 -435
  35. data/lib/sequel/model/associations.rb +77 -13
  36. data/lib/sequel/model/base.rb +30 -8
  37. data/lib/sequel/model/errors.rb +4 -4
  38. data/lib/sequel/plugins/caching.rb +38 -15
  39. data/lib/sequel/plugins/force_encoding.rb +18 -7
  40. data/lib/sequel/plugins/hook_class_methods.rb +4 -0
  41. data/lib/sequel/plugins/many_through_many.rb +1 -1
  42. data/lib/sequel/plugins/nested_attributes.rb +40 -11
  43. data/lib/sequel/plugins/serialization.rb +17 -3
  44. data/lib/sequel/plugins/validation_helpers.rb +65 -18
  45. data/lib/sequel/sql.rb +23 -1
  46. data/lib/sequel/version.rb +1 -1
  47. data/spec/adapters/mssql_spec.rb +96 -10
  48. data/spec/adapters/mysql_spec.rb +19 -0
  49. data/spec/adapters/postgres_spec.rb +65 -2
  50. data/spec/adapters/sqlite_spec.rb +10 -0
  51. data/spec/core/core_sql_spec.rb +9 -0
  52. data/spec/core/database_spec.rb +8 -4
  53. data/spec/core/dataset_spec.rb +122 -29
  54. data/spec/core/expression_filters_spec.rb +17 -0
  55. data/spec/extensions/caching_spec.rb +43 -3
  56. data/spec/extensions/force_encoding_spec.rb +43 -1
  57. data/spec/extensions/nested_attributes_spec.rb +55 -2
  58. data/spec/extensions/validation_helpers_spec.rb +71 -0
  59. data/spec/integration/associations_test.rb +281 -0
  60. data/spec/integration/dataset_test.rb +383 -9
  61. data/spec/integration/eager_loader_test.rb +0 -65
  62. data/spec/integration/model_test.rb +110 -0
  63. data/spec/integration/plugin_test.rb +306 -0
  64. data/spec/integration/prepared_statement_test.rb +32 -0
  65. data/spec/integration/schema_test.rb +8 -3
  66. data/spec/integration/spec_helper.rb +1 -25
  67. data/spec/model/association_reflection_spec.rb +38 -0
  68. data/spec/model/associations_spec.rb +184 -8
  69. data/spec/model/eager_loading_spec.rb +23 -0
  70. data/spec/model/model_spec.rb +8 -0
  71. data/spec/model/record_spec.rb +84 -1
  72. metadata +9 -2
@@ -25,7 +25,7 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
25
25
 
26
26
  == Using raw SQL
27
27
 
28
- DB << "CREATE TABLE users (name VARCHAR(255) NOT NULL, age INT(3) NOT NULL)"
28
+ DB.run "CREATE TABLE users (name VARCHAR(255) NOT NULL, age INT(3) NOT NULL)"
29
29
  dataset = DB["SELECT age FROM users WHERE name = ?", name]
30
30
  dataset.map(:age)
31
31
  DB.fetch("SELECT name FROM users") do |row|
@@ -79,9 +79,9 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
79
79
  dataset.where(:value=>[50,75,100])
80
80
 
81
81
  dataset.filter(:name => 'abc').first
82
- dataset[:name => 'abc'] # same as above
82
+ dataset[:name => 'abc']
83
83
 
84
- # Filter using a subquery
84
+ dataset.where('price > (SELECT avg(price) + 100 FROM table)')
85
85
  dataset.filter{|o| o.price > dataset.select(o.avg(price) + 100)}
86
86
 
87
87
  === Advanced filtering using ruby expressions
@@ -198,12 +198,21 @@ Transactions can also be aborted by raising Sequel::Rollback:
198
198
  raise(Sequel::Rollback) if something_bad_happened
199
199
  end # ROLLBACK issued and no error raised
200
200
 
201
- Miscellaneous:
201
+ Savepoints can be used if the database supports it:
202
+
203
+ DB.transaction do
204
+ dataset << {:first_name => 'Farm', :last_name => 'Boy'} # Inserted
205
+ DB.transaction(:savepoint=>true) # This savepoint is rolled back
206
+ dataset << {:first_name => 'Inigo', :last_name => 'Montoya'} # Not inserted
207
+ raise(Sequel::Rollback) if something_bad_happened
208
+ end
209
+ dataset << {:first_name => 'Prince', :last_name => 'Humperdink'} # Inserted
210
+ end
211
+
212
+ == Miscellaneous:
202
213
 
203
214
  dataset.sql #=> "SELECT * FROM items"
204
215
  dataset.delete_sql #=> "DELETE FROM items"
205
- dataset.where(:name => 'sequel').exists #=> "EXISTS ( SELECT 1 FROM items WHERE name = 'sequel' )"
216
+ dataset.where(:name => 'sequel').exists #=> "EXISTS ( SELECT * FROM items WHERE name = 'sequel' )"
206
217
  dataset.columns #=> array of columns in the result set, does a SELECT
207
-
208
- # Works on PostgreSQL, MySQL, SQLite, and JDBC
209
218
  DB.schema(:items) => [[:id, {:type=>:integer, ...}], [:name, {:type=>:string, ...}], ...]
@@ -94,9 +94,9 @@ possibly through WINE, but that's fairly unlikely).
94
94
  The following options are supported:
95
95
  * :driver - The driver to use. The default if not specified is 'SQL Server'.
96
96
  * :command_timeout - Sets the time in seconds to wait while attempting
97
- to execute a command before cancelling the attempt and generating
98
- an error. Specifically, it sets the ADO CommandTimeout property.
99
- If this property is not set, the default of 30 seconds is used.
97
+ to execute a command before cancelling the attempt and generating
98
+ an error. Specifically, it sets the ADO CommandTimeout property.
99
+ If this property is not set, the default of 30 seconds is used.
100
100
  * :conn_string - The full ADO connection string. If this is provided,
101
101
  the general connection options are ignored.
102
102
  * :provider - Sets the Provider of this ADO connection (for example, "SQLOLEDB")
@@ -49,7 +49,7 @@ may itself contain placeholders:
49
49
  == Prepared Statements
50
50
 
51
51
  Prepared statement support is similar to bound variable support, but you
52
- use Dataset#prepare with a name, and Dataset#call later with the values:
52
+ use Dataset#prepare with a name, and Dataset#call or Database#call later with the values:
53
53
 
54
54
  ds = DB[:items].filter(:name=>:$n)
55
55
  ps = ds.prepare(:select, :select_by_name)
@@ -10,7 +10,7 @@ You can get the adapter in use using Database.adapter_scheme. As this is a clas
10
10
 
11
11
  == Database Connected To
12
12
 
13
- In some case, the adapter scheme will be the same as the database to which you are connecting. However, many adapters support multiple databases. You can use the Database#database_type method to get the type of database to which you are connecting:
13
+ In some cases, the adapter scheme will be the same as the database to which you are connecting. However, many adapters support multiple databases. You can use the Database#database_type method to get the type of database to which you are connecting:
14
14
 
15
15
  DB.database_type # :postgres, :h2, :mssql
16
16
 
@@ -36,6 +36,7 @@ Database#schema takes a table symbol and returns column information in an array
36
36
  * :db_type - The type of column the database provided, as a string. Used by the schema_dumper plugin for a more specific type translation.
37
37
  * :default - The default value of the column, as either a string or nil. Uses a database specific format. Used by the schema_dumper plugin for converting to a ruby value.
38
38
  * :primary_key - Whether this column is one of the primary key columns for the table. Used by the Sequel::Model code to determine primary key columns.
39
+ * :ruby_default - The default value of the column as a ruby object, or nil if there is no default or the default could not be successfully parsed into a ruby object.
39
40
  * :type - The type of column, as a symbol (e.g. :string). Used by the Sequel::Model typecasting code.
40
41
 
41
42
  Example:
@@ -0,0 +1,366 @@
1
+ New Features
2
+ ------------
3
+
4
+ * Dataset#filter and related methods now accept a string with named
5
+ placeholders, and a hash with placeholder values:
6
+
7
+ ds.filter('copies_sold > :sales', :sales=>500000)
8
+
9
+ Sequel's general support for this syntax is nicer:
10
+
11
+ ds.filter{copies_sold > 500000}
12
+
13
+ But named placeholder support can make it easier to port code
14
+ from other database libraries. Also, it works much better than
15
+ the ? placeholder support if you have a long SQL statement:
16
+
17
+ DB['SELECT :n FROM t WHERE p > :q AND p < :r', :n=>1,:q=>2,:r=>3]
18
+
19
+ Sequel doesn't subsitute values that don't appear in the hash:
20
+
21
+ ds.where('price < :p AND id in :ids', :p=>100)
22
+ # WHERE (price < 100 AND id in :ids)
23
+
24
+ This makes it easier to spot missed placeholders, and avoids issues
25
+ with PostgreSQL's :: casting syntax or : inside string literals.
26
+
27
+ * The Model add_ association method now accepts a hash and creates
28
+ a new associated model object associated to the receiver:
29
+
30
+ Artist[:name=>'YJM'].add_album(:name=>'RF')
31
+
32
+ * The Model remove_ association method now accepts a primary key
33
+ and removes the associated model object from the association. For
34
+ models using composite primary keys, an array of primary key values
35
+ can be used. Example:
36
+
37
+ Artist[:name=>'YJM'].remove_album(1) # regular pk
38
+ Artist[:name=>'YJM'].remove_album([2, 3]) # composite pk
39
+
40
+ * Dataset#bind was added, allowing you to bind values before calling
41
+ Dataset#call. This is more consistent with Sequel's general
42
+ approach where queries can be built in any order.
43
+
44
+ * The native postgres adapter now has Dataset#use_cursor, which
45
+ allows you to process huge datasets without keeping all records in
46
+ memory. The default number of rows per cursor fetch is 1000, but
47
+ that can be modified:
48
+
49
+ DB[:huge_table].use_cursor.each{|r| p r}
50
+ DB[:huge_table].use_cursor(:rows_per_fetch=>10000).each{|r| p r}
51
+
52
+ This probably won't work with prepared statements or
53
+ bound variables.
54
+
55
+ * The nested_attributes plugin now adds newly created objects to the
56
+ cached association array immediately, even though the changes
57
+ are not persisted to the database until after the object is saved.
58
+ The reasoning for this is that otherwise there is no way to access
59
+ the newly created associated objects before the save, and no way
60
+ to access them at all if validation fails.
61
+
62
+ This makes the nested_attributes plugin much easier to use, since
63
+ now you can just iterate over the cached association array when
64
+ building the form. If validation fails, it will have the newly
65
+ created failed objects in the array, so you can easily display the
66
+ form as the user entered it for them to make changes.
67
+
68
+ This change doesn't affect many_to_one associations, since those
69
+ don't have a cached association array. This also does not affect
70
+ updating existing records, since those are already in the cached
71
+ array.
72
+
73
+ * You can now easily override the default options used in the
74
+ validation_helpers plugin (the recommended validation plugin).
75
+ Options can be overridden at a global level:
76
+
77
+ Sequel::Plugins::ValidationHelpers::DEFAULT_OPTIONS[:format].
78
+ merge!(:message=>"incorrect format", :allow_missing=>true)
79
+
80
+ Options can also be overridden on a per-class level:
81
+
82
+ class Album < Sequel::Model
83
+ plugin :validation_helpers
84
+ DEFAULT_VALIDATION_OPTIONS = {
85
+ :format=>{:message=>"incorrect format", :allow_missing=>true}}
86
+
87
+ private
88
+
89
+ def default_validation_helpers_options(type)
90
+ super.merge(DEFAULT_VALIDATION_OPTIONS[type] || {})
91
+ end
92
+ end
93
+
94
+ * You can now use a proc instead of a string for the
95
+ validation_helpers :message option. This should allow much
96
+ easier internationalization support. If a proc is given, Sequel
97
+ calls it to get the format string to use. Whether the proc should
98
+ take an argument depends on whether the associated validation
99
+ method takes an argument before the array of columns to validate,
100
+ and the argument provided is what is passed to the proc. The
101
+ exception to this is the validates_not_string method, which doesn't
102
+ take an argument, but does pass one to the proc (a symbol with the
103
+ schema type of the column).
104
+
105
+ Combined with the above default option support, full
106
+ internationalization support for the validation_helpers plugin
107
+ should be fairly easy.
108
+
109
+ * The nested_attributes plugin now accepts a :fields option that
110
+ specifies the fields that are allowed. If specified, the
111
+ plugin will use set_only instead of set when mass assigning
112
+ attributes. Without this, the only way to control which fields
113
+ are allowed is to set allowed/restricted attributes at a class
114
+ level in the associated class.
115
+
116
+ * Associations now accept a :distinct option which uses the SQL
117
+ DISTINCT clause. This can be used instead of :uniq for
118
+ many_to_many and many_through_many associations to handle
119
+ the uniqueness in the database instead of in ruby. It can
120
+ also be useful for one_to_many associations to models that
121
+ don't have primary keys.
122
+
123
+ * The caching plugin now accepts an :ignore_exceptions option that
124
+ allows it to work with memcached (which raises exceptions instead
125
+ of returning nil for missing records).
126
+
127
+ * Sequel now emulates JOIN USING poorly using JOIN ON for databases
128
+ that don't support JOIN USING (MSSQL and H2). This isn't
129
+ guaranteed to work for all queries, since USING and ON have
130
+ different semantics, but should work in most cases.
131
+
132
+ * The MSSQL shared adapter now supports insert_select, for faster
133
+ model object creation. If for some reason you need to disable it,
134
+ you can use disable_insert_output.
135
+
136
+ * Model#modified! has been added which explicitly marks the object
137
+ as modified. So even if no column values have been modified,
138
+ calling save_changes/update will still run through the regular
139
+ save process and call all before and after save/update hooks.
140
+
141
+ * Model#marshallable! has been added which removes unmarshallable
142
+ attributes from the object. Previously, you couldn't marshal
143
+ a saved model object because it contained a dataset with a
144
+ singleton class. Custom _dump and _load methods could be used
145
+ instead, but this approach is easier to implement.
146
+
147
+ * Dataset#literal_other now calls sql_literal on the object with
148
+ the current dataset instance, if the object responds to it.
149
+ This makes it easier to support the literalization of arbitrary
150
+ objects.
151
+
152
+ Note that if the object is a subclass of a class handled by
153
+ an existing dataset literalization method, you cannot use this
154
+ method. You have to override the specific Dataset#literal_* method
155
+ in that case.
156
+
157
+ * Model#save_changes now accepts an option hash that is passed to
158
+ save:
159
+
160
+ album.save_changes(:validate=>false)
161
+
162
+ * A bunch of Dataset#*_join methods have been added, for specific
163
+ join types:
164
+
165
+ * cross_join
166
+ * natural_join
167
+ * full_join
168
+ * left_join
169
+ * right_join
170
+ * natural_full_join
171
+ * natural_left_join
172
+ * natural_right_join
173
+
174
+ Previously, you had to use join_table(:cross, ...) to use a CROSS
175
+ JOIN.
176
+
177
+ * You can now create clustered indexes on Microsoft SQL Server using
178
+ the :clustered option.
179
+
180
+ * AssociationReflection#associated_object_keys has been added,
181
+ specifying the keys in the associated model object that are related
182
+ to this association.
183
+
184
+ * Sequel::SQL::SQLArray#to_a was added.
185
+
186
+ Other Improvements
187
+ ------------------
188
+
189
+ * Constant lookup in virtual row blocks now works correctly in ruby
190
+ 1.9. Virtual row blocks are based on BasicObject on ruby 1.9,
191
+ which doesn't allow referencing objects in the top level scope. So
192
+ the following code would cause an error on 1.9:
193
+
194
+ DB[:bonds].filter{maturity_date > Time.now}
195
+
196
+ Sequel now uses a Sequel::BasicObject class on 1.9 with a
197
+ const_missing that looks up constants in Object, which allows the
198
+ above code to work.
199
+
200
+ * Sequel no longer attempts to load associated objects when
201
+ one of the key fields in the current table is NULL. This fixes
202
+ the behavior when the :primary_key option for the association
203
+ is used to point to a non-primary key.
204
+
205
+ A consequence of this change is that attempting to load a
206
+ *_to_many association for a new model object now returns
207
+ an empty array instead of raising an exception. This has its
208
+ own advantage of allowing the same association viewing code
209
+ to work on both new and existing objects. Previously, you had
210
+ to actively avoid calling the association method on new objects,
211
+ or Sequel would raise an exception.
212
+
213
+ * Dataset aggreate methods (sum/avg/min/max/range/interval) now
214
+ work correctly with limited, grouped, or compound datasets.
215
+ Previously, count worked with them, but other aggregate methods
216
+ did not. These methods now use a subquery if called on a
217
+ limited, grouped or compound dataset.
218
+
219
+ * It is no longer required to have an existing GROUP BY clause
220
+ to use a HAVING clause (except on SQLite, which doesn't permit
221
+ it). Sequel has always had this limitation, but it's not required
222
+ by the SQL standard, and there are valid reasons to use HAVING
223
+ without GROUP BY.
224
+
225
+ * Sequel will now emulate support for databases that don't support
226
+ multiple column IN/NOT IN syntax, such as MSSQL and SQLite:
227
+
228
+ ds.filter([:col1, :col2]=>[[1, 2], [3, 4]].sql_array)
229
+ # default: WHERE (col1, col2) IN ((1, 2), (3, 4))
230
+ # emulated: WHERE (((col1 = 1) AND (col2 = 2)) OR
231
+ # ((col1 = 3) AND (col2 = 4)))
232
+
233
+ This is necessary for eager loading associated objects for models
234
+ with composite primary keys.
235
+
236
+ * Sequel now emulates :column.ilike('blah%') for case insensitive
237
+ searches on MSSQL and H2. MSSQL is case insensitive by default,
238
+ so it is the same as like. H2 is case sensitive, so Sequel
239
+ uses a case insensitive cast there.
240
+
241
+ * The nested_attributes plugin no longer allows modification of
242
+ keys related to the association. This fixes a possible security
243
+ issue with the plugin, where a user could associate the nested
244
+ record to a different record. For example:
245
+
246
+ Artist.one_to_many :albums
247
+ Artist.plugin :nested_attributes
248
+ Artist.nested_attributes :albums
249
+ artist = Artist.create
250
+ artist2 = Artist.create
251
+ album = Album.create
252
+ artist.add_album(album)
253
+ artist.albums_attributes = [{:id=>album.id,
254
+ :artist_id=>artist2.id}]
255
+ artist.save
256
+
257
+ * The one_to_many remove_* association method now makes sure that the
258
+ object to be removed is currently associated to this object.
259
+ Before, the method could be abused to disassociate the object from
260
+ whatever object it was associated to.
261
+
262
+ * Model add_ and remove_ association methods now check that the passed
263
+ object is of the correct class.
264
+
265
+ * Calling the add_* association method no longer adds the record
266
+ to the cached association array if the object is already in the
267
+ array. Previously, Sequel did this for reciprocal associations,
268
+ but not for regular associations.
269
+
270
+ This makes the most sense for one_to_many associations, since
271
+ those can only be associated to the object once. For many_to_many
272
+ associations, if you want an option to disable the behavior, please
273
+ bring it up on the Sequel mailing list.
274
+
275
+ * An array with a string and placeholders that is passed to
276
+ Dataset#filter is no longer modified. Previously:
277
+
278
+ options = ["name like ?", "%dog%"]
279
+ DB[:players].where(options)
280
+ options # => ["%dog%"]
281
+
282
+ * Getting the most recently inserted autoincremented primary key
283
+ is now optimized when connecting to MySQL via JDBC.
284
+
285
+ * Model.inherited now calls Class.inherited.
286
+
287
+ * The MSSQL shared adapter once again works on ruby 1.9. It was
288
+ broken in 3.5.0 due to minor syntax issues.
289
+
290
+ * The force_encoding plugin now handles refreshing an existing
291
+ object, either explicitly or implicitly when new objects are
292
+ created.
293
+
294
+ To use the force_encoding plugin with the identity_map plugin, the
295
+ identity_map plugin should be loaded first.
296
+
297
+ * Using nil as a bound variable now works on PostgreSQL. Before,
298
+ Sequel would incorrectly use "" instead of NULL, since it
299
+ transformed all objects to strings before binding them. Sequel
300
+ now binds the objects directly.
301
+
302
+ * The Amalgalite adapter is now significantly faster, especially for
303
+ code that modifies the schema or submits arbitrary SQL statements
304
+ using Database <<, run, or execute_ddl.
305
+
306
+ * Model#save_changes is now used when updating existing associated
307
+ objects in the nested_attributes plugin. This should be
308
+ significantly faster for the common case of submitting a complex
309
+ form with nested objects without making modifications.
310
+
311
+ * You can now prepare insert statements that take multiple arguments,
312
+ such as insert(1, 2, 3) and insert(columns, values).
313
+
314
+ * Dataset#group_and_count now supports aliased columns.
315
+
316
+ * Adding indexes to tables outside the default schema now works.
317
+
318
+ * Eager graphing now works better with models that use aliased tables.
319
+
320
+ * Sequel now correctly parses the column schema information for tables
321
+ in a non-default schema on Microsoft SQL Server.
322
+
323
+ * changed_columns is now cleared for when saving new model objects
324
+ for adapters that support insert_select, such as PostgreSQL.
325
+
326
+ * Dataset#replace on MySQL now works correctly when default values
327
+ are used.
328
+
329
+ * Dataset#lock on PostgreSQL now works correctly.
330
+
331
+ * Dataset#explain now works correctly on SQLite, and works using
332
+ any adapter. It also works correctly on Amalgalite.
333
+
334
+ * The JDBC adapter now handles binding Time arguments correctly when
335
+ using prepared statements.
336
+
337
+ * Model add_ and remove_ association methods now have more
338
+ descriptive exception messages.
339
+
340
+ * Dataset#simple_select_all? now ignores options that don't affect
341
+ the SQL, such as :server.
342
+
343
+ * Dataset#window in the PostgreSQL adapter now respects existing
344
+ named windows.
345
+
346
+ * Sequel now better handles a failure to begin a new transaction.
347
+
348
+ * The dataset code was split into some additional files for improved
349
+ readability.
350
+
351
+ * Many documentation improvements were made.
352
+
353
+ Backwards Compatibility
354
+ -----------------------
355
+
356
+ * Model::Errors no longer uses a default proc, but emulates one in the
357
+ [] method. This is unlikely to have a negative affect unless you
358
+ are calling a method on it that doesn't call [] (maybe using it in
359
+ a C extension?).
360
+
361
+ * Model#table_name now only provides the alias if an aliased table is
362
+ used.
363
+
364
+ * The Sequel::Dataset::STOCK_COUNT_OPTS constant has been removed.
365
+
366
+ * Dataset#lock on PostgreSQL now returns nil instead of a dataset.