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.
- 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
|