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,215 @@
1
+ Optimizations
2
+ -------------
3
+
4
+ * Model.[] was optimized to use static SQL in cases where doing so
5
+ should result in the same output. This should result in a 30-40%
6
+ performance increase. Since this can be the most significant or
7
+ only method call in a web application action, this has potential
8
+ to significantly enhance the performance of web application code.
9
+
10
+ In order for this optimization to have an effect, you need to
11
+ make sure that you are calling set_dataset with a Symbol and
12
+ not a Dataset object:
13
+
14
+ # Optimized:
15
+ class Foo < Sequel::Model; end
16
+ class Foo < Sequel::Model(:foos); end
17
+ class Foo < Sequel::Model
18
+ set_dataset :foos
19
+ end
20
+
21
+ # Not Optimized, but otherwise equivalent:
22
+ class Foo < Sequel::Model(Model.db[:foos]); end
23
+ class Foo < Sequel::Model
24
+ set_dataset db[:foos]
25
+ end
26
+
27
+ * Dataset#literal was refactored for performance reasons to make
28
+ overriding it in subclasses unnecessary. The changes made result
29
+ in a 20-25% performance increase. Sequel can spend about 10% of
30
+ it's time in Dataset#literal, so this may be only a 2% overall
31
+ performance improvement.
32
+
33
+ New Features
34
+ ------------
35
+
36
+ * Association datasets now know about the model objects that created
37
+ them, as well as the related association reflection. This makes
38
+ association extensions much more powerful. For example, you can
39
+ now create generic association extensions such as:
40
+
41
+ module FindOrCreate
42
+ def find_or_create(vals)
43
+ first(vals) || association_reflection.associated_class. \
44
+ create(vals.merge(association_reflection[:key]=> \
45
+ model_object.id))
46
+ end
47
+ end
48
+
49
+ The above will work for any standard one_to_many association:
50
+
51
+ Artist.one_to_many :albums, :extend=>FindOrCreate
52
+ # Create an album named Foo related to this artist,
53
+ # unless such an album already exists
54
+ Artist.first.albums_dataset.find_or_create(:name=>'Foo')
55
+
56
+ Before, the only way to do the above was to use a closure inside
57
+ the :dataset option proc, which couldn't be done generically
58
+ for multiple associations.
59
+
60
+ * A :conditions association option was added, which allows simple
61
+ filters to be set up without defining :graph_conditions and
62
+ an association block:
63
+
64
+ # 2.10.0
65
+ one_to_many(:japanese_verses, :class=>:Verse, \
66
+ :graph_conditions=>{:languageid=>3})do |ds|
67
+ ds.filter(:languageid=>3)
68
+ end
69
+ # 2.11.0
70
+ one_to_many(:japanese_verses, :class=>:Verse, \
71
+ :conditions=>{:languageid=>3})
72
+
73
+ * A :clone association option was added, which allows you to clone
74
+ an existing association. This is most useful when you are dealing
75
+ with a legacy schema and had to define the same options redundantly
76
+ for each type of association. You can now do:
77
+
78
+ many_to_many :deputies, :class=>:Employee, \
79
+ :join_table=>:employeecurrentaudits, :left_key=>:currentauditid, \
80
+ :right_key=>:employeeid, :order=>[:firstname, :lastname] do |ds|
81
+ ds.filter(:active).filter(:capacity=>1)
82
+ end
83
+ many_to_many :project_managers, :clone=>:deputies do |ds|
84
+ ds.filter(:active).filter(:capacity=>2)
85
+ end
86
+ many_to_many :team_leaders, :clone=>:deputies do |ds|
87
+ ds.filter(:active).filter(:capacity=>3)
88
+ end
89
+
90
+ All of the above would use the same :class, :join_table, :left_key,
91
+ :right_key, and :order options. If you don't provide an
92
+ association block, but you are cloning an association that has one,
93
+ the cloned association's block is used. You can use the
94
+ :block=>nil option to not use a block even if the cloned
95
+ association has a block.
96
+
97
+ * Dataset#select, #select_more, #order, #order_more, and #get all
98
+ take a block that yields a Sequel::SQL::VirtualRow instance,
99
+ similar to the behavior of filter. This allows for the easier
100
+ use of SQL functions on Ruby 1.9:
101
+
102
+ # 2.10.0
103
+ dataset.select(:prettify.sql_function(:name))
104
+ # 2.11.0
105
+ dataset.select{|o| o.prettify(:name)}
106
+
107
+ * String#lit can now accept arguments and return an SQL literal
108
+ string. This allows you to do things that were previously hard
109
+ or at least unnecessarily verbose. For example, you can now
110
+ easily use the SQL standard SUBSTRING function:
111
+
112
+ column = :user
113
+ pattern = params[:pattern]
114
+ dataset.select{|o| o.substring('? from ?'.lit(column, pattern))}
115
+
116
+ * A validates_inclusion_of validation method was added to Model. You
117
+ can provide a Range or an Array in the :in option to specify the
118
+ allowed values:
119
+
120
+ validates_inclusion_of :value, :in=>1..5
121
+ validates_inclusion_of :weekday, :in=>%w'Monday Tuesday ...'
122
+
123
+ * Dataset#with_sql was added, which returns a copy of the dataset
124
+ with static SQL. This is useful if you want to keep the same
125
+ row_proc/graph/transform/etc., but want to use your own custom
126
+ SQL.
127
+
128
+ Other Improvements
129
+ ------------------
130
+
131
+ * You can now use Sequel's database independent types when casting:
132
+
133
+ dataset.select(:number.cast(String))
134
+
135
+ Among other things, the default cast types for cast_string and
136
+ cast_numeric now work in the MySQL adapter.
137
+
138
+ * Model#set_associated_object was added. The many_to_one association
139
+ setter method calls it. This allows you to easily override the
140
+ association setters for all many_to_one associations of a class
141
+ by modifying a single method.
142
+
143
+ * Typecasting invalid date strings now raises a
144
+ Sequel::Error::InvalidValue instead of an argument error, which
145
+ means that you can use raise_on_typecast_failure = false and not
146
+ have an error raised when an invalid date format is used.
147
+
148
+ * String#to_sequel_blob was added and should now be used instead
149
+ of String#to_blob. sqlite3-ruby defines String#to_blob
150
+ differently, which could cause problems.
151
+
152
+ * Blob columns are now fully supported in the SQLite adapter, with
153
+ the hex escape syntax being used for input, and returning columns
154
+ of type Sequel::SQL::Blob on output.
155
+
156
+ * The SQLite adapter drop_column support is now significantly more
157
+ robust.
158
+
159
+ * The SQLite adapter now supports rename_column.
160
+
161
+ * The MySQL adapter now supports stored procedures with multiple
162
+ arguments.
163
+
164
+ * The MySQL adapter can now not use a compressed connection to the
165
+ server via the :compress=>false option.
166
+
167
+ * The MySQL adapter now sets a default timeout of 30 days to the
168
+ database connection, you can change it via the :timeout option,
169
+ which accepts a number of seconds.
170
+
171
+ * The MySQL adapter now sets SQL_AUTO_IS_NULL to false by default,
172
+ you can use the :auto_is_null=>true option to not do this.
173
+
174
+ * The MySQL adapter now sets the encoding option on the database
175
+ connection itself, so it works across reconnects.
176
+
177
+ * Sequel itself no longer uses String#lit or Symbol#* internally, so
178
+ it shouldn't break if another library defines them.
179
+
180
+ * The default index name is now generated correctly if a non-String
181
+ or Symbol column is used.
182
+
183
+ * Some ruby -w warnings have been fixed.
184
+
185
+ * INSERTs are now sent to the master database instead of the slave
186
+ database(s) if using a master/slave database configuration and
187
+ PostgreSQL 8.2+ or Firebird.
188
+
189
+ * DateTime literalization has been fixed in the Firebird adapter.
190
+
191
+ * Date literalization has been fixed in the H2 JDBC subadapter.
192
+
193
+ * Release notes for versions from 1.0 to the present are now included
194
+ in the Sequel repository and the RDoc documentation, see
195
+ http://sequel.rubyforge.org/rdoc/files/doc/release_notes/
196
+
197
+ Backwards Compatibilty
198
+ ----------------------
199
+
200
+ * The optimization of Model.[] may break if you modify the model's
201
+ dataset behind its back. Always use Model.set_dataset if you
202
+ want to change a Model's dataset.
203
+
204
+ * Sequel::Dataset::UnsupportedExceptIntersect and
205
+ Sequel::Dataset::UnsupportedExceptIntersectAll will now only be
206
+ defined if you are using an adapter that requires them.
207
+
208
+ * The private Model#cache_delete_unless_new method has been removed.
209
+
210
+ * Sequel::SQL::IrregularFunction was removed, as it was a bad hack
211
+ that is not used by Sequel anymore. Unless you were instantiating
212
+ it directly or using a plugin/extension that did, this shouldn't
213
+ affect you. Using a Sequel::SQL::Function with a
214
+ Sequel::SQL::PlaceholderLiteralString is recommended instead, see
215
+ the substring example above.
@@ -0,0 +1,253 @@
1
+ The Most Powerful and Flexible Associations of Any Ruby ORM
2
+ -----------------------------------------------------------
3
+
4
+ Sequel can now support any association type supported by
5
+ ActiveRecord, and many association types ActiveRecord doesn't
6
+ support.
7
+
8
+ Association callbacks (:before_add, :after_add, :before_remove,
9
+ :after_remove) have been added, and work for all association
10
+ types. Each of the callback options can be a Symbol specifying an
11
+ instance method that takes one argument (the associated object), or a
12
+ Proc that takes two arguments (the current object and the associated
13
+ object), or an array of Symbols and Procs. Additionally, an
14
+ :after_load callback is available, which is running after loading the
15
+ associated record(s) from the database.
16
+
17
+ Association extensions are now supported:
18
+
19
+ class FindOrCreate
20
+ def find_or_create(vals)
21
+ first(vals) || create(vals)
22
+ end
23
+ end
24
+ class Author < Sequel::Model
25
+ one_to_many :authorships, :extend=>FindOrCreate
26
+ end
27
+ Author.first.authorships_dataset.find_or_create(:name=>'Bob')
28
+
29
+ Sequel has been able to support most has_many :through style
30
+ associations since 1.3, via many_to_many (since it doesn't break on
31
+ join tables that are also model tables, unlike ActiveRecord's
32
+ has_and_belongs_to_many). Now it can also support has_many :through
33
+ style associations where it goes through a has_many association.
34
+
35
+ Sequel can now support polymorphic associations. Polymorphic
36
+ associations are really a design flaw, so Sequel doesn't support them
37
+ directly, but the tools that Sequel gives you make them pretty easy
38
+ to implement.
39
+
40
+ Sequel can also support associations that ActiveRecord does not. For
41
+ example, a belongs_to association where the column referenced in the
42
+ associated table is not the primary key, an association that depends
43
+ on multiple columns in each table, or even situations where the
44
+ association has a column in the primary table that can be referenced
45
+ by any of multiple columns in a second table that has a has_one style
46
+ association with the table you want to associate with.
47
+
48
+ Some of those associations can be supported for a single object using
49
+ custom SQL in ActiveRecord, but none are supported when eager
50
+ loading or allow further filtering.
51
+
52
+ Not only can all of these cases be supported with Sequel::Model, all
53
+ can be supported with eager loading, and can allow for further
54
+ filtering. See
55
+ http://sequel.rubyforge.org/files/sequel/doc/advanced_associations_rdoc.html
56
+ for details and example code for all association types covered above.
57
+
58
+ There have also been many additional options added for controlling
59
+ eager loading via eager_graph. Every part of the SQL JOINs can now
60
+ be controlled via one of the options, so you can use JOIN USING,
61
+ NATURAL JOIN, or arbitrary JOIN ON conditions.
62
+
63
+ Finally, just to show off the power that Sequel gives you when eager
64
+ loading, here is example code that will eagerly load all descendants
65
+ and ancestors in a tree structure, without knowing the depth of the
66
+ tree:
67
+
68
+ class Node < Sequel::Model
69
+ set_schema do
70
+ primary_key :id
71
+ foreign_key :parent_id, :nodes
72
+ end
73
+ create_table
74
+
75
+ many_to_one :parent
76
+ one_to_many :children, :key=>:parent_id
77
+
78
+ # Only useful when eager loading
79
+ many_to_one :ancestors, :eager_loader=>(proc do |key_hash, nodes,
80
+ associations|
81
+ # Handle cases where the root node has the same parent_id as
82
+ primary_key
83
+ # and also when it is NULL
84
+ non_root_nodes = nodes.reject do |n|
85
+ if [nil, n.pk].include?(n.parent_id)
86
+ # Make sure root nodes have their parent association set to
87
+ nil
88
+ n.associations[:parent] = nil
89
+ true
90
+ else
91
+ false
92
+ end
93
+ end
94
+ unless non_root_nodes.empty?
95
+ id_map = {}
96
+ # Create an map of parent_ids to nodes that have that parent id
97
+ non_root_nodes.each{|n| (id_map[n.parent_id] ||= []) << n}
98
+ # Doesn't cause an infinte loop, because when only the root node
99
+ # is left, this is not called.
100
+ Node.filter(Node.primary_key=>id_map.keys).eager(:ancestors).all
101
+ do |node|
102
+ # Populate the parent association for each node
103
+ id_map[node.pk].each{|n| n.associations[:parent] = node}
104
+ end
105
+ end
106
+ end)
107
+ many_to_one :descendants, :eager_loader=>(proc do |key_hash, nodes,
108
+ associations|
109
+ id_map = {}
110
+ nodes.each do |n|
111
+ # Initialize an empty array of child associations for each
112
+ parent node
113
+ n.associations[:children] = []
114
+ # Populate identity map of nodes
115
+ id_map[n.pk] = n
116
+ end
117
+ # Doesn't cause an infinite loop, because the :eager_loader is not
118
+ called
119
+ # if no records are returned. Exclude id = parent_id to avoid
120
+ infinite loop
121
+ # if the root note is one of the returned records and it has
122
+ parent_id = id
123
+ # instead of parent_id = NULL.
124
+ Node.filter(:parent_id=>id_map.keys).exclude(:id=>:parent_id).eager(:descendants).all
125
+ do |node|
126
+ # Get the parent from the identity map
127
+ parent = id_map[node.parent_id]
128
+ # Set the child's parent association to the parent
129
+ node.associations[:parent] = parent
130
+ # Add the child association to the array of children in the
131
+ parent
132
+ parent.associations[:children] << node
133
+ end
134
+ end)
135
+ end
136
+
137
+ nodes = Node.filter(:id < 10).eager(:ancestors, :descendants).all
138
+
139
+ New Adapter Features
140
+ --------------------
141
+
142
+ * PostgreSQL bytea fields are now fully supported.
143
+
144
+ * The PostgreSQL adapter now uses the safer connection-specific
145
+ string escaping if you are using ruby-pg.
146
+
147
+ * The SQLite adapter supports drop_column and add_index.
148
+
149
+ * You can now use URL parameters in the connection string, enabling
150
+ you to connect to PostgreSQL via a socket using
151
+ postgres://user:password@blah/database?host=/tmp
152
+
153
+ Other New Features
154
+ ------------------
155
+
156
+ * Dataset#graph now takes a block which it passes to join_table.
157
+
158
+ * Symbol#identifier has been added, which can be used if another
159
+ library defines the same operator(s) on Symbol that Sequel defines.
160
+
161
+ * Filter blocks now yield a VirtualRow instance, which can yield
162
+ Identifiers, QualifiedIdentifiers, or Functions. Like
163
+ Symbol#identifier, this is useful if another library defines the
164
+ same operator(s) on Symbol that Sequel defines.
165
+
166
+ * You can now call Model.to_hash to get an identity map for all
167
+ rows (before this required Model.dataset.to_hash).
168
+
169
+ * A model that can get it's column information from the schema will
170
+ set it in the dataset, potentially saving many queries.
171
+
172
+ * Model.validates_presence_of now works correctly for boolean
173
+ columns.
174
+
175
+ Notable Bug Fixes
176
+ -----------------
177
+
178
+ * Caching now works with Model subclasses.
179
+
180
+ * Model validation methods now work with source reloading.
181
+
182
+ * The PostgreSQL adapter no longer raises an Error if you try to
183
+ insert a record with the primary key already specified.
184
+
185
+ * Sequel no longer messes with the native MySQL adapter, so you can
186
+ use Sequel and ActiveRecord with MySQL in the same process.
187
+
188
+ * Dataset#count now works correctly for limited dataset.
189
+
190
+ * PostgreSQL Database#transaction method yields a connection, similar
191
+ to the other adapters.
192
+
193
+ * Using a hash argument in #distinct, #order, or #group is treated
194
+ as an expression instead of a column alias.
195
+
196
+ * Cloned datasets no longer ignore the existing columns unless it is
197
+ necessary.
198
+
199
+ * The :quote_identifiers and :single_threaded Database options now
200
+ work correctly.
201
+
202
+ Backwards Incompatible Changes
203
+ ------------------------------
204
+
205
+ * ParseTree support, deprecated in 2.1.0, has been removed in 2.2.0.
206
+ You should use the expression filter syntax instead, perferably
207
+ without the block (though it can be used inside a block as well).
208
+ This usually involves the following types of changes:
209
+
210
+ filter{:x == :y} => filter(:x => :y)
211
+ filter{:x << :y} => filter(:x => :y)
212
+ filter{:x && :y} => filter(:x & :y) # Don't forget about change
213
+ filter{:x || :y} => filter(:x | :y) # in operator precedence
214
+ filter{:x.like?('%blah%')} => filter(:x.like('%blah%'))
215
+ filter do => filter((:x > 1) & (:y < 2))
216
+ :x > 1
217
+ :y < 2
218
+ end
219
+
220
+ * Attempts to save an invalid Model instance will raise an error by
221
+ default. To revert to returning a nil value, use:
222
+
223
+ Sequel::Model.raise_on_save_failure = false # Global
224
+ Album.raise_on_save_failure = false # Class
225
+ album = Album.new
226
+ album.raise_on_save_failure = false # Instance
227
+
228
+ Note that before, save would return false where now it returns nil
229
+ if you disable raising on save failure.
230
+
231
+ * Dataset#update no longer takes a block, as it's use of the block
232
+ depended on ParseTree. With the introduction of the expression
233
+ syntax in 2.0.0, it's no longer necessary. You should use a hash
234
+ with an expression as the value instead:
235
+
236
+ DB[:table].update(:column=>:column + 1)
237
+
238
+ * validates_presence of now considers false as present instead of
239
+ absent. This is so it works with boolean columns.
240
+
241
+ * Dataset#graph ignores any previously selected columns when it is
242
+ called for the first time.
243
+
244
+ * Dataset#columns ignores any filtering, ordering, or distinct
245
+ clauses. This shouldn't cause issues unless you were using
246
+ SQL functions with side effects and expecting them to be called
247
+ when columns was called (unlikely at best).
248
+
249
+ One significant point of note is that the 2.2.0 release will be the
250
+ last release with both a sequel_core and sequel gem. Starting
251
+ with 2.3.0 they will be combined into one sequel gem. You will still
252
+ be able to get just the sequel_core part by requiring 'sequel_core',
253
+ but they will be packaged together.