sequel 2.10.0 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/CHANGELOG +51 -1
  2. data/README.rdoc +2 -2
  3. data/Rakefile +2 -2
  4. data/doc/advanced_associations.rdoc +6 -18
  5. data/doc/release_notes/1.0.txt +38 -0
  6. data/doc/release_notes/1.1.txt +143 -0
  7. data/doc/release_notes/1.3.txt +101 -0
  8. data/doc/release_notes/1.4.0.txt +53 -0
  9. data/doc/release_notes/1.5.0.txt +155 -0
  10. data/doc/release_notes/2.0.0.txt +298 -0
  11. data/doc/release_notes/2.1.0.txt +271 -0
  12. data/doc/release_notes/2.10.0.txt +328 -0
  13. data/doc/release_notes/2.11.0.txt +215 -0
  14. data/doc/release_notes/2.2.0.txt +253 -0
  15. data/doc/release_notes/2.3.0.txt +88 -0
  16. data/doc/release_notes/2.4.0.txt +106 -0
  17. data/doc/release_notes/2.5.0.txt +137 -0
  18. data/doc/release_notes/2.6.0.txt +157 -0
  19. data/doc/release_notes/2.7.0.txt +166 -0
  20. data/doc/release_notes/2.8.0.txt +171 -0
  21. data/doc/release_notes/2.9.0.txt +97 -0
  22. data/lib/sequel_core/adapters/ado.rb +3 -0
  23. data/lib/sequel_core/adapters/db2.rb +0 -11
  24. data/lib/sequel_core/adapters/dbi.rb +0 -11
  25. data/lib/sequel_core/adapters/do.rb +0 -12
  26. data/lib/sequel_core/adapters/firebird.rb +21 -16
  27. data/lib/sequel_core/adapters/informix.rb +1 -11
  28. data/lib/sequel_core/adapters/jdbc.rb +1 -13
  29. data/lib/sequel_core/adapters/jdbc/h2.rb +3 -11
  30. data/lib/sequel_core/adapters/jdbc/mysql.rb +0 -17
  31. data/lib/sequel_core/adapters/jdbc/postgresql.rb +3 -15
  32. data/lib/sequel_core/adapters/mysql.rb +31 -27
  33. data/lib/sequel_core/adapters/odbc.rb +34 -28
  34. data/lib/sequel_core/adapters/openbase.rb +0 -11
  35. data/lib/sequel_core/adapters/oracle.rb +11 -9
  36. data/lib/sequel_core/adapters/postgres.rb +14 -17
  37. data/lib/sequel_core/adapters/shared/mssql.rb +6 -15
  38. data/lib/sequel_core/adapters/shared/mysql.rb +29 -14
  39. data/lib/sequel_core/adapters/shared/oracle.rb +4 -0
  40. data/lib/sequel_core/adapters/shared/postgres.rb +30 -35
  41. data/lib/sequel_core/adapters/shared/progress.rb +4 -0
  42. data/lib/sequel_core/adapters/shared/sqlite.rb +73 -13
  43. data/lib/sequel_core/adapters/sqlite.rb +8 -18
  44. data/lib/sequel_core/adapters/utils/date_format.rb +21 -0
  45. data/lib/sequel_core/{dataset → adapters/utils}/stored_procedures.rb +0 -0
  46. data/lib/sequel_core/{dataset → adapters/utils}/unsupported.rb +0 -0
  47. data/lib/sequel_core/core_ext.rb +1 -1
  48. data/lib/sequel_core/core_sql.rb +9 -4
  49. data/lib/sequel_core/database.rb +63 -62
  50. data/lib/sequel_core/dataset.rb +9 -4
  51. data/lib/sequel_core/dataset/convenience.rb +10 -9
  52. data/lib/sequel_core/dataset/prepared_statements.rb +1 -1
  53. data/lib/sequel_core/dataset/sql.rb +130 -36
  54. data/lib/sequel_core/schema/sql.rb +2 -2
  55. data/lib/sequel_core/sql.rb +44 -51
  56. data/lib/sequel_core/version.rb +1 -1
  57. data/lib/sequel_model/associations.rb +25 -17
  58. data/lib/sequel_model/base.rb +35 -7
  59. data/lib/sequel_model/caching.rb +1 -6
  60. data/lib/sequel_model/record.rb +23 -5
  61. data/lib/sequel_model/validations.rb +20 -5
  62. data/spec/adapters/firebird_spec.rb +6 -1
  63. data/spec/adapters/mysql_spec.rb +12 -0
  64. data/spec/adapters/postgres_spec.rb +2 -2
  65. data/spec/adapters/sqlite_spec.rb +81 -2
  66. data/spec/integration/dataset_test.rb +2 -2
  67. data/spec/integration/type_test.rb +12 -2
  68. data/spec/sequel_core/core_sql_spec.rb +46 -12
  69. data/spec/sequel_core/database_spec.rb +24 -12
  70. data/spec/sequel_core/dataset_spec.rb +82 -32
  71. data/spec/sequel_core/schema_spec.rb +16 -0
  72. data/spec/sequel_model/associations_spec.rb +89 -0
  73. data/spec/sequel_model/base_spec.rb +66 -0
  74. data/spec/sequel_model/eager_loading_spec.rb +32 -0
  75. data/spec/sequel_model/record_spec.rb +9 -9
  76. data/spec/sequel_model/spec_helper.rb +3 -0
  77. data/spec/sequel_model/validations_spec.rb +63 -3
  78. metadata +41 -4
@@ -0,0 +1,155 @@
1
+ You can now graph a dataset and have the result split into component
2
+ tables:
3
+
4
+ DB[:artists].graph(:albums, :artist_id=>:id).first
5
+ # => {:artists=>{:id=>artists.id, :name=>artists.name}, \
6
+ # :albums=>{:id=>albums.id, :name=>albums.name,
7
+ :artist_id=>albums.artist_id}}
8
+
9
+ This aliases columns if necessary so they don't stomp on each other,
10
+ which
11
+ is what usually happens if you just join the tables:
12
+
13
+ DB[:artists].left_outer_join(:albums, :artist_id=>:id).first
14
+ # => {:id=>(albums.id||artists.id),
15
+ :name=>(albums.name||artist.names), \
16
+ :artist_id=>albums.artist_id}
17
+
18
+ Models can use graph as well, in which case the values will be model
19
+ objects:
20
+
21
+ Artist.graph(Album, :artist_id=>:id)
22
+ # => {:artists=>#<Artist...>, :albums=>#<Album...>}
23
+
24
+ Models can now eager load via .eager_graph, which will load all the
25
+ results
26
+ and all associations in a single query. This is necessary if you want
27
+ to
28
+ filter on columns in associated tables. It works exactly the same way
29
+ as
30
+ .eager, and supports cascading of associations as well:
31
+
32
+ # Artist.one_to_many :albums
33
+ # Album.one_to_many :tracks
34
+ # Track.many_to_one :genre
35
+ Artist.eager_graph(:albums=>{:tracks=>:genre}).filter( \
36
+ :tracks_name=>"Firewire").all
37
+
38
+ This will give you all artists have have an album with a track named
39
+ "Firewire", and calling .albums on one of those artists will only return
40
+ albums that have a track named "Firewire", and calling .tracks on one of
41
+ those albums will return only the track(s) named "Firewire".
42
+
43
+ You can use set_graph_aliases to select specific columns:
44
+
45
+ DB[:artists].graph(:albums, :artist_id=>:id).set_graph_aliases( \
46
+ :artist_name=>[:artists, :name], :album_name=>[:albums,
47
+ :name]).first
48
+ # => {:artists=>{:name=>artists.name}, :albums=>{:name=>albums.name}}
49
+
50
+ You can use eager_graph with set_graph_aliases to have eager loading
51
+ with
52
+ control over the SELECT clause.
53
+
54
+ All associations now update their reciprocal associations whenever the
55
+ association methods are used, so you don't need to refresh the
56
+ association or model to have the reciprocal association updated:
57
+
58
+ Album.many_to_one :band
59
+ Band.one_to_many :albums
60
+
61
+ # Note that all of these associations are cached,
62
+ # so after the first access there are no additional
63
+ # database queries to fetch associated records.
64
+
65
+ # many_to_one setter adds to reciprocal association
66
+ band1.albums # => []
67
+ album1.band = band1
68
+ band1.albums # => [album1]
69
+ band2.albums # => []
70
+ album1.band = band2
71
+ band1.albums # => []
72
+ band2.albums # => [album1]
73
+ album1.band = band2
74
+ band2.albums # => [album1]
75
+ album1.band = nil
76
+ band2.albums # => []
77
+
78
+ # one_to_many add_* method sets reciprocal association
79
+ # one_to_many remove_* method removes reciprocal association
80
+ album1.band # => nil
81
+ band1.add_album(album1)
82
+ album1.band # => band1
83
+ band2.add_album(album1)
84
+ album1.band # => band2
85
+ band2.remove_album(album1)
86
+ album1.band # => nil
87
+
88
+ Post.many_to_many :tags
89
+ Tag.many_to_many :posts
90
+
91
+ # many_to_many add_* method adds to reciprocal association
92
+ # many_to_many remove_* method removes from reciprocal association
93
+ post1.tags # => []
94
+ tag1.posts # => []
95
+ tag1.add_post(post1)
96
+ post1.tags # => [tag1]
97
+ tag1.posts # => [post1]
98
+ tag1.remove_post(post1)
99
+ post1.tags # => []
100
+ tag1.posts # => []
101
+ post1.add_tag(tag1)
102
+ post1.tags # => [tag1]
103
+ tag1.posts # => [post1]
104
+ post1.remove_tag(tag1)
105
+ post1.tags # => []
106
+ tag1.posts # => []
107
+
108
+ The MySQL and PostgreSQL adapters now support index types:
109
+
110
+ index :some_column, :type => :hash # or :spatial, :full_text, :rtree,
111
+ etc.
112
+
113
+ Starting in Sequel 1.5.0, some methods are deprecated. These methods
114
+ will be
115
+ removed in Sequel 2.0.0. The deprecation framework is fairly flexible.
116
+ You
117
+ can choose where the messages get sent:
118
+
119
+ Sequel::Deprecation.deprecation_message_stream = STDERR # the default
120
+ Sequel::Deprecation.deprecation_message_stream = \
121
+ File.new('deprecation.txt', 'wb') # A file
122
+ Sequel::Deprecation.deprecation_message_stream = nil # ignore the
123
+ messages
124
+
125
+ You can even have all deprecation messages accompanied by a traceback,
126
+ so you
127
+ can see exactly where in your code you are using a deprecated method:
128
+
129
+ Sequel::Deprecation.print_tracebacks = true
130
+
131
+ All deprecation methods come with an message telling you what
132
+ alternative code
133
+ will work.
134
+
135
+ In addition to deprecating some methods, we removed the ability to have
136
+ arrays returned instead of hashes. The array code still had debugging
137
+ messages
138
+ left it in, and we are not aware of anyone using it. Hashes have been
139
+ returned
140
+ by default since Sequel 0.3.
141
+
142
+ We have also removed the Numeric date/time extensions (e.g. 3.days.ago).
143
+ The
144
+ existing extensions were incomplete, better ones are provided elsewhere,
145
+ and the extensions were not really related to Sequel's purpose.
146
+
147
+ Sequel no longer depends on ParseTree, RubyInline, or ruby2ruby. They
148
+ are
149
+ still required to use the block filters. Sequel's only gem dependency
150
+ is on
151
+ the tiny metaid.
152
+
153
+ Sequel 1.5.0 has fixes for 12 tracker issues, including fixes to the
154
+ Informix,
155
+ MySQL, ODBC, ADO, JDBC, Postgres, and SQLite adapters.
@@ -0,0 +1,298 @@
1
+ Blockless Filter Expressions
2
+ ----------------------------
3
+
4
+ Before 2.0.0, in order to specify complex SQL expressions, you
5
+ either had to resort to writing the SQL yourself in a string or
6
+ using an expression inside a block that was parsed by ParseTree.
7
+ Because ParseTree was required, only ruby 1.8.* was supported, and
8
+ supporting other ruby versions (ruby 1.9, JRuby, Rubinius) would
9
+ never be possible.
10
+
11
+ With 2.0.0, you no longer need to use a block to write complex SQL
12
+ expressions. The basics of the blockless filters are the usual
13
+ arithmetic, inequality, and binary operators:
14
+
15
+ + = addition
16
+ - = subtraction
17
+ * = multiplication
18
+ / = division
19
+ > = greater than
20
+ < = less than
21
+ >= = greater than or equal to
22
+ <= = less than or equal to
23
+ ~ = negation
24
+ & = AND
25
+ | = OR
26
+
27
+ You can use these operators on Symbols, LiteralStrings, and other
28
+ Sequel::SQL::Expressions. Note that there is no equal operator or
29
+ not equal operator, to specify those, you use a Hash.
30
+
31
+ Here are some examples:
32
+
33
+ # Ruby code => SQL WHERE clause
34
+ :active => active
35
+ ~:active => NOT active
36
+ ~~:active => active
37
+ ~~~:active => NOT active
38
+ :is_true[] => is_true()
39
+ ~:is_true[] => NOT is_true()
40
+ :x > 100 => (x > 100)
41
+ :x < 100.01 => (x < 100.01)
42
+ :x <= 0 => (x <= 0)
43
+ :x >= 1 => (x >= 1)
44
+ ~(:x > 100) => (x <= 100)
45
+ {:x => 100} => (x = 100)
46
+ {:x => 'a'} => (x = 'a')
47
+ {:x => nil} => (x IS NULL)
48
+ ~{:x => 100} => (x != 100)
49
+ ~{:x => 'a'} => (x != 'a')
50
+ ~{:x => nil} => (x IS NOT NULL)
51
+ {:x => /a/} => (x ~ 'blah') # Default, MySQL different
52
+ ~{:x => /a/} => (x !~ 'blah') # Default, MySQL different
53
+ :x.like('a') => (x LIKE 'a')
54
+ ~:x.like('a') => (x NOT LIKE 'a')
55
+ :x.like(/a/) => (x ~ 'a') # Default, MySQL different
56
+ ~:x.like('a', /b/) => ((x NOT LIKE 'a') AND (x !~ 'b')) # Default
57
+ ~{:x => 1..5} => ((x < 1) OR (x > 5))
58
+ ~{:x => DB[:items].select(:i)} => (x NOT IN (SELECT i FROM items))
59
+ ~{:x => [1,2,3]} => (x NOT IN (1, 2, 3))
60
+ :x + 1 > 100 => ((x + 1) > 100)
61
+ (:x * :y) < 100.01 => ((x * y) < 100.01)
62
+ (:x - :y/2) >= 100 => ((x - (y / 2)) >= 100)
63
+ (((:x - :y)/(:x + :y))*:z) <= 100 => ((((x - y) / (x + y)) * z) <=
64
+ 100)
65
+ ~((((:x - :y)/(:x + :y))*:z) <= 100) => ((((x - y) / (x + y)) * z) >
66
+ 100)
67
+ :x & :y => (x AND y)
68
+ :x & :y & :z => ((x AND y) AND z)
69
+ :x & {:y => :z} => (x AND (y = z))
70
+ {:y => :z} & :x => ((y = z) AND x)
71
+ {:x => :a} & {:y => :z} => ((x = a) AND (y = z))
72
+ (:x > 200) & (:y < 200) => ((x > 200) AND (y < 200))
73
+ :x | :y => (x OR y)
74
+ :x | :y | :z => ((x OR y) OR z)
75
+ :x | {:y => :z} => (x OR (y = z))
76
+ {:y => :z} | :x => ((y = z) OR x)
77
+ {:x => :a} | {:y => :z} => ((x = a) OR (y = z))
78
+ (:x > 200) | (:y < 200) => ((x > 200) OR (y < 200))
79
+ (:x | :y) & :z => ((x OR y) AND z)
80
+ :x | (:y & :z) => (x OR (y AND z))
81
+ (:x & :w) | (:y & :z) => ((x AND w) OR (y AND z))
82
+ ~((:x | :y) & :z) => ((NOT x AND NOT y) OR NOT z)
83
+ ~((:x & :w) | (:y & :z)) => ((NOT x OR NOT w) AND (NOT y OR NOT z))
84
+ ~((:x > 200) | (:y & :z)) => ((x <= 200) AND (NOT y OR NOT z))
85
+ ~('x'.lit + 1 > 100) => ((x + 1) <= 100)
86
+ 'x'.lit.like(/a/) => (x ~ 'a') # (x ~ \'a\')
87
+
88
+ None of these require blocks, you can use any directly in a call to
89
+ filter:
90
+
91
+ DB[:items].filter((:price * :tax) - :discount > 100)
92
+ # => SELECT * FROM items WHERE (((price * tax) - discount) > 100)
93
+ DB[:items].filter(:active & ~:archived)
94
+ # => SELECT * FROM items WHERE (active AND NOT archived)
95
+
96
+ SQL String Concatenation
97
+ ------------------------
98
+
99
+ Sequel now has support for expressing SQL string concatenation in an
100
+ easy way:
101
+
102
+ [:name, :title].sql_string_join(" - ")
103
+ # SQL: name || ' - ' || title
104
+
105
+ You can use this in selecting columns, creating filters, ordering
106
+ datasets, and possibly elsewhere.
107
+
108
+ Schema Reflection Support/Typecasting on Assignment
109
+ ---------------------------------------------------
110
+
111
+ When used with PostgreSQL, MySQL, or SQLite, Sequel now has the
112
+ ability to get information from the database's schema in regards
113
+ to column types:
114
+
115
+ DB.schema(:artist)
116
+ => [[:id, {:type=>:integer, :db_type=>"integer", :max_chars=>0
117
+ :numeric_precision=>32, :allow_null=>false,
118
+ :default=>"nextval('artist_id_seq'::regclass)"}], [:name,
119
+ {:type=>:string, :default=>nil, :db_type=>"text",
120
+ :numeric_precision=>0, :allow_null=>true, :max_chars=>0}]]
121
+
122
+ Models now use this information to typecast values on attribute
123
+ assignment. For example, if you have an integer column named number
124
+ and a text (e.g. varchar) column named title:
125
+
126
+ 1.5.1:
127
+ model.number = '1'
128
+ model.number # => '1'
129
+ model.title = 1
130
+ model.title # => 1
131
+ 2.0.0:
132
+ model.number = '1'
133
+ model.number # => 1
134
+ model.title = 1
135
+ model.title # => '1'
136
+
137
+ Typecasting can be turned off on a global, per class, and per object
138
+ basis:
139
+
140
+ Sequel::Model.typecast_on_assignment = false # Global
141
+ Album.typecast_on_assignment = false # Per Class
142
+ Album.new.typecast_on_assignment = false # Per Object
143
+
144
+ Typecasting is somewhat strict, it does not allow obviously bogus
145
+ data to be used:
146
+
147
+ model.number = 'a' # Raises error
148
+
149
+ This is in contrast to how some other ORMs handle the situation:
150
+
151
+ model.number = 'a'
152
+ model.number # => 0
153
+
154
+ If Sequel is being used with a web framework and you want to display
155
+ friendly error messages to the user, you should probably turn
156
+ typecasting off and set up the necessary validations in your models.
157
+
158
+ Model Association Improvements
159
+ ------------------------------
160
+
161
+ Associations can now be eagerly loaded even if they have a block,
162
+ though the block should not rely on being evaluated in the context
163
+ of an instance. This allows you filter on associations when eagerly
164
+ loading:
165
+
166
+ Artist.one_to_many :albums_with_10_tracks, :class=>:Album do |ds|
167
+ ds.filter(:num_tracks => 10)
168
+ end
169
+ Artist.filter(:name.like('A%)).eager(:albums_with_10_tracks).all
170
+ # SELECT * FROM artists WHERE (name LIKE 'A%')
171
+ # SELECT albums.* FROM albums WHERE ((artist_id IN (...)) AND
172
+ # (num_tracks = 10))
173
+
174
+ Associations now have a remove_all_ method for removing all
175
+ associated objects in a single query:
176
+
177
+ Artist.many_to_many :albums
178
+ Artist[1].remove_all_albums
179
+ # DELETE FROM albums_artists WHERE artist_id = 1
180
+
181
+ Artist.one_to_many :albums
182
+ Artist[1].remove_all_albums
183
+ # UPDATE albums SET artist_id = NULL WHERE artist_id = 1
184
+
185
+ All associations can specify a :select option to change which columns
186
+ are selected. Previously only many to many associations suppported
187
+ this.
188
+
189
+ The SQL used when eagerly loading through eager_graph can be
190
+ modified via the :graph_join_type, :graph_conditions, and
191
+ :graph_join_conditions options.
192
+
193
+ :graph_join_type changes the join type from the default of
194
+ :left_outer. This can be useful if you do not want any
195
+ albums that don't have an artist in the result set:
196
+
197
+ Album.many_to_one :artist, :graph_join_type=>:inner
198
+ Album.eager_graph(:artist).sql
199
+ # SELECT ... FROM albums INNER JOIN artists ...
200
+
201
+ :graph_conditions adds conditions on the join to the table you are
202
+ joining, the eager_graph equivalent of an association block argument
203
+ in eager. It takes either a hash or an array where all elements
204
+ are arrays of length two, similar to join_table, where key symbols
205
+ specify columns in the joined table and value symbols specify
206
+ columns in the last joined or primary table:
207
+
208
+ Album.many_to_one :artist, :graph_conditions=>{:active=>true}
209
+ Album.eager_graph(:artist).sql
210
+ # SELECT ... FROM albums LEFT OUTER JOIN artists ON ((artists.id =
211
+ # albums.artist_id) AND (artists.active = 't'))
212
+
213
+ :graph_join_table_conditions exists for many to many associations only,
214
+ and operates the same as :graph_conditions, except it specifies a
215
+ condition on the many to many join table instead of the associated
216
+ model's table. This is necessary if the join table is also model
217
+ table with other columns on which you may want to filter:
218
+
219
+ Album.many_to_many :genres, :join_table=>:ag, \
220
+ :graph_join_table_conditions=>{:active=>true}
221
+ Album.eager_graph(:genres).sql
222
+ # SELECT ... FROM albums LEFT OUTER JOIN ag ON ((ag.album_id =
223
+ albums.id) AND (ag.active = 't')) LEFT OUTER JOIN genres ON
224
+ (genres.id = ag.genre_id)
225
+
226
+ Other Small Improvements
227
+ ------------------------
228
+
229
+ * Dataset#invert returns a dataset that matches all records not
230
+ matching the current filter.
231
+ * Dataset#unfiltered returns a dataset that has any filters removed.
232
+ * Dataset#last_page? and Dataset#first_page? for paginated datasets.
233
+ * The sequel command line tool now support an -E or --echo argument
234
+ that logs all SQL to the standard output. It also can take a path
235
+ to a yaml file with database connection options, in addition to a
236
+ database URL.
237
+ * Databases can now have multiple SQL loggers, so you can log to the
238
+ standard output as well as a file.
239
+ * SQL identifiers (columns and tables) are now quoted by default (you
240
+ can turn this off via Sequel.quote_identifiers = false if need be).
241
+ * Sequel.connect now takes an optional block that will disconnect the
242
+ database when the block finishes.
243
+ * AlterTableGenerator now has add_primary_key and add_foreign_key
244
+ methods.
245
+ * Running the specs without ParseTree installed skips the specs that
246
+ require ParseTree.
247
+ * You can use an array of arrays instead of a hash when specifying
248
+ conditions, which may be necessary in certain situations where
249
+ you would be using the same hash key more than once.
250
+ * Almost all documentation for Sequel was updated for 2.0.0, so if you
251
+ found Sequel documentation lacking before, check out the new RDoc
252
+ pages.
253
+ * There have been many minor refactoring improvements, the code
254
+ should now be easier to read and follow.
255
+ * Sequel now has no external dependencies.
256
+ * Sequel::Models now have before_validation and after_validation
257
+ hooks.
258
+ * Sequel::Model hooks that return false cause the methods that call
259
+ them (such as save) to return false.
260
+ * Sequel::Models can now load their schema on first instantiation,
261
+ instead of when they are created, via
262
+ Sequel::Model.lazy_load_schema=. This is helpful for certain
263
+ web frameworks that reload all models on every request.
264
+ * Hook methods that use blocks can now include an optional tag,
265
+ which allows them to work well with web frameworks that load source
266
+ files every time they are modified.
267
+
268
+ The PostgreSQL adapter has been rewritten and now supports ruby-pg.
269
+ There have also been improvements in the following adapters: DBI,
270
+ MySQL, SQLite, Oracle, and MSSQL.
271
+
272
+ All of the methods that have been deprecated in 1.5.0 have now been
273
+ removed. If you are want to upgrade to Sequel 2.0.0 from version 1.4.0
274
+ or previous, upgrade to 1.5.1 first, fix all of the deprecation
275
+ warnings that show up, and then upgrade to 2.0.0.
276
+
277
+ There were some backwards incompatible changes made in 2.0.0 beyond the
278
+ removal of deprecated methods. These are:
279
+
280
+ * Inflector is no longer used, the inflection methods were moved
281
+ directly into String (where they belong because inflections only
282
+ make sense for strings). So to override singularization
283
+ or pluralization rules, use String.inflections instead of
284
+ Inflector.inflections.
285
+ * MySQL tinyints are now returned as boolean values instead of
286
+ integers. MySQL doesn't have a boolean type, and usually it
287
+ is recommended to use tinyint for a boolean column.
288
+ * You can no longer pass an array to Dataset#order or Dataset#select,
289
+ you need to pass each argument separately (the * operator is your
290
+ friend).
291
+ * You must use '?' instead of '(?)' when interpolating an array
292
+ argument into a string (e.g. filter('x IN ?', [1,2,3]))
293
+ * You must pass an explicit table alias argument to join_table and
294
+ related methods, you can no longer include the table alias
295
+ inside the table argument.
296
+ * sqlite:// URLs now operate the same as file:// URLs (2 slashes
297
+ for a relative path, 3 for an absolute path).
298
+