sequel 3.11.0 → 3.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. data/CHANGELOG +70 -0
  2. data/Rakefile +1 -1
  3. data/doc/active_record.rdoc +896 -0
  4. data/doc/advanced_associations.rdoc +46 -31
  5. data/doc/association_basics.rdoc +14 -9
  6. data/doc/dataset_basics.rdoc +3 -3
  7. data/doc/migration.rdoc +1011 -0
  8. data/doc/model_hooks.rdoc +198 -0
  9. data/doc/querying.rdoc +811 -86
  10. data/doc/release_notes/3.12.0.txt +304 -0
  11. data/doc/sharding.rdoc +17 -0
  12. data/doc/sql.rdoc +537 -0
  13. data/doc/validations.rdoc +501 -0
  14. data/lib/sequel/adapters/jdbc.rb +19 -27
  15. data/lib/sequel/adapters/jdbc/postgresql.rb +0 -7
  16. data/lib/sequel/adapters/mysql.rb +5 -4
  17. data/lib/sequel/adapters/odbc.rb +3 -2
  18. data/lib/sequel/adapters/shared/mssql.rb +7 -6
  19. data/lib/sequel/adapters/shared/mysql.rb +2 -7
  20. data/lib/sequel/adapters/shared/postgres.rb +2 -8
  21. data/lib/sequel/adapters/shared/sqlite.rb +2 -5
  22. data/lib/sequel/adapters/sqlite.rb +4 -4
  23. data/lib/sequel/core.rb +0 -1
  24. data/lib/sequel/database.rb +2 -1060
  25. data/lib/sequel/database/connecting.rb +227 -0
  26. data/lib/sequel/database/dataset.rb +58 -0
  27. data/lib/sequel/database/dataset_defaults.rb +127 -0
  28. data/lib/sequel/database/logging.rb +62 -0
  29. data/lib/sequel/database/misc.rb +246 -0
  30. data/lib/sequel/database/query.rb +390 -0
  31. data/lib/sequel/database/schema_generator.rb +7 -3
  32. data/lib/sequel/database/schema_methods.rb +351 -7
  33. data/lib/sequel/dataset/actions.rb +9 -2
  34. data/lib/sequel/dataset/misc.rb +6 -2
  35. data/lib/sequel/dataset/mutation.rb +3 -11
  36. data/lib/sequel/dataset/query.rb +49 -6
  37. data/lib/sequel/exceptions.rb +3 -0
  38. data/lib/sequel/extensions/migration.rb +395 -113
  39. data/lib/sequel/extensions/schema_dumper.rb +21 -13
  40. data/lib/sequel/model.rb +27 -25
  41. data/lib/sequel/model/associations.rb +72 -34
  42. data/lib/sequel/model/base.rb +74 -18
  43. data/lib/sequel/model/errors.rb +8 -1
  44. data/lib/sequel/plugins/active_model.rb +8 -0
  45. data/lib/sequel/plugins/association_pks.rb +87 -0
  46. data/lib/sequel/plugins/association_proxies.rb +8 -0
  47. data/lib/sequel/plugins/boolean_readers.rb +12 -6
  48. data/lib/sequel/plugins/caching.rb +14 -7
  49. data/lib/sequel/plugins/class_table_inheritance.rb +15 -9
  50. data/lib/sequel/plugins/composition.rb +2 -1
  51. data/lib/sequel/plugins/force_encoding.rb +10 -7
  52. data/lib/sequel/plugins/hook_class_methods.rb +12 -11
  53. data/lib/sequel/plugins/identity_map.rb +9 -0
  54. data/lib/sequel/plugins/instance_hooks.rb +23 -13
  55. data/lib/sequel/plugins/lazy_attributes.rb +4 -1
  56. data/lib/sequel/plugins/many_through_many.rb +18 -4
  57. data/lib/sequel/plugins/nested_attributes.rb +1 -0
  58. data/lib/sequel/plugins/optimistic_locking.rb +1 -1
  59. data/lib/sequel/plugins/rcte_tree.rb +9 -8
  60. data/lib/sequel/plugins/schema.rb +8 -0
  61. data/lib/sequel/plugins/serialization.rb +1 -3
  62. data/lib/sequel/plugins/sharding.rb +135 -0
  63. data/lib/sequel/plugins/single_table_inheritance.rb +117 -25
  64. data/lib/sequel/plugins/skip_create_refresh.rb +35 -0
  65. data/lib/sequel/plugins/string_stripper.rb +26 -0
  66. data/lib/sequel/plugins/tactical_eager_loading.rb +8 -0
  67. data/lib/sequel/plugins/timestamps.rb +15 -2
  68. data/lib/sequel/plugins/touch.rb +13 -0
  69. data/lib/sequel/plugins/update_primary_key.rb +48 -0
  70. data/lib/sequel/plugins/validation_class_methods.rb +8 -0
  71. data/lib/sequel/plugins/validation_helpers.rb +1 -1
  72. data/lib/sequel/sql.rb +17 -20
  73. data/lib/sequel/version.rb +1 -1
  74. data/spec/adapters/postgres_spec.rb +5 -5
  75. data/spec/core/core_sql_spec.rb +17 -1
  76. data/spec/core/database_spec.rb +17 -5
  77. data/spec/core/dataset_spec.rb +31 -8
  78. data/spec/core/schema_generator_spec.rb +8 -1
  79. data/spec/core/schema_spec.rb +13 -0
  80. data/spec/extensions/association_pks_spec.rb +85 -0
  81. data/spec/extensions/hook_class_methods_spec.rb +9 -9
  82. data/spec/extensions/migration_spec.rb +339 -219
  83. data/spec/extensions/schema_dumper_spec.rb +28 -17
  84. data/spec/extensions/sharding_spec.rb +272 -0
  85. data/spec/extensions/single_table_inheritance_spec.rb +92 -4
  86. data/spec/extensions/skip_create_refresh_spec.rb +17 -0
  87. data/spec/extensions/string_stripper_spec.rb +23 -0
  88. data/spec/extensions/update_primary_key_spec.rb +65 -0
  89. data/spec/extensions/validation_class_methods_spec.rb +5 -5
  90. data/spec/files/bad_down_migration/001_create_alt_basic.rb +4 -0
  91. data/spec/files/bad_down_migration/002_create_alt_advanced.rb +4 -0
  92. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +9 -0
  93. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +9 -0
  94. data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +3 -0
  95. data/spec/files/bad_up_migration/001_create_alt_basic.rb +4 -0
  96. data/spec/files/bad_up_migration/002_create_alt_advanced.rb +3 -0
  97. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +9 -0
  98. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +9 -0
  99. data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +4 -0
  100. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +9 -0
  101. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +9 -0
  102. data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +4 -0
  103. data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +4 -0
  104. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +9 -0
  105. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +9 -0
  106. data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +4 -0
  107. data/spec/files/integer_migrations/001_create_sessions.rb +9 -0
  108. data/spec/files/integer_migrations/002_create_nodes.rb +9 -0
  109. data/spec/files/integer_migrations/003_3_create_users.rb +4 -0
  110. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +9 -0
  111. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +9 -0
  112. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +9 -0
  113. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +9 -0
  114. data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +4 -0
  115. data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +4 -0
  116. data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +4 -0
  117. data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +9 -0
  118. data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +4 -0
  119. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +9 -0
  120. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +9 -0
  121. data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +4 -0
  122. data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +9 -0
  123. data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +9 -0
  124. data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +4 -0
  125. data/spec/integration/eager_loader_test.rb +20 -20
  126. data/spec/integration/migrator_test.rb +187 -0
  127. data/spec/integration/plugin_test.rb +150 -0
  128. data/spec/integration/schema_test.rb +13 -2
  129. data/spec/model/associations_spec.rb +41 -14
  130. data/spec/model/base_spec.rb +69 -0
  131. data/spec/model/eager_loading_spec.rb +7 -3
  132. data/spec/model/record_spec.rb +79 -4
  133. data/spec/model/validations_spec.rb +21 -9
  134. metadata +66 -5
  135. data/doc/schema.rdoc +0 -36
  136. data/lib/sequel/database/schema_sql.rb +0 -320
@@ -7,6 +7,7 @@ module Sequel
7
7
  # Nested attributes are created using the nested_attributes method:
8
8
  #
9
9
  # Artist.one_to_many :albums
10
+ # Artist.plugin :nested_attributes
10
11
  # Artist.nested_attributes :albums
11
12
  # a = Artist.new(:name=>'YJM',
12
13
  # :albums_attributes=>[{:name=>'RF'}, {:name=>'MO'}])
@@ -1,5 +1,5 @@
1
1
  module Sequel
2
- require 'plugins/instance_filters'
2
+ tsk_require 'sequel/plugins/instance_filters'
3
3
 
4
4
  module Plugins
5
5
  # This plugin implements a simple database-independent locking mechanism
@@ -146,11 +146,11 @@ module Sequel
146
146
  end
147
147
  end
148
148
  a[:after_load] ||= aal
149
- a[:eager_loader] ||= proc do |key_hash, objects, associations|
150
- id_map = key_hash[key]
149
+ a[:eager_loader] ||= proc do |eo|
150
+ id_map = eo[:key_hash][key]
151
151
  parent_map = {}
152
152
  children_map = {}
153
- objects.each do |obj|
153
+ eo[:rows].each do |obj|
154
154
  parent_map[obj[prkey]] = obj
155
155
  (children_map[obj[key]] ||= []) << obj
156
156
  obj.associations[ancestors] = []
@@ -164,7 +164,7 @@ module Sequel
164
164
  model.join(t, key=>prkey).
165
165
  select(SQL::QualifiedIdentifier.new(t, ka), c_all)),
166
166
  r.select,
167
- associations).all do |obj|
167
+ eo[:associations], eo).all do |obj|
168
168
  opk = obj[prkey]
169
169
  if in_pm = parent_map.has_key?(opk)
170
170
  if idm_obj = parent_map[opk]
@@ -224,11 +224,12 @@ module Sequel
224
224
  end
225
225
  end
226
226
  d[:after_load] = dal
227
- d[:eager_loader] ||= proc do |key_hash, objects, associations|
228
- id_map = key_hash[prkey]
227
+ d[:eager_loader] ||= proc do |eo|
228
+ id_map = eo[:key_hash][prkey]
229
+ associations = eo[:associations]
229
230
  parent_map = {}
230
231
  children_map = {}
231
- objects.each do |obj|
232
+ eo[:rows].each do |obj|
232
233
  parent_map[obj[prkey]] = obj
233
234
  obj.associations[descendants] = []
234
235
  obj.associations[childrena] = []
@@ -248,7 +249,7 @@ module Sequel
248
249
  model.eager_loading_dataset(r,
249
250
  model.from(t).with_recursive(t, base_case, recursive_case),
250
251
  r.select,
251
- associations).all do |obj|
252
+ associations, eo).all do |obj|
252
253
  if level
253
254
  no_cache = no_cache_level == obj.values.delete(la)
254
255
  end
@@ -8,6 +8,14 @@ module Sequel
8
8
  # This plugin is mostly suited to test code. If there is any
9
9
  # chance that your application's schema could change, you should
10
10
  # be using the migration extension instead.
11
+ #
12
+ # Usage:
13
+ #
14
+ # # Add the schema methods to all model subclasses (called before loading subclasses)
15
+ # Sequel::Model.plugin :schema
16
+ #
17
+ # # Add the schema methods to the Album class
18
+ # Album.plugin :schema
11
19
  module Schema
12
20
  module ClassMethods
13
21
  # Creates table, using the column information from set_schema.
@@ -117,10 +117,8 @@ module Sequel
117
117
 
118
118
  # Serialize all deserialized values
119
119
  def before_save
120
+ deserialized_values.each{|k,v| @values[k] = serialize_value(k, v)}
120
121
  super
121
- deserialized_values.each do |k,v|
122
- @values[k] = serialize_value(k, v)
123
- end
124
122
  end
125
123
 
126
124
  # Empty the deserialized values when refreshing.
@@ -0,0 +1,135 @@
1
+ module Sequel
2
+ module Plugins
3
+ # The sharding plugin makes it easy to use Sequel's sharding features
4
+ # with models. It lets you create model objects on specific shards,
5
+ # and any models retrieved from specific shards are automatically
6
+ # saved back to those shards. It also works with associations,
7
+ # so that model objects retrieved from specific shards will only
8
+ # return associated objects from that shard, and using the
9
+ # add/remove/remove_all association methods will only affect
10
+ # that shard.
11
+ #
12
+ # Usage:
13
+ #
14
+ # # Add the sharding support to all model subclasses (called before loading subclasses)
15
+ # Sequel::Model.plugin :sharding
16
+ #
17
+ # # Add the sharding support to the Album class
18
+ # Album.plugin :sharding
19
+ module Sharding
20
+ module ClassMethods
21
+ # Create a new object on the given shard s.
22
+ def create_using_server(s, values={}, &block)
23
+ new_using_server(s, values, &block).save
24
+ end
25
+
26
+ # When eagerly loading, if the current dataset has a defined shard and the
27
+ # dataset that you will be using to get the associated records does not,
28
+ # use the current dataset's shard for the associated dataset.
29
+ def eager_loading_dataset(opts, ds, select, associations, eager_options={})
30
+ ds = super(opts, ds, select, associations, eager_options)
31
+ if !ds.opts[:server] and s = eager_options[:self] and server = s.opts[:server]
32
+ ds = ds.server(server)
33
+ end
34
+ ds
35
+ end
36
+
37
+ # Return a newly instantiated object that is tied to the given
38
+ # shard s. When the object is saved, a record will be inserted
39
+ # on shard s.
40
+ def new_using_server(s, values={}, &block)
41
+ new(values, &block).set_server(s)
42
+ end
43
+ end
44
+
45
+ module InstanceMethods
46
+ # Set the shard that this object is tied to. Returns self.
47
+ def set_server(s)
48
+ @server = s
49
+ self
50
+ end
51
+
52
+ # Set the server that this object is tied to, unless it has
53
+ # already been set. Returns self.
54
+ def set_server?(s)
55
+ @server ||= s
56
+ self
57
+ end
58
+
59
+ # Ensure that the instance dataset is tied to the correct shard.
60
+ def this
61
+ use_server(super)
62
+ end
63
+
64
+ private
65
+
66
+ # Ensure that association datasets are tied to the correct shard.
67
+ def _apply_association_options(*args)
68
+ use_server(super)
69
+ end
70
+
71
+ # Ensure that the object is inserted into the correct shard.
72
+ def _insert_dataset
73
+ use_server(super)
74
+ end
75
+
76
+ # Ensure that the join table for many_to_many associations uses the correct shard.
77
+ def _join_table_dataset(opts)
78
+ use_server(super)
79
+ end
80
+
81
+ # Make sure to use the correct shard when using a transaction
82
+ def checked_transaction(opts={}, &block)
83
+ super(@server ? {:server=>@server}.merge(opts) : opts, &block)
84
+ end
85
+
86
+ # If creating the object by doing <tt>add_association</tt> for a
87
+ # +many_to_many+ association, make sure the associated object is created on the
88
+ # current object's shard, unless the passed object already has an assigned shard.
89
+ def ensure_associated_primary_key(opts, o, *args)
90
+ o.set_server?(@server) if o.respond_to?(:set_server?)
91
+ super
92
+ end
93
+
94
+ # Set the given dataset to use the current object's shard.
95
+ def use_server(ds)
96
+ @server ? ds.server(@server) : ds
97
+ end
98
+ end
99
+
100
+ module DatasetMethods
101
+ # If a row proc exists on the dataset, replace it with one that calls the
102
+ # previous row_proc, but calls set_server on the output of that row_proc,
103
+ # ensuring that objects retrieved by a specific shard know which shard they
104
+ # are tied to.
105
+ def server(s)
106
+ ds = super
107
+ if rp = row_proc
108
+ ds.row_proc = proc{|r| rp.call(r).set_server(s)}
109
+ end
110
+ ds
111
+ end
112
+
113
+ private
114
+
115
+ # Set the shard of all retrieved objects to the shard of
116
+ # the table's dataset, or the current shard if the table's
117
+ # dataset does not have a shard.
118
+ def graph_each
119
+ ta = @opts[:graph][:table_aliases]
120
+ s = @opts[:server]
121
+ super do |r|
122
+ r.each do |k, v|
123
+ if ds = ta[k]
124
+ dss = ds.opts[:server]
125
+ end
126
+ vs = dss || s
127
+ v.set_server(vs) if vs && v.respond_to?(:set_server)
128
+ end
129
+ yield r
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -1,27 +1,76 @@
1
1
  module Sequel
2
2
  module Plugins
3
- # Sequel's built in Single Table Inheritance plugin makes subclasses
4
- # of this model only load rows where the given key field matches the
5
- # subclass's name. If the key given has a NULL value or there are
6
- # any problems looking up the class, uses the current class.
3
+ # The single_table_inheritance plugin allows storing all objects
4
+ # in the same class hierarchy in the same table. It makes it so
5
+ # subclasses of this model only load rows related to the subclass,
6
+ # and when you retrieve rows from the main class, you get instances
7
+ # of the subclasses (if the rows should use the subclasses's class).
8
+ #
9
+ # By default, the plugin assumes that the +sti_key+ column (the first
10
+ # argument to the plugin) holds the class name as a string. However,
11
+ # you can override this by using the <tt>:model_map</tt> option and/or
12
+ # the <tt>:key_map</tt> option.
7
13
  #
8
- # You should only use this in the parent class, not in the subclasses.
14
+ # You should only load this plugin in the parent class, not in the subclasses.
9
15
  #
10
16
  # You shouldn't call set_dataset in the model after applying this
11
- # plugin, otherwise subclasses might use the wrong dataset.
17
+ # plugin, otherwise subclasses might use the wrong dataset. You should
18
+ # make sure this plugin is loaded before the subclasses. Note that since you
19
+ # need to load the plugin before the subclasses are created, you can't use
20
+ # direct class references in the plugin class. You should specify subclasses
21
+ # in the plugin call using class name strings or symbols, see usage below.
12
22
  #
13
- # The filters and row_proc that sti_key sets up in subclasses may not work correctly if
14
- # those subclasses have further subclasses. For those middle subclasses,
15
- # you may need to call set_dataset manually with the correct filter and
16
- # row_proc.
23
+ # Usage:
24
+ #
25
+ # # Use the default of storing the class name in the sti_key
26
+ # # column (:kind in this case)
27
+ # Employee.plugin :single_table_inheritance, :kind
28
+ #
29
+ # # Using integers to store the class type, with a :model_map hash
30
+ # # and an sti_key of :type
31
+ # Employee.plugin :single_table_inheritance, :type,
32
+ # :model_map=>{1=>:Staff, 2=>:Manager}
33
+ #
34
+ # # Using non-class name strings
35
+ # Employee.plugin :single_table_inheritance, :type,
36
+ # :model_map=>{'line staff'=>:Staff, 'supervisor'=>:Manager}
37
+ #
38
+ # # Using custom procs, with :model_map taking column values
39
+ # # and yielding either a class, string, symbol, or nil,
40
+ # # and :key_map taking a class object and returning the column
41
+ # # value to use
42
+ # Employee.plugin :single_table_inheritance, :type,
43
+ # :model_map=>proc{|v| v.reverse},
44
+ # :key_map=>proc{|klass| klass.name.reverse}
45
+ #
46
+ # One minor issue to note is that if you specify the <tt>:key_map</tt>
47
+ # option as a hash, instead of having it inferred from the <tt>:model_map</tt>,
48
+ # you should only use class name strings as keys, you should not use symbols
49
+ # as keys.
17
50
  module SingleTableInheritance
18
- # Set the sti_key and sti_dataset for the model, and change the
19
- # dataset's row_proc so that the dataset yields objects of varying classes,
20
- # where the class used has the same name as the key field.
21
- def self.configure(model, key)
51
+ # Setup the necessary STI variables, see the module RDoc for SingleTableInheritance
52
+ def self.configure(model, key, opts={})
22
53
  model.instance_eval do
54
+ @sti_key_array = nil
23
55
  @sti_key = key
24
56
  @sti_dataset = dataset
57
+ @sti_model_map = opts[:model_map] || lambda{|v| v if v && v != ''}
58
+ @sti_key_map = if km = opts[:key_map]
59
+ if km.is_a?(Hash)
60
+ h = Hash.new{|h,k| h[k.to_s] unless k.is_a?(String)}
61
+ h.merge!(km)
62
+ else
63
+ km
64
+ end
65
+ elsif sti_model_map.is_a?(Hash)
66
+ h = Hash.new{|h,k| h[k.to_s] unless k.is_a?(String)}
67
+ sti_model_map.each do |k,v|
68
+ h[v.to_s] = k
69
+ end
70
+ h
71
+ else
72
+ lambda{|klass| klass.name.to_s}
73
+ end
25
74
  dataset.row_proc = lambda{|r| model.sti_load(r)}
26
75
  end
27
76
  end
@@ -34,17 +83,38 @@ module Sequel
34
83
  # The column name holding the STI key for this model
35
84
  attr_reader :sti_key
36
85
 
37
- # Copy the sti_key and sti_dataset to the subclasses, and filter the
38
- # subclass's dataset so it is restricted to rows where the key column
39
- # matches the subclass's name.
86
+ # Array holding keys for all subclasses of this class, used for the
87
+ # dataset filter in subclasses. Nil in the main class.
88
+ attr_reader :sti_key_array
89
+
90
+ # A hash/proc with class keys and column value values, mapping
91
+ # the the class to a particular value given to the sti_key column.
92
+ # Used to set the column value when creating objects, and for the
93
+ # filter when retrieving objects in subclasses.
94
+ attr_reader :sti_key_map
95
+
96
+ # A hash/proc with column value keys and class values, mapping
97
+ # the value of the sti_key column to the appropriate class to use.
98
+ attr_reader :sti_model_map
99
+
100
+ # Copy the necessary attributes to the subclasses, and filter the
101
+ # subclass's dataset based on the sti_kep_map entry for the class.
40
102
  def inherited(subclass)
41
103
  super
42
104
  sk = sti_key
43
105
  sd = sti_dataset
44
- subclass.set_dataset(sd.filter(SQL::QualifiedIdentifier.new(table_name, sk)=>subclass.name.to_s), :inherited=>true)
106
+ skm = sti_key_map
107
+ smm = sti_model_map
108
+ key = skm[subclass]
109
+ sti_subclass_added(key)
110
+ ska = [key]
111
+ subclass.set_dataset(sd.filter(SQL::QualifiedIdentifier.new(table_name, sk)=>ska), :inherited=>true)
45
112
  subclass.instance_eval do
46
113
  @sti_key = sk
114
+ @sti_key_array = ska
47
115
  @sti_dataset = sd
116
+ @sti_key_map = skm
117
+ @sti_model_map = smm
48
118
  @simple_table = nil
49
119
  end
50
120
  end
@@ -52,21 +122,43 @@ module Sequel
52
122
  # Return an instance of the class specified by sti_key,
53
123
  # used by the row_proc.
54
124
  def sti_load(r)
55
- v = r[sti_key]
56
- model = if (v && v != '')
125
+ sti_class(sti_model_map[r[sti_key]]).load(r)
126
+ end
127
+
128
+ # Make sure that all subclasses of the parent class correctly include
129
+ # keys for all of their descendant classes.
130
+ def sti_subclass_added(key)
131
+ if sti_key_array
132
+ sti_key_array << key
133
+ superclass.sti_subclass_added(key)
134
+ end
135
+ end
136
+
137
+ private
138
+
139
+ # Return a class object. If a class is given, return it directly.
140
+ # Treat strings and symbols as class names. If nil is given or
141
+ # an invalid class name string or symbol is used, return self.
142
+ # Raise an error for other types.
143
+ def sti_class(v)
144
+ case v
145
+ when String, Symbol
57
146
  constantize(v) rescue self
58
- else
147
+ when nil
59
148
  self
149
+ when Class
150
+ v
151
+ else
152
+ raise(Error, "Invalid class type used: #{v.inspect}")
60
153
  end
61
- model.load(r)
62
154
  end
63
155
  end
64
156
 
65
157
  module InstanceMethods
66
- # Set the sti_key column to the name of the model.
158
+ # Set the sti_key column based on the sti_key_map.
67
159
  def before_create
68
- return false if super == false
69
- send("#{model.sti_key}=", model.name.to_s) unless send(model.sti_key)
160
+ send("#{model.sti_key}=", model.sti_key_map[model]) unless send(model.sti_key)
161
+ super
70
162
  end
71
163
  end
72
164
  end
@@ -0,0 +1,35 @@
1
+ module Sequel
2
+ module Plugins
3
+ # SkipCreateRefresh is a simple plugin that make Sequel not
4
+ # refresh after saving a new model object. Sequel does the
5
+ # refresh to make sure all columns are populated, which is
6
+ # necessary so that database defaults work correctly.
7
+ #
8
+ # This plugin is mostly for performance reasons where you
9
+ # want to save the cost of select statement after the insert,
10
+ # but it could also help cases where records are not
11
+ # immediately available for selection after insertion.
12
+ #
13
+ # Note that Sequel does not attempt to refresh records when
14
+ # updating existing model objects, only when inserting new
15
+ # model objects.
16
+ #
17
+ # Usage:
18
+ #
19
+ # # Make all model subclass instances skip refreshes when saving
20
+ # # (called before loading subclasses)
21
+ # Sequel::Model.plugin :skip_create_refresh
22
+ #
23
+ # # Make the Album class skip refreshes when saving
24
+ # Album.plugin :skip_create_refresh
25
+ module SkipCreateRefresh
26
+ module InstanceMethods
27
+ private
28
+ # Do nothing instead of refreshing the record inside of save.
29
+ def _save_refresh
30
+ nil
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end