sequel 3.11.0 → 3.12.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 +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
|
@@ -13,12 +13,12 @@ module Sequel
|
|
|
13
13
|
def dump_indexes_migration(options={})
|
|
14
14
|
ts = tables(options)
|
|
15
15
|
<<END_MIG
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
Sequel.migration do
|
|
17
|
+
up do
|
|
18
18
|
#{ts.sort_by{|t| t.to_s}.map{|t| dump_table_indexes(t, :add_index, options)}.reject{|x| x == ''}.join("\n\n").gsub(/^/o, ' ')}
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
down do
|
|
22
22
|
#{ts.sort_by{|t| t.to_s}.map{|t| dump_table_indexes(t, :drop_index, options)}.reject{|x| x == ''}.join("\n\n").gsub(/^/o, ' ')}
|
|
23
23
|
end
|
|
24
24
|
end
|
|
@@ -37,12 +37,12 @@ END_MIG
|
|
|
37
37
|
def dump_schema_migration(options={})
|
|
38
38
|
ts = tables(options)
|
|
39
39
|
<<END_MIG
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
Sequel.migration do
|
|
41
|
+
up do
|
|
42
42
|
#{ts.sort_by{|t| t.to_s}.map{|t| dump_table_schema(t, options)}.join("\n\n").gsub(/^/o, ' ')}
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
down do
|
|
46
46
|
drop_table(#{ts.sort_by{|t| t.to_s}.inspect[1...-1]})
|
|
47
47
|
end
|
|
48
48
|
end
|
|
@@ -52,12 +52,18 @@ END_MIG
|
|
|
52
52
|
# Return a string with a create table block that will recreate the given
|
|
53
53
|
# table's schema. Takes the same options as dump_schema_migration.
|
|
54
54
|
def dump_table_schema(table, options={})
|
|
55
|
+
table = table.value.to_s if table.is_a?(SQL::Identifier)
|
|
56
|
+
raise(Error, "must provide table as a Symbol, String, or Sequel::SQL::Identifier") unless [String, Symbol].any?{|c| table.is_a?(c)}
|
|
55
57
|
s = schema(table).dup
|
|
56
58
|
pks = s.find_all{|x| x.last[:primary_key] == true}.map{|x| x.first}
|
|
57
59
|
options = options.merge(:single_pk=>true) if pks.length == 1
|
|
58
60
|
m = method(:column_schema_to_generator_opts)
|
|
59
61
|
im = method(:index_to_generator_opts)
|
|
60
|
-
|
|
62
|
+
begin
|
|
63
|
+
indexes = indexes(table).sort_by{|k,v| k.to_s} if options[:indexes] != false
|
|
64
|
+
rescue Sequel::NotImplemented
|
|
65
|
+
nil
|
|
66
|
+
end
|
|
61
67
|
gen = Schema::Generator.new(self) do
|
|
62
68
|
s.each{|name, info| send(*m.call(name, info, options))}
|
|
63
69
|
primary_key(pks) if !@primary_key && pks.length > 0
|
|
@@ -128,8 +134,8 @@ END_MIG
|
|
|
128
134
|
{:type=>Date}
|
|
129
135
|
when /\A(?:small)?datetime\z/o
|
|
130
136
|
{:type=>DateTime}
|
|
131
|
-
when /\Atimestamp(?: with(?:out)? time zone)?\z/o
|
|
132
|
-
{:type=>DateTime}
|
|
137
|
+
when /\Atimestamp(?:\((\d+)\))?(?: with(?:out)? time zone)?\z/o
|
|
138
|
+
{:type=>DateTime, :size=>($1.to_i if $1)}
|
|
133
139
|
when /\Atime(?: with(?:out)? time zone)?\z/o
|
|
134
140
|
{:type=>Time, :only_time=>true}
|
|
135
141
|
when /\An?char(?:acter)?(?:\((\d+)\))?\z/o
|
|
@@ -208,7 +214,7 @@ END_MIG
|
|
|
208
214
|
# Dump this generator's constraints to a string that could be evaled inside
|
|
209
215
|
# another instance to represent the same constraints
|
|
210
216
|
def dump_constraints
|
|
211
|
-
constraints.map do |c|
|
|
217
|
+
cs = constraints.map do |c|
|
|
212
218
|
c = c.dup
|
|
213
219
|
type = c.delete(:type)
|
|
214
220
|
case type
|
|
@@ -224,7 +230,8 @@ END_MIG
|
|
|
224
230
|
cols = c.delete(:columns)
|
|
225
231
|
"#{type} #{cols.inspect}#{opts_inspect(c)}"
|
|
226
232
|
end
|
|
227
|
-
end
|
|
233
|
+
end
|
|
234
|
+
cs.join("\n")
|
|
228
235
|
end
|
|
229
236
|
|
|
230
237
|
# Dump this generator's indexes to a string that could be evaled inside
|
|
@@ -235,7 +242,7 @@ END_MIG
|
|
|
235
242
|
# * :drop_index - Same as add_index, but create drop_index statements.
|
|
236
243
|
# * :ignore_errors - Add the ignore_errors option to the outputted indexes
|
|
237
244
|
def dump_indexes(options={})
|
|
238
|
-
indexes.map do |c|
|
|
245
|
+
is = indexes.map do |c|
|
|
239
246
|
c = c.dup
|
|
240
247
|
cols = c.delete(:columns)
|
|
241
248
|
if table = options[:add_index] || options[:drop_index]
|
|
@@ -243,7 +250,8 @@ END_MIG
|
|
|
243
250
|
else
|
|
244
251
|
"index #{cols.inspect}#{opts_inspect(c)}"
|
|
245
252
|
end
|
|
246
|
-
end
|
|
253
|
+
end
|
|
254
|
+
is.join("\n")
|
|
247
255
|
end
|
|
248
256
|
|
|
249
257
|
private
|
data/lib/sequel/model.rb
CHANGED
|
@@ -44,28 +44,30 @@ module Sequel
|
|
|
44
44
|
ANONYMOUS_MODEL_CLASSES = {}
|
|
45
45
|
|
|
46
46
|
# Class methods added to model that call the method of the same name on the dataset
|
|
47
|
-
DATASET_METHODS =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
inner_join insert insert_multiple intersect interval invert join join_table
|
|
51
|
-
last left_join left_outer_join limit lock_style map max min multi_insert naked
|
|
52
|
-
natural_full_join natural_join natural_left_join natural_right_join order order_by
|
|
53
|
-
order_more paginate print qualify query range reverse reverse_order right_join right_outer_join
|
|
54
|
-
select select_all select_append select_hash select_map select_more select_order_map
|
|
55
|
-
server set set_defaults set_graph_aliases set_overrides
|
|
56
|
-
single_value sum to_csv to_hash truncate unfiltered ungraphed ungrouped union unlimited unordered
|
|
57
|
-
update where with with_recursive with_sql'.map{|x| x.to_sym}
|
|
58
|
-
|
|
47
|
+
DATASET_METHODS = (Dataset::ACTION_METHODS + Dataset::QUERY_METHODS +
|
|
48
|
+
[:eager, :eager_graph, :each_page, :each_server, :print]) - [:and, :or, :[], :[]=, :columns, :columns!]
|
|
49
|
+
|
|
59
50
|
# Class instance variables to set to nil when a subclass is created, for -w compliance
|
|
60
51
|
EMPTY_INSTANCE_VARIABLES = [:@overridable_methods_module, :@db]
|
|
61
52
|
|
|
53
|
+
# Boolean settings that can be modified at the global, class, or instance level.
|
|
54
|
+
BOOLEAN_SETTINGS = [:typecast_empty_string_to_nil, :typecast_on_assignment, :strict_param_setting, :raise_on_save_failure, :raise_on_typecast_failure, :require_modification, :use_transactions]
|
|
55
|
+
|
|
56
|
+
# Hooks that are called before an action. Can return false to not do the action. When
|
|
57
|
+
# overriding these, it is recommended to call super as the last line of your method,
|
|
58
|
+
# so later hooks are called before earlier hooks.
|
|
59
|
+
BEFORE_HOOKS = [:before_create, :before_update, :before_save, :before_destroy, :before_validation]
|
|
60
|
+
|
|
61
|
+
# Hooks that are called after an action. When overriding these, it is recommended to call
|
|
62
|
+
# super on the first line of your method, so later hooks are called before earlier hooks.
|
|
63
|
+
AFTER_HOOKS = [:after_initialize, :after_create, :after_update, :after_save, :after_destroy, :after_validation]
|
|
64
|
+
|
|
62
65
|
# Empty instance methods to create that the user can override to get hook/callback behavior.
|
|
63
66
|
# Just like any other method defined by Sequel, if you override one of these, you should
|
|
64
67
|
# call super to get the default behavior (while empty by default, they can also be defined
|
|
65
|
-
# by plugins).
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
:before_validation, :after_validation]
|
|
68
|
+
# by plugins). See the {"Model Hooks" guide}[link:files/doc/model_hooks_rdoc.html] for
|
|
69
|
+
# more detail on hooks.
|
|
70
|
+
HOOKS = BEFORE_HOOKS + AFTER_HOOKS
|
|
69
71
|
|
|
70
72
|
# Class instance variables that are inherited in subclasses. If the value is :dup, dup is called
|
|
71
73
|
# on the superclass's instance variable when creating the instance variable in the subclass.
|
|
@@ -83,10 +85,6 @@ module Sequel
|
|
|
83
85
|
# avoid problems when using eval with a string to define methods.
|
|
84
86
|
NORMAL_METHOD_NAME_REGEXP = /\A[A-Za-z_][A-Za-z0-9_]*\z/
|
|
85
87
|
|
|
86
|
-
# The setter methods (methods ending with =) that are never allowed
|
|
87
|
-
# to be called automatically via set/update/new/etc..
|
|
88
|
-
RESTRICTED_SETTER_METHODS = %w"== === []= taguri= typecast_empty_string_to_nil= typecast_on_assignment= strict_param_setting= raise_on_save_failure= raise_on_typecast_failure="
|
|
89
|
-
|
|
90
88
|
# Regular expression that determines if the method is a valid setter name
|
|
91
89
|
# (i.e. it ends with =).
|
|
92
90
|
SETTER_METHOD_REGEXP = /=\z/
|
|
@@ -110,11 +108,15 @@ module Sequel
|
|
|
110
108
|
@typecast_empty_string_to_nil = true
|
|
111
109
|
@typecast_on_assignment = true
|
|
112
110
|
@use_transactions = true
|
|
113
|
-
end
|
|
114
111
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
112
|
+
Sequel.require %w"default_inflections inflections plugins base exceptions errors", "model"
|
|
113
|
+
if !defined?(::SEQUEL_NO_ASSOCIATIONS) && !ENV.has_key?('SEQUEL_NO_ASSOCIATIONS')
|
|
114
|
+
Sequel.require 'associations', 'model'
|
|
115
|
+
plugin Model::Associations
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# The setter methods (methods ending with =) that are never allowed
|
|
119
|
+
# to be called automatically via set/update/new/etc..
|
|
120
|
+
RESTRICTED_SETTER_METHODS = instance_methods.map{|x| x.to_s}.grep(SETTER_METHOD_REGEXP)
|
|
119
121
|
end
|
|
120
122
|
end
|
|
@@ -310,6 +310,11 @@ module Sequel
|
|
|
310
310
|
self[:join_table]
|
|
311
311
|
end
|
|
312
312
|
|
|
313
|
+
# Alias of right_primary_keys
|
|
314
|
+
def associated_object_keys
|
|
315
|
+
right_primary_keys
|
|
316
|
+
end
|
|
317
|
+
|
|
313
318
|
# many_to_many associations can only have associated objects if none of
|
|
314
319
|
# the :left_primary_keys options have a nil value.
|
|
315
320
|
def can_have_associated_objects?(obj)
|
|
@@ -380,7 +385,6 @@ module Sequel
|
|
|
380
385
|
def right_primary_keys
|
|
381
386
|
self[:right_primary_keys] ||= Array(right_primary_key)
|
|
382
387
|
end
|
|
383
|
-
alias associated_object_keys right_primary_keys
|
|
384
388
|
|
|
385
389
|
# The columns to select when loading the association, associated_class.table_name.* by default.
|
|
386
390
|
def select
|
|
@@ -441,8 +445,8 @@ module Sequel
|
|
|
441
445
|
# => {:type => :many_to_one, :name => :portfolio, :class_name => "Portfolio"}
|
|
442
446
|
#
|
|
443
447
|
# For a more in depth general overview, as well as a reference guide,
|
|
444
|
-
# see the {Association Basics
|
|
445
|
-
# For examples of advanced usage, see the {Advanced Associations
|
|
448
|
+
# see the {Association Basics guide}[link:files/doc/association_basics_rdoc.html].
|
|
449
|
+
# For examples of advanced usage, see the {Advanced Associations guide}[link:files/doc/advanced_associations_rdoc.html].
|
|
446
450
|
module ClassMethods
|
|
447
451
|
# All association reflections defined for this model (default: none).
|
|
448
452
|
attr_reader :association_reflections
|
|
@@ -521,9 +525,11 @@ module Sequel
|
|
|
521
525
|
# Takes three arguments, a dataset, an alias to use for the table to graph for this association,
|
|
522
526
|
# and the alias that was used for the current table (since you can cascade associations),
|
|
523
527
|
# Should return a copy of the dataset with the association graphed into it.
|
|
524
|
-
# - :eager_loader - A proc to use to implement eager loading, overriding the default. Takes three arguments
|
|
525
|
-
# a key hash (used solely to enhance performance), an array of records,
|
|
526
|
-
# and a hash of dependent associations.
|
|
528
|
+
# - :eager_loader - A proc to use to implement eager loading, overriding the default. Takes one or three arguments.
|
|
529
|
+
# If three arguments, the first should be a key hash (used solely to enhance performance), the second an array of records,
|
|
530
|
+
# and the third a hash of dependent associations. If one argument, is passed a hash with keys :key_hash,
|
|
531
|
+
# :rows, and :associations, corresponding to the three arguments, and an additional key :self, which is
|
|
532
|
+
# the dataset doing the eager loading. In the proc, the associated records should
|
|
527
533
|
# be queried from the database and the associations cache for each
|
|
528
534
|
# record should be populated for this to work correctly.
|
|
529
535
|
# - :eager_loader_key - A symbol for the key column to use to populate the key hash
|
|
@@ -593,6 +599,8 @@ module Sequel
|
|
|
593
599
|
# the current model and the associated model, as a symbol. Defaults to the name
|
|
594
600
|
# of current model and name of associated model, pluralized,
|
|
595
601
|
# underscored, sorted, and joined with '_'.
|
|
602
|
+
# - :join_table_block - proc that can be used to modify the dataset used in the add/remove/remove_all
|
|
603
|
+
# methods. Should accept a dataset argument and return a modified dataset if present.
|
|
596
604
|
# - :left_key - foreign key in join table that points to current model's
|
|
597
605
|
# primary key, as a symbol. Defaults to :"#{self.name.underscore}_id".
|
|
598
606
|
# Can use an array of symbols for a composite key association.
|
|
@@ -610,6 +618,7 @@ module Sequel
|
|
|
610
618
|
raise(Error, 'one_to_many association type with :one_to_one option removed, used one_to_one association type') if opts[:one_to_one] && type == :one_to_many
|
|
611
619
|
raise(Error, 'invalid association type') unless assoc_class = ASSOCIATION_TYPES[type]
|
|
612
620
|
raise(Error, 'Model.associate name argument must be a symbol') unless Symbol === name
|
|
621
|
+
raise(Error, ':eager_loader option must have an arity of 1 or 3') if opts[:eager_loader] && ![1, 3].include?(opts[:eager_loader].arity)
|
|
613
622
|
|
|
614
623
|
# merge early so we don't modify opts
|
|
615
624
|
orig_opts = opts.dup
|
|
@@ -649,7 +658,7 @@ module Sequel
|
|
|
649
658
|
end
|
|
650
659
|
|
|
651
660
|
# Modify and return eager loading dataset based on association options. Options:
|
|
652
|
-
def eager_loading_dataset(opts, ds, select, associations)
|
|
661
|
+
def eager_loading_dataset(opts, ds, select, associations, eager_options={})
|
|
653
662
|
ds = ds.select(*select) if select
|
|
654
663
|
if c = opts[:conditions]
|
|
655
664
|
ds = (c.is_a?(Array) && !Sequel.condition_specifier?(c)) ? ds.filter(*c) : ds.filter(c)
|
|
@@ -757,12 +766,12 @@ module Sequel
|
|
|
757
766
|
opts[:dataset] ||= proc{opts.associated_class.inner_join(join_table, rcks.zip(opts.right_primary_keys) + lcks.zip(lcpks.map{|k| send(k)}))}
|
|
758
767
|
database = db
|
|
759
768
|
|
|
760
|
-
opts[:eager_loader] ||= proc do |
|
|
761
|
-
h = key_hash[left_pk]
|
|
762
|
-
|
|
769
|
+
opts[:eager_loader] ||= proc do |eo|
|
|
770
|
+
h = eo[:key_hash][left_pk]
|
|
771
|
+
eo[:rows].each{|object| object.associations[name] = []}
|
|
763
772
|
r = uses_rcks ? rcks.zip(opts.right_primary_keys) : [[right, opts.right_primary_key]]
|
|
764
773
|
l = uses_lcks ? [[lcks.map{|k| SQL::QualifiedIdentifier.new(join_table, k)}, SQL::SQLArray.new(h.keys)]] : [[left, h.keys]]
|
|
765
|
-
model.eager_loading_dataset(opts, opts.associated_class.inner_join(join_table, r + l), Array(opts.select), associations).all do |assoc_record|
|
|
774
|
+
model.eager_loading_dataset(opts, opts.associated_class.inner_join(join_table, r + l), Array(opts.select), eo[:associations], eo).all do |assoc_record|
|
|
766
775
|
hash_key = if uses_lcks
|
|
767
776
|
left_key_alias.map{|k| assoc_record.values.delete(k)}
|
|
768
777
|
else
|
|
@@ -796,13 +805,13 @@ module Sequel
|
|
|
796
805
|
h = {}
|
|
797
806
|
lcks.zip(lcpks).each{|k, pk| h[k] = send(pk)}
|
|
798
807
|
rcks.zip(opts.right_primary_keys).each{|k, pk| h[k] = o.send(pk)}
|
|
799
|
-
|
|
808
|
+
_join_table_dataset(opts).insert(h)
|
|
800
809
|
end
|
|
801
810
|
association_module_private_def(opts._remove_method) do |o|
|
|
802
|
-
|
|
811
|
+
_join_table_dataset(opts).filter(lcks.zip(lcpks.map{|k| send(k)}) + rcks.zip(opts.right_primary_keys.map{|k| o.send(k)})).delete
|
|
803
812
|
end
|
|
804
813
|
association_module_private_def(opts._remove_all_method) do
|
|
805
|
-
|
|
814
|
+
_join_table_dataset(opts).filter(lcks.zip(lcpks.map{|k| send(k)})).delete
|
|
806
815
|
end
|
|
807
816
|
|
|
808
817
|
def_add_method(opts)
|
|
@@ -823,16 +832,16 @@ module Sequel
|
|
|
823
832
|
klass = opts.associated_class
|
|
824
833
|
klass.filter(opts.primary_keys.map{|k| SQL::QualifiedIdentifier.new(klass.table_name, k)}.zip(cks.map{|k| send(k)}))
|
|
825
834
|
end
|
|
826
|
-
opts[:eager_loader] ||= proc do |
|
|
827
|
-
h = key_hash[key]
|
|
835
|
+
opts[:eager_loader] ||= proc do |eo|
|
|
836
|
+
h = eo[:key_hash][key]
|
|
828
837
|
keys = h.keys
|
|
829
838
|
# Default the cached association to nil, so any object that doesn't have it
|
|
830
839
|
# populated will have cached the negative lookup.
|
|
831
|
-
|
|
840
|
+
eo[:rows].each{|object| object.associations[name] = nil}
|
|
832
841
|
# Skip eager loading if no objects have a foreign key for this association
|
|
833
842
|
unless keys.empty?
|
|
834
843
|
klass = opts.associated_class
|
|
835
|
-
model.eager_loading_dataset(opts, klass.filter(uses_cks ? {opts.primary_keys.map{|k| SQL::QualifiedIdentifier.new(klass.table_name, k)}=>SQL::SQLArray.new(keys)} : {SQL::QualifiedIdentifier.new(klass.table_name, opts.primary_key)=>keys}), opts.select, associations).all do |assoc_record|
|
|
844
|
+
model.eager_loading_dataset(opts, klass.filter(uses_cks ? {opts.primary_keys.map{|k| SQL::QualifiedIdentifier.new(klass.table_name, k)}=>SQL::SQLArray.new(keys)} : {SQL::QualifiedIdentifier.new(klass.table_name, opts.primary_key)=>keys}), opts.select, eo[:associations], eo).all do |assoc_record|
|
|
836
845
|
hash_key = uses_cks ? opts.primary_keys.map{|k| assoc_record.send(k)} : assoc_record.send(opts.primary_key)
|
|
837
846
|
next unless objects = h[hash_key]
|
|
838
847
|
objects.each{|object| object.associations[name] = assoc_record}
|
|
@@ -873,16 +882,16 @@ module Sequel
|
|
|
873
882
|
klass = opts.associated_class
|
|
874
883
|
klass.filter(cks.map{|k| SQL::QualifiedIdentifier.new(klass.table_name, k)}.zip(cpks.map{|k| send(k)}))
|
|
875
884
|
end
|
|
876
|
-
opts[:eager_loader] ||= proc do |
|
|
877
|
-
h = key_hash[primary_key]
|
|
885
|
+
opts[:eager_loader] ||= proc do |eo|
|
|
886
|
+
h = eo[:key_hash][primary_key]
|
|
878
887
|
if one_to_one
|
|
879
|
-
|
|
888
|
+
eo[:rows].each{|object| object.associations[name] = nil}
|
|
880
889
|
else
|
|
881
|
-
|
|
890
|
+
eo[:rows].each{|object| object.associations[name] = []}
|
|
882
891
|
end
|
|
883
892
|
reciprocal = opts.reciprocal
|
|
884
893
|
klass = opts.associated_class
|
|
885
|
-
model.eager_loading_dataset(opts, klass.filter(uses_cks ? {cks.map{|k| SQL::QualifiedIdentifier.new(klass.table_name, k)}=>SQL::SQLArray.new(h.keys)} : {SQL::QualifiedIdentifier.new(klass.table_name, key)=>h.keys}), opts.select, associations).all do |assoc_record|
|
|
894
|
+
model.eager_loading_dataset(opts, klass.filter(uses_cks ? {cks.map{|k| SQL::QualifiedIdentifier.new(klass.table_name, k)}=>SQL::SQLArray.new(h.keys)} : {SQL::QualifiedIdentifier.new(klass.table_name, key)=>h.keys}), opts.select, eo[:associations], eo).all do |assoc_record|
|
|
886
895
|
hash_key = uses_cks ? cks.map{|k| assoc_record.send(k)} : assoc_record.send(key)
|
|
887
896
|
next unless objects = h[hash_key]
|
|
888
897
|
if one_to_one
|
|
@@ -928,11 +937,10 @@ module Sequel
|
|
|
928
937
|
up_ds = up_ds.exclude(o.pk_hash)
|
|
929
938
|
cks.zip(cpks).each{|k, pk| o.send(:"#{k}=", send(pk))}
|
|
930
939
|
end
|
|
931
|
-
|
|
940
|
+
checked_transaction do
|
|
932
941
|
up_ds.update(ck_nil_hash)
|
|
933
942
|
o.save(:validate=>validate) || raise(Sequel::Error, "invalid associated object, cannot save") if o
|
|
934
943
|
end
|
|
935
|
-
use_transactions && o ? db.transaction(opts){update_database.call} : update_database.call
|
|
936
944
|
end
|
|
937
945
|
association_module_def(opts.setter_method){|o| set_one_to_one_associated_object(opts, o)}
|
|
938
946
|
else
|
|
@@ -953,7 +961,11 @@ module Sequel
|
|
|
953
961
|
end
|
|
954
962
|
end
|
|
955
963
|
end
|
|
956
|
-
|
|
964
|
+
|
|
965
|
+
# Alias of def_one_to_many
|
|
966
|
+
def def_one_to_one(opts)
|
|
967
|
+
def_one_to_many(opts)
|
|
968
|
+
end
|
|
957
969
|
|
|
958
970
|
# Add the remove_ and remove_all instance methods
|
|
959
971
|
def def_remove_methods(opts)
|
|
@@ -1005,6 +1017,12 @@ module Sequel
|
|
|
1005
1017
|
_apply_association_options(opts, send(opts._dataset_method))
|
|
1006
1018
|
end
|
|
1007
1019
|
|
|
1020
|
+
# Dataset for the join table of the given many to many association reflection
|
|
1021
|
+
def _join_table_dataset(opts)
|
|
1022
|
+
ds = model.db.from(opts[:join_table])
|
|
1023
|
+
opts[:join_table_block] ? opts[:join_table_block].call(ds) : ds
|
|
1024
|
+
end
|
|
1025
|
+
|
|
1008
1026
|
# Return the associated objects from the dataset, without callbacks, reciprocals, and caching.
|
|
1009
1027
|
def _load_associated_objects(opts)
|
|
1010
1028
|
if opts.returns_array?
|
|
@@ -1031,10 +1049,7 @@ module Sequel
|
|
|
1031
1049
|
raise(Sequel::Error, "associated object #{o.inspect} not of correct type #{klass}")
|
|
1032
1050
|
end
|
|
1033
1051
|
raise(Sequel::Error, "model object #{inspect} does not have a primary key") unless pk
|
|
1034
|
-
|
|
1035
|
-
o.save(:validate=>opts[:validate]) if o.new?
|
|
1036
|
-
raise(Sequel::Error, "associated object #{o.inspect} does not have a primary key") unless o.pk
|
|
1037
|
-
end
|
|
1052
|
+
ensure_associated_primary_key(opts, o, *args)
|
|
1038
1053
|
return if run_association_callbacks(opts, :before_add, o) == false
|
|
1039
1054
|
send(opts._add_method, o, *args)
|
|
1040
1055
|
if array = associations[opts[:name]] and !array.include?(o)
|
|
@@ -1063,6 +1078,16 @@ module Sequel
|
|
|
1063
1078
|
a.uniq!
|
|
1064
1079
|
end
|
|
1065
1080
|
|
|
1081
|
+
# Save the associated object if the associated object needs a primary key
|
|
1082
|
+
# and the associated object is new and does not have one. Raise an error if
|
|
1083
|
+
# the object still does not have a primary key
|
|
1084
|
+
def ensure_associated_primary_key(opts, o, *args)
|
|
1085
|
+
if opts.need_associated_primary_key?
|
|
1086
|
+
o.save(:validate=>opts[:validate]) if o.new?
|
|
1087
|
+
raise(Sequel::Error, "associated object #{o.inspect} does not have a primary key") unless o.pk
|
|
1088
|
+
end
|
|
1089
|
+
end
|
|
1090
|
+
|
|
1066
1091
|
# Load the associated objects using the dataset, handling callbacks, reciprocals, and caching.
|
|
1067
1092
|
def load_associated_objects(opts, reload=false)
|
|
1068
1093
|
name = opts[:name]
|
|
@@ -1095,9 +1120,7 @@ module Sequel
|
|
|
1095
1120
|
def remove_associated_object(opts, o, *args)
|
|
1096
1121
|
klass = opts.associated_class
|
|
1097
1122
|
if o.is_a?(Integer) || o.is_a?(String) || o.is_a?(Array)
|
|
1098
|
-
|
|
1099
|
-
pkh = klass.primary_key_hash(key)
|
|
1100
|
-
raise(Sequel::Error, "no object with key(s) #{key} is currently associated to #{inspect}") unless o = (opts.remove_should_check_existing? ? send(opts.dataset_method) : klass).first(pkh)
|
|
1123
|
+
o = remove_check_existing_object_from_pk(opts, o, *args)
|
|
1101
1124
|
elsif !o.is_a?(klass)
|
|
1102
1125
|
raise(Sequel::Error, "associated object #{o.inspect} not of correct type #{klass}")
|
|
1103
1126
|
elsif opts.remove_should_check_existing? && send(opts.dataset_method).filter(o.pk_hash).empty?
|
|
@@ -1113,6 +1136,16 @@ module Sequel
|
|
|
1113
1136
|
o
|
|
1114
1137
|
end
|
|
1115
1138
|
|
|
1139
|
+
# If necessary, check that the object from the associated table specified by the primary key
|
|
1140
|
+
# is currently associated to the object. If it is associated, return the object, otherwise
|
|
1141
|
+
# raise an error.
|
|
1142
|
+
def remove_check_existing_object_from_pk(opts, o, *args)
|
|
1143
|
+
key = o
|
|
1144
|
+
pkh = opts.associated_class.qualified_primary_key_hash(key)
|
|
1145
|
+
raise(Sequel::Error, "no object with key(s) #{key.inspect} is currently associated to #{inspect}") unless o = send(opts.dataset_method).first(pkh)
|
|
1146
|
+
o
|
|
1147
|
+
end
|
|
1148
|
+
|
|
1116
1149
|
# Remove/unset the current object from/as the given object's reciprocal association.
|
|
1117
1150
|
def remove_reciprocal_object(opts, o)
|
|
1118
1151
|
return unless reciprocal = opts.reciprocal
|
|
@@ -1498,7 +1531,12 @@ module Sequel
|
|
|
1498
1531
|
end
|
|
1499
1532
|
|
|
1500
1533
|
reflections.each do |r|
|
|
1501
|
-
|
|
1534
|
+
loader = r[:eager_loader]
|
|
1535
|
+
if loader.arity == 1
|
|
1536
|
+
loader.call(:key_hash=>key_hash, :rows=>a, :associations=>eager_assoc[r[:name]], :self=>self)
|
|
1537
|
+
else
|
|
1538
|
+
loader.call(key_hash, a, eager_assoc[r[:name]])
|
|
1539
|
+
end
|
|
1502
1540
|
a.each{|object| object.send(:run_association_callbacks, r, :after_load, object.associations[r[:name]])} unless r[:after_load].empty?
|
|
1503
1541
|
end
|
|
1504
1542
|
end
|
data/lib/sequel/model/base.rb
CHANGED
|
@@ -113,6 +113,11 @@ module Sequel
|
|
|
113
113
|
def dataset
|
|
114
114
|
@dataset || raise(Error, "No dataset associated with #{self}")
|
|
115
115
|
end
|
|
116
|
+
|
|
117
|
+
# Alias of set_dataset
|
|
118
|
+
def dataset=(ds)
|
|
119
|
+
set_dataset(ds)
|
|
120
|
+
end
|
|
116
121
|
|
|
117
122
|
# Returns the database associated with the Model class.
|
|
118
123
|
# If this model doesn't have a database associated with it,
|
|
@@ -236,6 +241,14 @@ module Sequel
|
|
|
236
241
|
{key => value}
|
|
237
242
|
end
|
|
238
243
|
end
|
|
244
|
+
|
|
245
|
+
# Return a hash where the keys are qualified column references. Uses the given
|
|
246
|
+
# qualifier if provided, or the table_name otherwise.
|
|
247
|
+
def qualified_primary_key_hash(value, qualifier=table_name)
|
|
248
|
+
h = primary_key_hash(value)
|
|
249
|
+
h.to_a.each{|k,v| h[SQL::QualifiedIdentifier.new(qualifier, k)] = h.delete(k)}
|
|
250
|
+
h
|
|
251
|
+
end
|
|
239
252
|
|
|
240
253
|
# Restrict the setting of the primary key(s) inside new/set/update. Because
|
|
241
254
|
# this is the default, this only make sense to use in a subclass where the
|
|
@@ -299,7 +312,6 @@ module Sequel
|
|
|
299
312
|
check_non_connection_error{@db_schema = (inherited ? superclass.db_schema : get_db_schema)}
|
|
300
313
|
self
|
|
301
314
|
end
|
|
302
|
-
alias dataset= set_dataset
|
|
303
315
|
|
|
304
316
|
# Sets the primary key for this model. You can use either a regular
|
|
305
317
|
# or a composite primary key.
|
|
@@ -524,7 +536,7 @@ module Sequel
|
|
|
524
536
|
private_class_method :class_attr_overridable, :class_attr_reader
|
|
525
537
|
|
|
526
538
|
class_attr_reader :columns, :db, :primary_key, :db_schema
|
|
527
|
-
class_attr_overridable
|
|
539
|
+
class_attr_overridable *BOOLEAN_SETTINGS
|
|
528
540
|
|
|
529
541
|
# The hash of attribute values. Keys are symbols with the names of the
|
|
530
542
|
# underlying database columns.
|
|
@@ -576,11 +588,10 @@ module Sequel
|
|
|
576
588
|
end
|
|
577
589
|
end
|
|
578
590
|
|
|
579
|
-
#
|
|
591
|
+
# Alias of eql?
|
|
580
592
|
def ==(obj)
|
|
581
|
-
(obj
|
|
593
|
+
eql?(obj)
|
|
582
594
|
end
|
|
583
|
-
alias eql? ==
|
|
584
595
|
|
|
585
596
|
# If pk is not nil, true only if the objects have the same class and pk.
|
|
586
597
|
# If pk is nil, false.
|
|
@@ -632,6 +643,11 @@ module Sequel
|
|
|
632
643
|
@values.each(&block)
|
|
633
644
|
end
|
|
634
645
|
|
|
646
|
+
# Compares model instances by values.
|
|
647
|
+
def eql?(obj)
|
|
648
|
+
(obj.class == model) && (obj.values == @values)
|
|
649
|
+
end
|
|
650
|
+
|
|
635
651
|
# Returns the validation errors associated with this object.
|
|
636
652
|
def errors
|
|
637
653
|
@errors ||= Errors.new
|
|
@@ -772,6 +788,13 @@ module Sequel
|
|
|
772
788
|
set_restricted(hash, false, except.flatten)
|
|
773
789
|
end
|
|
774
790
|
|
|
791
|
+
# For each of the fields in the given array +fields+, call the setter
|
|
792
|
+
# method with the value of that +hash+ entry for the field. Returns self.
|
|
793
|
+
def set_fields(hash, fields)
|
|
794
|
+
fields.each{|f| send("#{f}=", hash[f])}
|
|
795
|
+
self
|
|
796
|
+
end
|
|
797
|
+
|
|
775
798
|
# Set the values using the entries in the hash, only if the key
|
|
776
799
|
# is included in only.
|
|
777
800
|
def set_only(hash, *only)
|
|
@@ -800,6 +823,13 @@ module Sequel
|
|
|
800
823
|
update_restricted(hash, false, except.flatten)
|
|
801
824
|
end
|
|
802
825
|
|
|
826
|
+
# Update the instances values by calling +set_fields+ with the +hash+
|
|
827
|
+
# and +fields+, then save any changes to the record. Returns self.
|
|
828
|
+
def update_fields(hash, fields)
|
|
829
|
+
set_fields(hash, fields)
|
|
830
|
+
save_changes
|
|
831
|
+
end
|
|
832
|
+
|
|
803
833
|
# Update the values using the entries in the hash, only if the key
|
|
804
834
|
# is included in only.
|
|
805
835
|
def update_only(hash, *only)
|
|
@@ -808,7 +838,8 @@ module Sequel
|
|
|
808
838
|
|
|
809
839
|
# Validates the object. If the object is invalid, errors should be added
|
|
810
840
|
# to the errors attribute. By default, does nothing, as all models
|
|
811
|
-
# are valid by default.
|
|
841
|
+
# are valid by default. See the {"Model Validations" guide}[link:files/doc/validations_rdoc.html].
|
|
842
|
+
# for details about validation.
|
|
812
843
|
def validate
|
|
813
844
|
end
|
|
814
845
|
|
|
@@ -855,8 +886,10 @@ module Sequel
|
|
|
855
886
|
delete
|
|
856
887
|
end
|
|
857
888
|
|
|
889
|
+
# Insert the record into the database, returning the primary key if
|
|
890
|
+
# the record should be refreshed from the database.
|
|
858
891
|
def _insert
|
|
859
|
-
ds =
|
|
892
|
+
ds = _insert_dataset
|
|
860
893
|
if ds.respond_to?(:insert_select) and h = ds.insert_select(@values)
|
|
861
894
|
@values = h
|
|
862
895
|
nil
|
|
@@ -871,6 +904,12 @@ module Sequel
|
|
|
871
904
|
end
|
|
872
905
|
end
|
|
873
906
|
|
|
907
|
+
# The dataset to use when inserting a new object. The same as the model's
|
|
908
|
+
# dataset by default.
|
|
909
|
+
def _insert_dataset
|
|
910
|
+
model.dataset
|
|
911
|
+
end
|
|
912
|
+
|
|
874
913
|
# Refresh using a particular dataset, used inside save to make sure the same server
|
|
875
914
|
# is used for reading newly inserted values from the database
|
|
876
915
|
def _refresh(dataset)
|
|
@@ -886,30 +925,28 @@ module Sequel
|
|
|
886
925
|
if new?
|
|
887
926
|
return save_failure(:create) if before_create == false
|
|
888
927
|
pk = _insert
|
|
889
|
-
@this = nil
|
|
928
|
+
@this = nil
|
|
890
929
|
@new = false
|
|
891
930
|
@was_new = true
|
|
892
931
|
after_create
|
|
893
932
|
after_save
|
|
894
933
|
@was_new = nil
|
|
895
|
-
|
|
896
|
-
ds = this
|
|
897
|
-
ds = ds.server(:default) unless ds.opts[:server]
|
|
898
|
-
_refresh(ds)
|
|
899
|
-
else
|
|
900
|
-
changed_columns.clear
|
|
901
|
-
end
|
|
934
|
+
pk ? _save_refresh : changed_columns.clear
|
|
902
935
|
else
|
|
903
936
|
return save_failure(:update) if before_update == false
|
|
904
937
|
if columns.empty?
|
|
905
|
-
@columns_updated = opts[:changed]
|
|
938
|
+
@columns_updated = if opts[:changed]
|
|
939
|
+
@values.reject{|k,v| !changed_columns.include?(k)}
|
|
940
|
+
else
|
|
941
|
+
_save_update_all_columns_hash
|
|
942
|
+
end
|
|
906
943
|
changed_columns.clear
|
|
907
944
|
else # update only the specified columns
|
|
908
945
|
@columns_updated = @values.reject{|k, v| !columns.include?(k)}
|
|
909
946
|
changed_columns.reject!{|c| columns.include?(c)}
|
|
910
947
|
end
|
|
911
|
-
Array(primary_key).each{|x| @columns_updated.delete(x)}
|
|
912
948
|
_update(@columns_updated) unless @columns_updated.empty?
|
|
949
|
+
@this = nil
|
|
913
950
|
after_update
|
|
914
951
|
after_save
|
|
915
952
|
@columns_updated = nil
|
|
@@ -917,6 +954,25 @@ module Sequel
|
|
|
917
954
|
@modified = false
|
|
918
955
|
self
|
|
919
956
|
end
|
|
957
|
+
|
|
958
|
+
# Refresh the object after saving it, used to get
|
|
959
|
+
# default values of all columns. Separated from _save so it
|
|
960
|
+
# can be overridden to avoid the refresh.
|
|
961
|
+
def _save_refresh
|
|
962
|
+
_refresh(this.opts[:server] ? this : this.server(:default))
|
|
963
|
+
end
|
|
964
|
+
|
|
965
|
+
# Return a hash of values used when saving all columns of an
|
|
966
|
+
# existing object (i.e. not passing specific columns to save
|
|
967
|
+
# or using update/save_changes). Defaults to all of the
|
|
968
|
+
# object's values except unmodified primary key columns, as some
|
|
969
|
+
# databases don't like you setting primary key values even
|
|
970
|
+
# to their existing values.
|
|
971
|
+
def _save_update_all_columns_hash
|
|
972
|
+
v = @values.dup
|
|
973
|
+
Array(primary_key).each{|x| v.delete(x) unless changed_columns.include?(x)}
|
|
974
|
+
v
|
|
975
|
+
end
|
|
920
976
|
|
|
921
977
|
# Update this instance's dataset with the supplied column hash.
|
|
922
978
|
def _update(columns)
|
|
@@ -946,7 +1002,7 @@ module Sequel
|
|
|
946
1002
|
end
|
|
947
1003
|
|
|
948
1004
|
# If transactions should be used, wrap the yield in a transaction block.
|
|
949
|
-
def checked_transaction(opts)
|
|
1005
|
+
def checked_transaction(opts={})
|
|
950
1006
|
use_transaction?(opts) ? db.transaction(opts){yield} : yield
|
|
951
1007
|
end
|
|
952
1008
|
|