sequel 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. data/CHANGELOG +64 -0
  2. data/Rakefile +1 -1
  3. data/lib/sequel_core/adapters/jdbc.rb +6 -2
  4. data/lib/sequel_core/adapters/jdbc/oracle.rb +23 -0
  5. data/lib/sequel_core/adapters/oracle.rb +4 -77
  6. data/lib/sequel_core/adapters/postgres.rb +39 -26
  7. data/lib/sequel_core/adapters/shared/mssql.rb +0 -1
  8. data/lib/sequel_core/adapters/shared/mysql.rb +1 -1
  9. data/lib/sequel_core/adapters/shared/oracle.rb +82 -0
  10. data/lib/sequel_core/adapters/shared/postgres.rb +65 -46
  11. data/lib/sequel_core/core_ext.rb +10 -0
  12. data/lib/sequel_core/core_sql.rb +7 -0
  13. data/lib/sequel_core/database.rb +22 -0
  14. data/lib/sequel_core/database/schema.rb +1 -1
  15. data/lib/sequel_core/dataset.rb +29 -11
  16. data/lib/sequel_core/dataset/sql.rb +27 -7
  17. data/lib/sequel_core/migration.rb +20 -2
  18. data/lib/sequel_core/object_graph.rb +24 -10
  19. data/lib/sequel_core/schema/generator.rb +22 -9
  20. data/lib/sequel_core/schema/sql.rb +13 -9
  21. data/lib/sequel_core/sql.rb +27 -2
  22. data/lib/sequel_model/association_reflection.rb +251 -141
  23. data/lib/sequel_model/associations.rb +114 -61
  24. data/lib/sequel_model/base.rb +25 -21
  25. data/lib/sequel_model/eager_loading.rb +17 -40
  26. data/lib/sequel_model/hooks.rb +25 -24
  27. data/lib/sequel_model/record.rb +29 -51
  28. data/lib/sequel_model/schema.rb +1 -1
  29. data/lib/sequel_model/validations.rb +13 -3
  30. data/spec/adapters/postgres_spec.rb +104 -18
  31. data/spec/adapters/spec_helper.rb +4 -1
  32. data/spec/integration/eager_loader_test.rb +5 -4
  33. data/spec/integration/spec_helper.rb +4 -1
  34. data/spec/sequel_core/connection_pool_spec.rb +24 -24
  35. data/spec/sequel_core/core_sql_spec.rb +12 -0
  36. data/spec/sequel_core/dataset_spec.rb +77 -2
  37. data/spec/sequel_core/expression_filters_spec.rb +6 -0
  38. data/spec/sequel_core/object_graph_spec.rb +40 -2
  39. data/spec/sequel_core/schema_spec.rb +13 -0
  40. data/spec/sequel_model/association_reflection_spec.rb +8 -8
  41. data/spec/sequel_model/associations_spec.rb +164 -3
  42. data/spec/sequel_model/caching_spec.rb +2 -1
  43. data/spec/sequel_model/eager_loading_spec.rb +107 -3
  44. data/spec/sequel_model/hooks_spec.rb +38 -22
  45. data/spec/sequel_model/model_spec.rb +11 -35
  46. data/spec/sequel_model/plugins_spec.rb +4 -2
  47. data/spec/sequel_model/record_spec.rb +8 -5
  48. data/spec/sequel_model/validations_spec.rb +25 -0
  49. data/spec/spec_config.rb +4 -3
  50. metadata +21 -19
@@ -88,7 +88,7 @@ module Sequel::Model::Associations
88
88
  # after a new item is added to the association.
89
89
  # - :after_load - Symbol, Proc, or array of both/either specifying a callback to call
90
90
  # after the associated record(s) have been retrieved from the database. Not called
91
- # when eager loading (see the :eager_loader option to accomplish it when eager loading).
91
+ # when eager loading via eager_graph, but called when eager loading via eager.
92
92
  # - :after_remove - Symbol, Proc, or array of both/either specifying a callback to call
93
93
  # after an item is removed from the association.
94
94
  # - :allow_eager - If set to false, you cannot load the association eagerly
@@ -113,6 +113,10 @@ module Sequel::Model::Associations
113
113
  # For many_to_one associations, this is ignored unless this association is
114
114
  # being eagerly loaded, as it doesn't save queries unless multiple objects
115
115
  # can be loaded at once.
116
+ # - :eager_grapher - A proc to use to implement eager loading via eager graph, overriding the default.
117
+ # Takes three arguments, a dataset, an alias to use for the table to graph for this association,
118
+ # and the alias that was used for the current table (since you can cascade associations),
119
+ # Should return a copy of the dataset with the association graphed into it.
116
120
  # - :eager_loader - A proc to use to implement eager loading, overriding the default. Takes three arguments,
117
121
  # a key hash (used solely to enhance performance), an array of records,
118
122
  # and a hash of dependent associations. The associated records should
@@ -152,6 +156,8 @@ module Sequel::Model::Associations
152
156
  # * :many_to_one:
153
157
  # - :key - foreign_key in current model's table that references
154
158
  # associated model's primary key, as a symbol. Defaults to :"#{name}_id".
159
+ # - :primary_key - column in the associated table that :key option references, as a symbol.
160
+ # Defaults to the primary key of the associated table.
155
161
  # * :one_to_many:
156
162
  # - :key - foreign key in associated model's table that references
157
163
  # current model's primary key, as a symbol. Defaults to
@@ -164,15 +170,9 @@ module Sequel::Model::Associations
164
170
  # so using this is similar to using many_to_one, in terms of the methods
165
171
  # it adds, the main difference is that the foreign key is in the associated
166
172
  # table instead of the current table.
173
+ # - :primary_key - column in the current table that :key option references, as a symbol.
174
+ # Defaults to primary key of the current table.
167
175
  # * :many_to_many:
168
- # - :join_table - name of table that includes the foreign keys to both
169
- # the current model and the associated model, as a symbol. Defaults to the name
170
- # of current model and name of associated model, pluralized,
171
- # underscored, sorted, and joined with '_'.
172
- # - :left_key - foreign key in join table that points to current model's
173
- # primary key, as a symbol. Defaults to :"#{self.name.underscore}_id".
174
- # - :right_key - foreign key in join table that points to associated
175
- # model's primary key, as a symbol. Defaults to Defaults to :"#{name.to_s.singularize}_id".
176
176
  # - :graph_join_table_block - The block to pass to join_table for
177
177
  # the join table when eagerly loading the association via eager_graph.
178
178
  # - :graph_join_table_conditions - The additional conditions to use on the SQL join for
@@ -185,13 +185,26 @@ module Sequel::Model::Associations
185
185
  # table when eagerly loading the association via eager_graph, instead of the default
186
186
  # conditions specified by the foreign/primary keys. This option causes the
187
187
  # :graph_join_table_conditions option to be ignored.
188
+ # - :join_table - name of table that includes the foreign keys to both
189
+ # the current model and the associated model, as a symbol. Defaults to the name
190
+ # of current model and name of associated model, pluralized,
191
+ # underscored, sorted, and joined with '_'.
192
+ # - :left_key - foreign key in join table that points to current model's
193
+ # primary key, as a symbol. Defaults to :"#{self.name.underscore}_id".
194
+ # - :left_primary_key - column in current table that :left_key points to, as a symbol.
195
+ # Defaults to primary key of current table.
196
+ # - :right_key - foreign key in join table that points to associated
197
+ # model's primary key, as a symbol. Defaults to Defaults to :"#{name.to_s.singularize}_id".
198
+ # - :right_primary_key - column in associated table that :right_key points to, as a symbol.
199
+ # Defaults to primary key of the associated table.
200
+ # - :uniq - Adds a after_load callback that makes the array of objects unique.
188
201
  def associate(type, name, opts = {}, &block)
189
- raise(Error, 'invalid association type') unless AssociationReflection::ASSOCIATION_TYPES.include?(type)
202
+ raise(Error, 'invalid association type') unless assoc_class = ASSOCIATION_TYPES[type]
190
203
  raise(Error, 'Model.associate name argument must be a symbol') unless Symbol === name
191
204
 
192
205
  # merge early so we don't modify opts
193
206
  opts = opts.merge(:type => type, :name => name, :block => block, :cache => true, :model => self)
194
- opts = AssociationReflection.new.merge!(opts)
207
+ opts = assoc_class.new.merge!(opts)
195
208
  opts[:eager_block] = block unless opts.include?(:eager_block)
196
209
  opts[:graph_join_type] ||= :left_outer
197
210
  opts[:order_eager_graph] = true unless opts.include?(:order_eager_graph)
@@ -246,29 +259,30 @@ module Sequel::Model::Associations
246
259
 
247
260
  private
248
261
 
249
- # Hash storing the association reflections. Keys are association name
250
- # symbols, values are association reflection hashes.
251
- def association_reflections
252
- @association_reflections ||= {}
262
+ # Add a method to the association module
263
+ def association_module_def(name, &block)
264
+ overridable_methods_module.class_def(name, &block)
253
265
  end
254
-
266
+
267
+ # Add a method to the association module
268
+ def association_module_private_def(name, &block)
269
+ association_module_def(name, &block)
270
+ overridable_methods_module.send(:private, name)
271
+ end
272
+
255
273
  # Add the add_ instance method
256
274
  def def_add_method(opts)
257
- class_def(opts.add_method){|o| add_associated_object(opts, o)}
275
+ association_module_def(opts.add_method){|o| add_associated_object(opts, o)}
258
276
  end
259
277
 
260
278
  # Adds association methods to the model for *_to_many associations.
261
279
  def def_association_dataset_methods(opts)
262
280
  # If a block is given, define a helper method for it, because it takes
263
281
  # an argument. This is unnecessary in Ruby 1.9, as that has instance_exec.
264
- if opts[:block]
265
- class_def(opts.dataset_helper_method, &opts[:block])
266
- private opts.dataset_helper_method
267
- end
268
- class_def(opts._dataset_method, &opts[:dataset])
269
- private opts._dataset_method
270
- class_def(opts.dataset_method){_dataset(opts)}
271
- class_def(opts.association_method){|*reload| load_associated_objects(opts, reload[0])}
282
+ association_module_private_def(opts.dataset_helper_method, &opts[:block]) if opts[:block]
283
+ association_module_private_def(opts._dataset_method, &opts[:dataset])
284
+ association_module_def(opts.dataset_method){_dataset(opts)}
285
+ association_module_def(opts.association_method){|*reload| load_associated_objects(opts, reload[0])}
272
286
  end
273
287
 
274
288
  # Adds many_to_many association instance methods
@@ -277,38 +291,54 @@ module Sequel::Model::Associations
277
291
  model = self
278
292
  left = (opts[:left_key] ||= opts.default_left_key)
279
293
  right = (opts[:right_key] ||= opts.default_right_key)
294
+ left_pk = (opts[:left_primary_key] ||= self.primary_key)
280
295
  opts[:class_name] ||= name.to_s.singularize.camelize
281
296
  join_table = (opts[:join_table] ||= opts.default_join_table)
282
297
  left_key_alias = opts[:left_key_alias] ||= :x_foreign_key_x
283
298
  left_key_select = opts[:left_key_select] ||= left.qualify(join_table).as(opts[:left_key_alias])
284
- opts[:graph_join_table_conditions] = opts[:graph_join_table_conditions] ? opts[:graph_join_table_conditions].to_a : []
299
+ graph_jt_conds = opts[:graph_join_table_conditions] = opts[:graph_join_table_conditions] ? opts[:graph_join_table_conditions].to_a : []
285
300
  opts[:graph_join_table_join_type] ||= opts[:graph_join_type]
286
- opts[:dataset] ||= proc{opts.associated_class.inner_join(join_table, [[right, opts.associated_primary_key], [left, pk]])}
301
+ opts[:after_load].unshift(:array_uniq!) if opts[:uniq]
302
+ opts[:dataset] ||= proc{opts.associated_class.inner_join(join_table, [[right, opts.right_primary_key], [left, send(left_pk)]])}
287
303
  database = db
288
304
 
289
305
  opts[:eager_loader] ||= proc do |key_hash, records, associations|
290
- h = key_hash[model.primary_key]
306
+ h = key_hash[left_pk]
291
307
  records.each{|object| object.associations[name] = []}
292
- model.eager_loading_dataset(opts, opts.associated_class.inner_join(join_table, [[right, opts.associated_primary_key], [left, h.keys]]), Array(opts.select) + Array(left_key_select), associations).all do |assoc_record|
308
+ model.eager_loading_dataset(opts, opts.associated_class.inner_join(join_table, [[right, opts.right_primary_key], [left, h.keys]]), Array(opts.select) + Array(left_key_select), associations).all do |assoc_record|
293
309
  next unless objects = h[assoc_record.values.delete(left_key_alias)]
294
310
  objects.each{|object| object.associations[name].push(assoc_record)}
295
311
  end
296
312
  end
297
313
 
314
+ join_type = opts[:graph_join_type]
315
+ select = opts[:graph_select]
316
+ use_only_conditions = opts.include?(:graph_only_conditions)
317
+ only_conditions = opts[:graph_only_conditions]
318
+ conditions = opts[:graph_conditions]
319
+ graph_block = opts[:graph_block]
320
+ use_jt_only_conditions = opts.include?(:graph_join_table_only_conditions)
321
+ jt_only_conditions = opts[:graph_join_table_only_conditions]
322
+ jt_join_type = opts[:graph_join_table_join_type]
323
+ jt_graph_block = opts[:graph_join_table_block]
324
+ opts[:eager_grapher] ||= proc do |ds, assoc_alias, table_alias|
325
+ ds = ds.graph(join_table, use_jt_only_conditions ? jt_only_conditions : [[left, left_pk]] + graph_jt_conds, :select=>false, :table_alias=>ds.send(:eager_unique_table_alias, ds, join_table), :join_type=>jt_join_type, :implicit_qualifier=>table_alias, &jt_graph_block)
326
+ ds.graph(opts.associated_class, use_only_conditions ? only_conditions : [[opts.right_primary_key, right]] + conditions, :select=>select, :table_alias=>assoc_alias, :join_type=>join_type, &graph_block)
327
+ end
328
+
298
329
  def_association_dataset_methods(opts)
299
330
 
300
331
  return if opts[:read_only]
301
332
 
302
- class_def(opts._add_method) do |o|
303
- database.dataset.from(join_table).insert(left=>pk, right=>o.pk)
333
+ association_module_private_def(opts._add_method) do |o|
334
+ database.dataset.from(join_table).insert(left=>send(left_pk), right=>o.send(opts.right_primary_key))
304
335
  end
305
- class_def(opts._remove_method) do |o|
306
- database.dataset.from(join_table).filter([[left, pk], [right, o.pk]]).delete
336
+ association_module_private_def(opts._remove_method) do |o|
337
+ database.dataset.from(join_table).filter([[left, send(left_pk)], [right, o.send(opts.right_primary_key)]]).delete
307
338
  end
308
- class_def(opts._remove_all_method) do
309
- database.dataset.from(join_table).filter(left=>pk).delete
339
+ association_module_private_def(opts._remove_all_method) do
340
+ database.dataset.from(join_table).filter(left=>send(left_pk)).delete
310
341
  end
311
- private opts._add_method, opts._remove_method, opts._remove_all_method
312
342
 
313
343
  def_add_method(opts)
314
344
  def_remove_methods(opts)
@@ -318,12 +348,12 @@ module Sequel::Model::Associations
318
348
  def def_many_to_one(opts)
319
349
  name = opts[:name]
320
350
  model = self
321
- opts[:key] = opts.default_right_key unless opts.include?(:key)
351
+ opts[:key] = opts.default_key unless opts.include?(:key)
322
352
  key = opts[:key]
323
353
  opts[:class_name] ||= name.to_s.camelize
324
354
  opts[:dataset] ||= proc do
325
355
  klass = opts.associated_class
326
- klass.filter(opts.associated_primary_key.qualify(klass.table_name)=>send(key))
356
+ klass.filter(opts.primary_key.qualify(klass.table_name)=>send(key))
327
357
  end
328
358
  opts[:eager_loader] ||= proc do |key_hash, records, associations|
329
359
  h = key_hash[key]
@@ -333,21 +363,31 @@ module Sequel::Model::Associations
333
363
  records.each{|object| object.associations[name] = nil}
334
364
  # Skip eager loading if no objects have a foreign key for this association
335
365
  unless keys.empty?
336
- model.eager_loading_dataset(opts, opts.associated_class.filter(opts.associated_primary_key.qualify(opts.associated_class.table_name)=>keys), opts.select, associations).all do |assoc_record|
337
- next unless objects = h[assoc_record.pk]
366
+ klass = opts.associated_class
367
+ model.eager_loading_dataset(opts, klass.filter(opts.primary_key.qualify(klass.table_name)=>keys), opts.select, associations).all do |assoc_record|
368
+ next unless objects = h[assoc_record.send(opts.primary_key)]
338
369
  objects.each{|object| object.associations[name] = assoc_record}
339
370
  end
340
371
  end
341
372
  end
342
373
 
374
+ join_type = opts[:graph_join_type]
375
+ select = opts[:graph_select]
376
+ use_only_conditions = opts.include?(:graph_only_conditions)
377
+ only_conditions = opts[:graph_only_conditions]
378
+ conditions = opts[:graph_conditions]
379
+ graph_block = opts[:graph_block]
380
+ opts[:eager_grapher] ||= proc do |ds, assoc_alias, table_alias|
381
+ ds.graph(opts.associated_class, use_only_conditions ? only_conditions : [[opts.primary_key, key]] + conditions, :select=>select, :table_alias=>assoc_alias, :join_type=>join_type, :implicit_qualifier=>table_alias, &graph_block)
382
+ end
383
+
343
384
  def_association_dataset_methods(opts)
344
385
 
345
386
  return if opts[:read_only]
346
387
 
347
- class_def(opts._setter_method){|o| send(:"#{key}=", (o.pk if o))}
348
- private opts._setter_method
388
+ association_module_private_def(opts._setter_method){|o| send(:"#{key}=", (o.send(opts.primary_key) if o))}
349
389
 
350
- class_def(opts.setter_method) do |o|
390
+ association_module_def(opts.setter_method) do |o|
351
391
  raise(Sequel::Error, 'model object does not have a primary key') if o && !o.pk
352
392
  old_val = send(opts.association_method)
353
393
  return o if old_val == o
@@ -367,17 +407,19 @@ module Sequel::Model::Associations
367
407
  def def_one_to_many(opts)
368
408
  name = opts[:name]
369
409
  model = self
370
- key = (opts[:key] ||= opts.default_left_key)
410
+ key = (opts[:key] ||= opts.default_key)
411
+ primary_key = (opts[:primary_key] ||= self.primary_key)
371
412
  opts[:class_name] ||= name.to_s.singularize.camelize
372
413
  opts[:dataset] ||= proc do
373
414
  klass = opts.associated_class
374
- klass.filter(key.qualify(klass.table_name) => pk)
415
+ klass.filter(key.qualify(klass.table_name) => send(primary_key))
375
416
  end
376
417
  opts[:eager_loader] ||= proc do |key_hash, records, associations|
377
- h = key_hash[model.primary_key]
418
+ h = key_hash[primary_key]
378
419
  records.each{|object| object.associations[name] = []}
379
420
  reciprocal = opts.reciprocal
380
- model.eager_loading_dataset(opts, opts.associated_class.filter(key.qualify(opts.associated_class.table_name)=>h.keys), opts.select, associations).all do |assoc_record|
421
+ klass = opts.associated_class
422
+ model.eager_loading_dataset(opts, klass.filter(key.qualify(klass.table_name)=>h.keys), opts.select, associations).all do |assoc_record|
381
423
  next unless objects = h[assoc_record[key]]
382
424
  objects.each do |object|
383
425
  object.associations[name].push(assoc_record)
@@ -386,44 +428,55 @@ module Sequel::Model::Associations
386
428
  end
387
429
  end
388
430
 
431
+ join_type = opts[:graph_join_type]
432
+ select = opts[:graph_select]
433
+ use_only_conditions = opts.include?(:graph_only_conditions)
434
+ only_conditions = opts[:graph_only_conditions]
435
+ conditions = opts[:graph_conditions]
436
+ graph_block = opts[:graph_block]
437
+ opts[:eager_grapher] ||= proc do |ds, assoc_alias, table_alias|
438
+ ds = ds.graph(opts.associated_class, use_only_conditions ? only_conditions : [[key, primary_key]] + conditions, :select=>select, :table_alias=>assoc_alias, :join_type=>join_type, :implicit_qualifier=>table_alias, &graph_block)
439
+ # We only load reciprocals for one_to_many associations, as other reciprocals don't make sense
440
+ ds.opts[:eager_graph][:reciprocals][assoc_alias] = opts.reciprocal
441
+ ds
442
+ end
443
+
389
444
  def_association_dataset_methods(opts)
390
445
 
391
446
  unless opts[:read_only]
392
- class_def(opts._add_method) do |o|
393
- o.send(:"#{key}=", pk)
447
+ association_module_private_def(opts._add_method) do |o|
448
+ o.send(:"#{key}=", send(primary_key))
394
449
  o.save || raise(Sequel::Error, "invalid associated object, cannot save")
395
450
  end
396
- private opts._add_method
397
451
  def_add_method(opts)
398
452
 
399
453
  unless opts[:one_to_one]
400
- class_def(opts._remove_method) do |o|
454
+ association_module_private_def(opts._remove_method) do |o|
401
455
  o.send(:"#{key}=", nil)
402
456
  o.save || raise(Sequel::Error, "invalid associated object, cannot save")
403
457
  end
404
- class_def(opts._remove_all_method) do
405
- opts.associated_class.filter(key=>pk).update(key=>nil)
458
+ association_module_private_def(opts._remove_all_method) do
459
+ opts.associated_class.filter(key=>send(primary_key)).update(key=>nil)
406
460
  end
407
- private opts._remove_method, opts._remove_all_method
408
461
  def_remove_methods(opts)
409
462
  end
410
463
  end
411
464
  if opts[:one_to_one]
412
- private opts.association_method, opts.dataset_method
465
+ overridable_methods_module.send(:private, opts.association_method, opts.dataset_method)
413
466
  n = name.to_s.singularize.to_sym
414
467
  raise(Sequel::Error, "one_to_many association names should still be plural even when using the :one_to_one option") if n == name
415
- class_def(n) do |*o|
468
+ association_module_def(n) do |*o|
416
469
  objs = send(name, *o)
417
470
  raise(Sequel::Error, "multiple values found for a one-to-one relationship") if objs.length > 1
418
471
  objs.first
419
472
  end
420
473
  unless opts[:read_only]
421
- private opts.add_method
422
- class_def(:"#{n}=") do |o|
474
+ overridable_methods_module.send(:private, opts.add_method)
475
+ association_module_def(:"#{n}=") do |o|
423
476
  klass = opts.associated_class
424
477
  model.db.transaction do
425
478
  send(opts.add_method, o)
426
- klass.filter(Sequel::SQL::BooleanExpression.new(:AND, {key=>pk}, ~{klass.primary_key=>o.pk}.sql_expr)).update(key=>nil)
479
+ klass.filter(Sequel::SQL::BooleanExpression.new(:AND, {key=>send(primary_key)}, ~{klass.primary_key=>o.pk}.sql_expr)).update(key=>nil)
427
480
  end
428
481
  end
429
482
  end
@@ -432,7 +485,7 @@ module Sequel::Model::Associations
432
485
 
433
486
  # Add the remove_ and remove_all instance methods
434
487
  def def_remove_methods(opts)
435
- class_def(opts.remove_method){|o| remove_associated_object(opts, o)}
436
- class_def(opts.remove_all_method){remove_all_associated_objects(opts)}
488
+ association_module_def(opts.remove_method){|o| remove_associated_object(opts, o)}
489
+ association_module_def(opts.remove_all_method){remove_all_associated_objects(opts)}
437
490
  end
438
491
  end
@@ -1,12 +1,9 @@
1
1
  module Sequel
2
2
  class Model
3
- # Whether to lazily load the schema for future subclasses. Unless turned
4
- # off, checks the database for the table schema whenever a subclass is
5
- # created
6
- @@lazy_load_schema = false
7
-
8
3
  @allowed_columns = nil
4
+ @association_reflections = {}
9
5
  @dataset_methods = {}
6
+ @hooks = {}
10
7
  @primary_key = :id
11
8
  @raise_on_save_failure = true
12
9
  @raise_on_typecast_failure = true
@@ -22,6 +19,9 @@ module Sequel
22
19
  # (default: all columns).
23
20
  metaattr_reader :allowed_columns
24
21
 
22
+ # All association reflections defined for this model (default: none).
23
+ metaattr_reader :association_reflections
24
+
25
25
  # Hash of dataset methods to add to this class and subclasses when
26
26
  # set_dataset is called.
27
27
  metaattr_reader :dataset_methods
@@ -76,7 +76,7 @@ module Sequel
76
76
  :@raise_on_save_failure=>nil, :@restricted_columns=>:dup, :@restrict_primary_key=>nil,
77
77
  :@sti_dataset=>nil, :@sti_key=>nil, :@strict_param_setting=>nil,
78
78
  :@typecast_empty_string_to_nil=>nil, :@typecast_on_assignment=>nil,
79
- :@raise_on_typecast_failure=>nil}
79
+ :@raise_on_typecast_failure=>nil, :@association_reflections=>:dup}
80
80
 
81
81
  # Returns the first record from the database matching the conditions.
82
82
  # If a hash is given, it is used as the conditions. If another
@@ -218,6 +218,8 @@ module Sequel
218
218
  nil
219
219
  end
220
220
  end
221
+ hooks = subclass.instance_variable_set(:@hooks, {})
222
+ sup_class.instance_variable_get(:@hooks).each{|k,v| hooks[k] = v.dup}
221
223
  end
222
224
 
223
225
  # Returns the implicit table name for the model class.
@@ -225,14 +227,6 @@ module Sequel
225
227
  name.demodulize.underscore.pluralize.to_sym
226
228
  end
227
229
 
228
- # Set whether to lazily load the schema for future model classes.
229
- # When the schema is lazy loaded, the schema information is grabbed
230
- # during the first instantiation of the class instead of
231
- # when the class is created.
232
- def self.lazy_load_schema=(value)
233
- @@lazy_load_schema = value
234
- end
235
-
236
230
  # Initializes a model instance as an existing record. This constructor is
237
231
  # used by Sequel to initialize model instances when fetching records.
238
232
  # #load requires that values be a hash where all keys are symbols. It
@@ -290,6 +284,11 @@ module Sequel
290
284
  end
291
285
  @dataset.transform(@transform) if @dataset
292
286
  end
287
+
288
+ # Whether or not the given column is serialized for this model.
289
+ def self.serialized?(column)
290
+ @transform ? @transform.include?(column) : false
291
+ end
293
292
 
294
293
  # Set the columns to allow in new/set/update. Using this means that
295
294
  # any columns not listed here will not be modified. If you have any virtual
@@ -312,8 +311,7 @@ module Sequel
312
311
  # and adds a destroy method to it. It also extends the dataset with
313
312
  # the Associations::EagerLoading methods, and assigns a transform to it
314
313
  # if there is one associated with the model. Finally, it attempts to
315
- # determine the database schema based on the given/created dataset unless
316
- # lazy_load_schema is set.
314
+ # determine the database schema based on the given/created dataset.
317
315
  def self.set_dataset(ds, opts={})
318
316
  inherited = opts[:inherited]
319
317
  @dataset = case ds
@@ -328,13 +326,13 @@ module Sequel
328
326
  @dataset.set_model(self)
329
327
  @dataset.transform(@transform) if @transform
330
328
  if inherited
331
- ((@columns = @dataset.columns) rescue nil) unless @@lazy_load_schema
329
+ @columns = @dataset.columns rescue nil
332
330
  else
333
331
  @dataset.extend(DatasetMethods)
334
332
  @dataset.extend(Associations::EagerLoading)
335
333
  @dataset_methods.each{|meth, block| @dataset.meta_def(meth, &block)} if @dataset_methods
336
334
  end
337
- ((@db_schema = inherited ? superclass.db_schema : get_db_schema) rescue nil) unless @@lazy_load_schema
335
+ @db_schema = (inherited ? superclass.db_schema : get_db_schema) rescue nil
338
336
  self
339
337
  end
340
338
  metaalias :dataset=, :set_dataset
@@ -434,11 +432,10 @@ module Sequel
434
432
 
435
433
  # Create the column accessors
436
434
  def self.def_column_accessor(*columns) # :nodoc:
437
- include(@column_accessors_module = Module.new) unless @column_accessors_module
438
435
  columns.each do |column|
439
436
  im = instance_methods.collect{|x| x.to_s}
440
437
  meth = "#{column}="
441
- @column_accessors_module.module_eval do
438
+ overridable_methods_module.module_eval do
442
439
  define_method(column){self[column]} unless im.include?(column.to_s)
443
440
  unless im.include?(meth)
444
441
  define_method(meth) do |*v|
@@ -492,6 +489,13 @@ module Sequel
492
489
  schema_hash
493
490
  end
494
491
 
492
+ # Module that the class includes that holds methods the class adds for column accessors and
493
+ # associations so that the methods can be overridden with super
494
+ def self.overridable_methods_module
495
+ include(@overridable_methods_module = Module.new) unless @overridable_methods_module
496
+ @overridable_methods_module
497
+ end
498
+
495
499
  # Set the columns for this model, reset the str_columns,
496
500
  # and create accessor methods for each column.
497
501
  def self.set_columns(new_columns) # :nodoc:
@@ -501,6 +505,6 @@ module Sequel
501
505
  @columns
502
506
  end
503
507
 
504
- private_class_method :def_column_accessor, :get_db_schema, :set_columns
508
+ private_class_method :def_column_accessor, :get_db_schema, :overridable_methods_module, :set_columns
505
509
  end
506
510
  end