sequel 2.6.0 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +64 -0
- data/Rakefile +1 -1
- data/lib/sequel_core/adapters/jdbc.rb +6 -2
- data/lib/sequel_core/adapters/jdbc/oracle.rb +23 -0
- data/lib/sequel_core/adapters/oracle.rb +4 -77
- data/lib/sequel_core/adapters/postgres.rb +39 -26
- data/lib/sequel_core/adapters/shared/mssql.rb +0 -1
- data/lib/sequel_core/adapters/shared/mysql.rb +1 -1
- data/lib/sequel_core/adapters/shared/oracle.rb +82 -0
- data/lib/sequel_core/adapters/shared/postgres.rb +65 -46
- data/lib/sequel_core/core_ext.rb +10 -0
- data/lib/sequel_core/core_sql.rb +7 -0
- data/lib/sequel_core/database.rb +22 -0
- data/lib/sequel_core/database/schema.rb +1 -1
- data/lib/sequel_core/dataset.rb +29 -11
- data/lib/sequel_core/dataset/sql.rb +27 -7
- data/lib/sequel_core/migration.rb +20 -2
- data/lib/sequel_core/object_graph.rb +24 -10
- data/lib/sequel_core/schema/generator.rb +22 -9
- data/lib/sequel_core/schema/sql.rb +13 -9
- data/lib/sequel_core/sql.rb +27 -2
- data/lib/sequel_model/association_reflection.rb +251 -141
- data/lib/sequel_model/associations.rb +114 -61
- data/lib/sequel_model/base.rb +25 -21
- data/lib/sequel_model/eager_loading.rb +17 -40
- data/lib/sequel_model/hooks.rb +25 -24
- data/lib/sequel_model/record.rb +29 -51
- data/lib/sequel_model/schema.rb +1 -1
- data/lib/sequel_model/validations.rb +13 -3
- data/spec/adapters/postgres_spec.rb +104 -18
- data/spec/adapters/spec_helper.rb +4 -1
- data/spec/integration/eager_loader_test.rb +5 -4
- data/spec/integration/spec_helper.rb +4 -1
- data/spec/sequel_core/connection_pool_spec.rb +24 -24
- data/spec/sequel_core/core_sql_spec.rb +12 -0
- data/spec/sequel_core/dataset_spec.rb +77 -2
- data/spec/sequel_core/expression_filters_spec.rb +6 -0
- data/spec/sequel_core/object_graph_spec.rb +40 -2
- data/spec/sequel_core/schema_spec.rb +13 -0
- data/spec/sequel_model/association_reflection_spec.rb +8 -8
- data/spec/sequel_model/associations_spec.rb +164 -3
- data/spec/sequel_model/caching_spec.rb +2 -1
- data/spec/sequel_model/eager_loading_spec.rb +107 -3
- data/spec/sequel_model/hooks_spec.rb +38 -22
- data/spec/sequel_model/model_spec.rb +11 -35
- data/spec/sequel_model/plugins_spec.rb +4 -2
- data/spec/sequel_model/record_spec.rb +8 -5
- data/spec/sequel_model/validations_spec.rb +25 -0
- data/spec/spec_config.rb +4 -3
- 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
|
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
|
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 =
|
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
|
-
#
|
250
|
-
|
251
|
-
|
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
|
-
|
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
|
-
|
266
|
-
|
267
|
-
|
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[:
|
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[
|
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.
|
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
|
-
|
303
|
-
database.dataset.from(join_table).insert(left=>
|
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
|
-
|
306
|
-
database.dataset.from(join_table).filter([[left,
|
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
|
-
|
309
|
-
database.dataset.from(join_table).filter(left=>
|
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.
|
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.
|
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
|
-
|
337
|
-
|
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
|
-
|
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
|
-
|
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.
|
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) =>
|
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[
|
418
|
+
h = key_hash[primary_key]
|
378
419
|
records.each{|object| object.associations[name] = []}
|
379
420
|
reciprocal = opts.reciprocal
|
380
|
-
|
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
|
-
|
393
|
-
o.send(:"#{key}=",
|
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
|
-
|
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
|
-
|
405
|
-
opts.associated_class.filter(key=>
|
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
|
-
|
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
|
-
|
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=>
|
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
|
-
|
436
|
-
|
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
|
data/lib/sequel_model/base.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|