sequel 3.11.0 → 3.12.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +70 -0
- data/Rakefile +1 -1
- data/doc/active_record.rdoc +896 -0
- data/doc/advanced_associations.rdoc +46 -31
- data/doc/association_basics.rdoc +14 -9
- data/doc/dataset_basics.rdoc +3 -3
- data/doc/migration.rdoc +1011 -0
- data/doc/model_hooks.rdoc +198 -0
- data/doc/querying.rdoc +811 -86
- data/doc/release_notes/3.12.0.txt +304 -0
- data/doc/sharding.rdoc +17 -0
- data/doc/sql.rdoc +537 -0
- data/doc/validations.rdoc +501 -0
- data/lib/sequel/adapters/jdbc.rb +19 -27
- data/lib/sequel/adapters/jdbc/postgresql.rb +0 -7
- data/lib/sequel/adapters/mysql.rb +5 -4
- data/lib/sequel/adapters/odbc.rb +3 -2
- data/lib/sequel/adapters/shared/mssql.rb +7 -6
- data/lib/sequel/adapters/shared/mysql.rb +2 -7
- data/lib/sequel/adapters/shared/postgres.rb +2 -8
- data/lib/sequel/adapters/shared/sqlite.rb +2 -5
- data/lib/sequel/adapters/sqlite.rb +4 -4
- data/lib/sequel/core.rb +0 -1
- data/lib/sequel/database.rb +2 -1060
- data/lib/sequel/database/connecting.rb +227 -0
- data/lib/sequel/database/dataset.rb +58 -0
- data/lib/sequel/database/dataset_defaults.rb +127 -0
- data/lib/sequel/database/logging.rb +62 -0
- data/lib/sequel/database/misc.rb +246 -0
- data/lib/sequel/database/query.rb +390 -0
- data/lib/sequel/database/schema_generator.rb +7 -3
- data/lib/sequel/database/schema_methods.rb +351 -7
- data/lib/sequel/dataset/actions.rb +9 -2
- data/lib/sequel/dataset/misc.rb +6 -2
- data/lib/sequel/dataset/mutation.rb +3 -11
- data/lib/sequel/dataset/query.rb +49 -6
- data/lib/sequel/exceptions.rb +3 -0
- data/lib/sequel/extensions/migration.rb +395 -113
- data/lib/sequel/extensions/schema_dumper.rb +21 -13
- data/lib/sequel/model.rb +27 -25
- data/lib/sequel/model/associations.rb +72 -34
- data/lib/sequel/model/base.rb +74 -18
- data/lib/sequel/model/errors.rb +8 -1
- data/lib/sequel/plugins/active_model.rb +8 -0
- data/lib/sequel/plugins/association_pks.rb +87 -0
- data/lib/sequel/plugins/association_proxies.rb +8 -0
- data/lib/sequel/plugins/boolean_readers.rb +12 -6
- data/lib/sequel/plugins/caching.rb +14 -7
- data/lib/sequel/plugins/class_table_inheritance.rb +15 -9
- data/lib/sequel/plugins/composition.rb +2 -1
- data/lib/sequel/plugins/force_encoding.rb +10 -7
- data/lib/sequel/plugins/hook_class_methods.rb +12 -11
- data/lib/sequel/plugins/identity_map.rb +9 -0
- data/lib/sequel/plugins/instance_hooks.rb +23 -13
- data/lib/sequel/plugins/lazy_attributes.rb +4 -1
- data/lib/sequel/plugins/many_through_many.rb +18 -4
- data/lib/sequel/plugins/nested_attributes.rb +1 -0
- data/lib/sequel/plugins/optimistic_locking.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +9 -8
- data/lib/sequel/plugins/schema.rb +8 -0
- data/lib/sequel/plugins/serialization.rb +1 -3
- data/lib/sequel/plugins/sharding.rb +135 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +117 -25
- data/lib/sequel/plugins/skip_create_refresh.rb +35 -0
- data/lib/sequel/plugins/string_stripper.rb +26 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +8 -0
- data/lib/sequel/plugins/timestamps.rb +15 -2
- data/lib/sequel/plugins/touch.rb +13 -0
- data/lib/sequel/plugins/update_primary_key.rb +48 -0
- data/lib/sequel/plugins/validation_class_methods.rb +8 -0
- data/lib/sequel/plugins/validation_helpers.rb +1 -1
- data/lib/sequel/sql.rb +17 -20
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +5 -5
- data/spec/core/core_sql_spec.rb +17 -1
- data/spec/core/database_spec.rb +17 -5
- data/spec/core/dataset_spec.rb +31 -8
- data/spec/core/schema_generator_spec.rb +8 -1
- data/spec/core/schema_spec.rb +13 -0
- data/spec/extensions/association_pks_spec.rb +85 -0
- data/spec/extensions/hook_class_methods_spec.rb +9 -9
- data/spec/extensions/migration_spec.rb +339 -219
- data/spec/extensions/schema_dumper_spec.rb +28 -17
- data/spec/extensions/sharding_spec.rb +272 -0
- data/spec/extensions/single_table_inheritance_spec.rb +92 -4
- data/spec/extensions/skip_create_refresh_spec.rb +17 -0
- data/spec/extensions/string_stripper_spec.rb +23 -0
- data/spec/extensions/update_primary_key_spec.rb +65 -0
- data/spec/extensions/validation_class_methods_spec.rb +5 -5
- data/spec/files/bad_down_migration/001_create_alt_basic.rb +4 -0
- data/spec/files/bad_down_migration/002_create_alt_advanced.rb +4 -0
- data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +9 -0
- data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +9 -0
- data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +3 -0
- data/spec/files/bad_up_migration/001_create_alt_basic.rb +4 -0
- data/spec/files/bad_up_migration/002_create_alt_advanced.rb +3 -0
- data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +9 -0
- data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +9 -0
- data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +4 -0
- data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +9 -0
- data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +9 -0
- data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +4 -0
- data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +4 -0
- data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +9 -0
- data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +9 -0
- data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +4 -0
- data/spec/files/integer_migrations/001_create_sessions.rb +9 -0
- data/spec/files/integer_migrations/002_create_nodes.rb +9 -0
- data/spec/files/integer_migrations/003_3_create_users.rb +4 -0
- data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +9 -0
- data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +9 -0
- data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +9 -0
- data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +9 -0
- data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +4 -0
- data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +4 -0
- data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +4 -0
- data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +9 -0
- data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +4 -0
- data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +9 -0
- data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +9 -0
- data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +4 -0
- data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +9 -0
- data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +9 -0
- data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +4 -0
- data/spec/integration/eager_loader_test.rb +20 -20
- data/spec/integration/migrator_test.rb +187 -0
- data/spec/integration/plugin_test.rb +150 -0
- data/spec/integration/schema_test.rb +13 -2
- data/spec/model/associations_spec.rb +41 -14
- data/spec/model/base_spec.rb +69 -0
- data/spec/model/eager_loading_spec.rb +7 -3
- data/spec/model/record_spec.rb +79 -4
- data/spec/model/validations_spec.rb +21 -9
- metadata +66 -5
- data/doc/schema.rdoc +0 -36
- 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'}])
|
@@ -146,11 +146,11 @@ module Sequel
|
|
146
146
|
end
|
147
147
|
end
|
148
148
|
a[:after_load] ||= aal
|
149
|
-
a[:eager_loader] ||= proc do |
|
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
|
-
|
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 |
|
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
|
-
|
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
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
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
|
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
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
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
|
-
#
|
19
|
-
|
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
|
-
#
|
38
|
-
#
|
39
|
-
|
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
|
-
|
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
|
-
|
56
|
-
|
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
|
-
|
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
|
158
|
+
# Set the sti_key column based on the sti_key_map.
|
67
159
|
def before_create
|
68
|
-
|
69
|
-
|
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
|