sequel 2.11.0 → 2.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 +168 -0
- data/README.rdoc +77 -95
- data/Rakefile +100 -80
- data/bin/sequel +2 -1
- data/doc/advanced_associations.rdoc +23 -32
- data/doc/cheat_sheet.rdoc +23 -40
- data/doc/dataset_filtering.rdoc +6 -6
- data/doc/prepared_statements.rdoc +22 -22
- data/doc/release_notes/2.12.0.txt +534 -0
- data/doc/schema.rdoc +3 -1
- data/doc/sharding.rdoc +8 -8
- data/doc/virtual_rows.rdoc +65 -0
- data/lib/sequel.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/ado.rb +3 -3
- data/lib/{sequel_core → sequel}/adapters/db2.rb +0 -0
- data/lib/{sequel_core → sequel}/adapters/dbi.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/do.rb +9 -5
- data/lib/{sequel_core → sequel}/adapters/do/mysql.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/do/postgres.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/do/sqlite.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/firebird.rb +84 -80
- data/lib/{sequel_core → sequel}/adapters/informix.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/jdbc.rb +21 -14
- data/lib/{sequel_core → sequel}/adapters/jdbc/h2.rb +14 -13
- data/lib/{sequel_core → sequel}/adapters/jdbc/mysql.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/jdbc/oracle.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/jdbc/postgresql.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/jdbc/sqlite.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/mysql.rb +60 -39
- data/lib/{sequel_core → sequel}/adapters/odbc.rb +8 -4
- data/lib/{sequel_core → sequel}/adapters/openbase.rb +0 -0
- data/lib/{sequel_core → sequel}/adapters/oracle.rb +38 -7
- data/lib/{sequel_core → sequel}/adapters/postgres.rb +24 -24
- data/lib/{sequel_core → sequel}/adapters/shared/mssql.rb +5 -5
- data/lib/{sequel_core → sequel}/adapters/shared/mysql.rb +126 -71
- data/lib/{sequel_core → sequel}/adapters/shared/oracle.rb +7 -10
- data/lib/{sequel_core → sequel}/adapters/shared/postgres.rb +159 -125
- data/lib/{sequel_core → sequel}/adapters/shared/progress.rb +1 -2
- data/lib/{sequel_core → sequel}/adapters/shared/sqlite.rb +72 -67
- data/lib/{sequel_core → sequel}/adapters/sqlite.rb +11 -7
- data/lib/{sequel_core → sequel}/adapters/utils/date_format.rb +0 -0
- data/lib/{sequel_core → sequel}/adapters/utils/stored_procedures.rb +0 -0
- data/lib/{sequel_core → sequel}/adapters/utils/unsupported.rb +19 -0
- data/lib/{sequel_core → sequel}/connection_pool.rb +7 -5
- data/lib/sequel/core.rb +221 -0
- data/lib/{sequel_core → sequel}/core_sql.rb +91 -49
- data/lib/{sequel_core → sequel}/database.rb +264 -149
- data/lib/{sequel_core/schema/generator.rb → sequel/database/schema_generator.rb} +6 -2
- data/lib/{sequel_core/database/schema.rb → sequel/database/schema_methods.rb} +12 -12
- data/lib/sequel/database/schema_sql.rb +224 -0
- data/lib/{sequel_core → sequel}/dataset.rb +78 -236
- data/lib/{sequel_core → sequel}/dataset/convenience.rb +99 -61
- data/lib/{sequel_core/object_graph.rb → sequel/dataset/graph.rb} +16 -14
- data/lib/{sequel_core → sequel}/dataset/prepared_statements.rb +1 -1
- data/lib/{sequel_core → sequel}/dataset/sql.rb +150 -99
- data/lib/sequel/deprecated.rb +593 -0
- data/lib/sequel/deprecated_migration.rb +91 -0
- data/lib/sequel/exceptions.rb +48 -0
- data/lib/sequel/extensions/blank.rb +42 -0
- data/lib/{sequel_model → sequel/extensions}/inflector.rb +8 -1
- data/lib/{sequel_core → sequel/extensions}/migration.rb +1 -1
- data/lib/{sequel_core/dataset → sequel/extensions}/pagination.rb +0 -0
- data/lib/{sequel_core → sequel/extensions}/pretty_table.rb +7 -0
- data/lib/{sequel_core/dataset → sequel/extensions}/query.rb +7 -0
- data/lib/sequel/extensions/string_date_time.rb +47 -0
- data/lib/sequel/metaprogramming.rb +43 -0
- data/lib/sequel/model.rb +110 -0
- data/lib/sequel/model/associations.rb +1300 -0
- data/lib/sequel/model/base.rb +937 -0
- data/lib/sequel/model/deprecated.rb +204 -0
- data/lib/sequel/model/deprecated_hooks.rb +103 -0
- data/lib/sequel/model/deprecated_inflector.rb +335 -0
- data/lib/sequel/model/deprecated_validations.rb +388 -0
- data/lib/sequel/model/errors.rb +39 -0
- data/lib/{sequel_model → sequel/model}/exceptions.rb +4 -4
- data/lib/sequel/model/inflections.rb +208 -0
- data/lib/sequel/model/plugins.rb +76 -0
- data/lib/sequel/plugins/caching.rb +122 -0
- data/lib/sequel/plugins/hook_class_methods.rb +122 -0
- data/lib/sequel/plugins/schema.rb +53 -0
- data/lib/sequel/plugins/serialization.rb +117 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
- data/lib/sequel/plugins/validation_class_methods.rb +384 -0
- data/lib/sequel/plugins/validation_helpers.rb +150 -0
- data/lib/{sequel_core → sequel}/sql.rb +125 -190
- data/lib/{sequel_core → sequel}/version.rb +2 -1
- data/lib/sequel_core.rb +1 -172
- data/lib/sequel_model.rb +1 -91
- data/spec/adapters/firebird_spec.rb +5 -5
- data/spec/adapters/informix_spec.rb +1 -1
- data/spec/adapters/mysql_spec.rb +128 -42
- data/spec/adapters/oracle_spec.rb +47 -19
- data/spec/adapters/postgres_spec.rb +64 -52
- data/spec/adapters/spec_helper.rb +1 -1
- data/spec/adapters/sqlite_spec.rb +12 -17
- data/spec/{sequel_core → core}/connection_pool_spec.rb +10 -10
- data/spec/{sequel_core → core}/core_ext_spec.rb +19 -19
- data/spec/{sequel_core → core}/core_sql_spec.rb +68 -71
- data/spec/{sequel_core → core}/database_spec.rb +135 -99
- data/spec/{sequel_core → core}/dataset_spec.rb +398 -242
- data/spec/{sequel_core → core}/expression_filters_spec.rb +13 -13
- data/spec/core/migration_spec.rb +263 -0
- data/spec/{sequel_core → core}/object_graph_spec.rb +10 -10
- data/spec/{sequel_core → core}/pretty_table_spec.rb +2 -2
- data/spec/{sequel_core → core}/schema_generator_spec.rb +0 -0
- data/spec/{sequel_core → core}/schema_spec.rb +8 -10
- data/spec/{sequel_core → core}/spec_helper.rb +29 -2
- data/spec/{sequel_core → core}/version_spec.rb +0 -0
- data/spec/extensions/blank_spec.rb +67 -0
- data/spec/extensions/caching_spec.rb +201 -0
- data/spec/{sequel_model/hooks_spec.rb → extensions/hook_class_methods_spec.rb} +8 -23
- data/spec/{sequel_model → extensions}/inflector_spec.rb +3 -0
- data/spec/{sequel_core → extensions}/migration_spec.rb +4 -4
- data/spec/extensions/pagination_spec.rb +99 -0
- data/spec/extensions/pretty_table_spec.rb +91 -0
- data/spec/extensions/query_spec.rb +85 -0
- data/spec/{sequel_model → extensions}/schema_spec.rb +22 -1
- data/spec/extensions/serialization_spec.rb +109 -0
- data/spec/extensions/single_table_inheritance_spec.rb +53 -0
- data/spec/{sequel_model → extensions}/spec_helper.rb +13 -4
- data/spec/extensions/string_date_time_spec.rb +93 -0
- data/spec/{sequel_model/validations_spec.rb → extensions/validation_class_methods_spec.rb} +15 -103
- data/spec/extensions/validation_helpers_spec.rb +291 -0
- data/spec/integration/dataset_test.rb +31 -0
- data/spec/integration/eager_loader_test.rb +17 -30
- data/spec/integration/schema_test.rb +8 -5
- data/spec/integration/spec_helper.rb +17 -0
- data/spec/integration/transaction_test.rb +68 -0
- data/spec/{sequel_model → model}/association_reflection_spec.rb +0 -0
- data/spec/{sequel_model → model}/associations_spec.rb +23 -10
- data/spec/{sequel_model → model}/base_spec.rb +29 -20
- data/spec/{sequel_model → model}/caching_spec.rb +16 -14
- data/spec/{sequel_model → model}/dataset_methods_spec.rb +0 -0
- data/spec/{sequel_model → model}/eager_loading_spec.rb +8 -8
- data/spec/model/hooks_spec.rb +472 -0
- data/spec/model/inflector_spec.rb +126 -0
- data/spec/{sequel_model → model}/model_spec.rb +25 -20
- data/spec/model/plugins_spec.rb +142 -0
- data/spec/{sequel_model → model}/record_spec.rb +121 -62
- data/spec/model/schema_spec.rb +92 -0
- data/spec/model/spec_helper.rb +124 -0
- data/spec/model/validations_spec.rb +1080 -0
- metadata +136 -107
- data/lib/sequel_core/core_ext.rb +0 -217
- data/lib/sequel_core/dataset/callback.rb +0 -13
- data/lib/sequel_core/dataset/schema.rb +0 -15
- data/lib/sequel_core/deprecated.rb +0 -26
- data/lib/sequel_core/exceptions.rb +0 -44
- data/lib/sequel_core/schema.rb +0 -2
- data/lib/sequel_core/schema/sql.rb +0 -325
- data/lib/sequel_model/association_reflection.rb +0 -267
- data/lib/sequel_model/associations.rb +0 -499
- data/lib/sequel_model/base.rb +0 -539
- data/lib/sequel_model/caching.rb +0 -82
- data/lib/sequel_model/dataset_methods.rb +0 -26
- data/lib/sequel_model/eager_loading.rb +0 -370
- data/lib/sequel_model/hooks.rb +0 -101
- data/lib/sequel_model/plugins.rb +0 -62
- data/lib/sequel_model/record.rb +0 -568
- data/lib/sequel_model/schema.rb +0 -49
- data/lib/sequel_model/validations.rb +0 -429
- data/spec/sequel_model/plugins_spec.rb +0 -80
data/lib/sequel_model/hooks.rb
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
module Sequel
|
|
2
|
-
class Model
|
|
3
|
-
# Hooks that are safe for public use
|
|
4
|
-
HOOKS = [:after_initialize, :before_create, :after_create, :before_update,
|
|
5
|
-
:after_update, :before_save, :after_save, :before_destroy, :after_destroy,
|
|
6
|
-
:before_validation, :after_validation]
|
|
7
|
-
|
|
8
|
-
# Hooks that are only for internal use
|
|
9
|
-
PRIVATE_HOOKS = [:before_update_values, :before_delete]
|
|
10
|
-
|
|
11
|
-
# This adds a new hook type. It will define both a class
|
|
12
|
-
# method that you can use to add hooks, as well as an instance method
|
|
13
|
-
# that you can use to call all hooks of that type. The class method
|
|
14
|
-
# can be called with a symbol or a block or both. If a block is given and
|
|
15
|
-
# and symbol is not, it adds the hook block to the hook type. If a block
|
|
16
|
-
# and symbol are both given, it replaces the hook block associated with
|
|
17
|
-
# that symbol for a given hook type, or adds it if there is no hook block
|
|
18
|
-
# with that symbol for that hook type. If no block is given, it assumes
|
|
19
|
-
# the symbol specifies an instance method to call and adds it to the hook
|
|
20
|
-
# type.
|
|
21
|
-
#
|
|
22
|
-
# If any hook block returns false, the instance method will return false
|
|
23
|
-
# immediately without running the rest of the hooks of that type.
|
|
24
|
-
#
|
|
25
|
-
# It is recommended that you always provide a symbol to this method,
|
|
26
|
-
# for descriptive purposes. It's only necessary to do so when you
|
|
27
|
-
# are using a system that reloads code.
|
|
28
|
-
#
|
|
29
|
-
# All of Sequel's standard hook types are also implemented using this
|
|
30
|
-
# method.
|
|
31
|
-
#
|
|
32
|
-
# Example of usage:
|
|
33
|
-
#
|
|
34
|
-
# class MyModel
|
|
35
|
-
# define_hook :before_move_to
|
|
36
|
-
# before_move_to(:check_move_allowed){|o| o.allow_move?}
|
|
37
|
-
# def move_to(there)
|
|
38
|
-
# return if before_move_to == false
|
|
39
|
-
# # move MyModel object to there
|
|
40
|
-
# end
|
|
41
|
-
# end
|
|
42
|
-
def self.add_hook_type(*hooks)
|
|
43
|
-
hooks.each do |hook|
|
|
44
|
-
@hooks[hook] = []
|
|
45
|
-
instance_eval("def #{hook}(method = nil, &block); define_hook_instance_method(:#{hook}); add_hook(:#{hook}, method, &block) end")
|
|
46
|
-
class_eval("def #{hook}; end")
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Returns true if there are any hook blocks for the given hook.
|
|
51
|
-
def self.has_hooks?(hook)
|
|
52
|
-
!@hooks[hook].empty?
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Yield every block related to the given hook.
|
|
56
|
-
def self.hook_blocks(hook)
|
|
57
|
-
@hooks[hook].each{|k,v| yield v}
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
### Private Class Methods ###
|
|
61
|
-
|
|
62
|
-
# Add a hook block to the list of hook methods.
|
|
63
|
-
# If a non-nil tag is given and it already is in the list of hooks,
|
|
64
|
-
# replace it with the new block.
|
|
65
|
-
def self.add_hook(hook, tag, &block) #:nodoc:
|
|
66
|
-
unless block
|
|
67
|
-
(raise Error, 'No hook method specified') unless tag
|
|
68
|
-
block = proc {send tag}
|
|
69
|
-
end
|
|
70
|
-
h = @hooks[hook]
|
|
71
|
-
if tag && (old = h.find{|x| x[0] == tag})
|
|
72
|
-
old[1] = block
|
|
73
|
-
else
|
|
74
|
-
if hook.to_s =~ /^before/
|
|
75
|
-
h.unshift([tag,block])
|
|
76
|
-
else
|
|
77
|
-
h << [tag, block]
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# Define a hook instance method that calls the run_hooks instance method.
|
|
83
|
-
def self.define_hook_instance_method(hook) #:nodoc:
|
|
84
|
-
class_eval("def #{hook}; run_hooks(:#{hook}); end")
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
private_class_method :add_hook, :define_hook_instance_method
|
|
88
|
-
|
|
89
|
-
private
|
|
90
|
-
|
|
91
|
-
# Runs all hook blocks of given hook type on this object.
|
|
92
|
-
# Stops running hook blocks and returns false if any hook block returns false.
|
|
93
|
-
def run_hooks(hook)
|
|
94
|
-
model.hook_blocks(hook){|block| return false if instance_eval(&block) == false}
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
# For performance reasons, we define empty hook instance methods, which are
|
|
98
|
-
# overwritten with real hook instance methods whenever the hook class method is called.
|
|
99
|
-
add_hook_type(*(HOOKS + PRIVATE_HOOKS))
|
|
100
|
-
end
|
|
101
|
-
end
|
data/lib/sequel_model/plugins.rb
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
module Sequel
|
|
2
|
-
# Empty namespace that plugins should use to store themselves,
|
|
3
|
-
# so they can be loaded via Model.is.
|
|
4
|
-
#
|
|
5
|
-
# Plugins should be modules with one of the following conditions:
|
|
6
|
-
# * A singleton method named apply, which takes a model and
|
|
7
|
-
# additional arguments.
|
|
8
|
-
# * A module inside the plugin module named InstanceMethods,
|
|
9
|
-
# which will be included in the model class.
|
|
10
|
-
# * A module inside the plugin module named ClassMethods,
|
|
11
|
-
# which will extend the model class.
|
|
12
|
-
# * A module inside the plugin module named DatasetMethods,
|
|
13
|
-
# which will extend the model's dataset.
|
|
14
|
-
module Plugins
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
class Model
|
|
18
|
-
# Loads a plugin for use with the model class, passing optional arguments
|
|
19
|
-
# to the plugin. If the plugin has a DatasetMethods module and the model
|
|
20
|
-
# doesn't have a dataset, raise an Error.
|
|
21
|
-
def self.is(plugin, *args)
|
|
22
|
-
m = plugin_module(plugin)
|
|
23
|
-
raise(Error, "Plugin cannot be applied because the model class has no dataset") if m.const_defined?("DatasetMethods") && !@dataset
|
|
24
|
-
if m.respond_to?(:apply)
|
|
25
|
-
m.apply(self, *args)
|
|
26
|
-
end
|
|
27
|
-
if m.const_defined?("InstanceMethods")
|
|
28
|
-
class_def(:"#{plugin}_opts") {args.first}
|
|
29
|
-
include(m::InstanceMethods)
|
|
30
|
-
end
|
|
31
|
-
if m.const_defined?("ClassMethods")
|
|
32
|
-
meta_def(:"#{plugin}_opts") {args.first}
|
|
33
|
-
extend(m::ClassMethods)
|
|
34
|
-
end
|
|
35
|
-
if m.const_defined?("DatasetMethods")
|
|
36
|
-
dataset.meta_def(:"#{plugin}_opts") {args.first}
|
|
37
|
-
dataset.extend(m::DatasetMethods)
|
|
38
|
-
def_dataset_method(*m::DatasetMethods.public_instance_methods)
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
metaalias :is_a, :is
|
|
42
|
-
|
|
43
|
-
### Private Class Methods ###
|
|
44
|
-
|
|
45
|
-
# Returns the gem name for the given plugin.
|
|
46
|
-
def self.plugin_gem(plugin) # :nodoc:
|
|
47
|
-
"sequel_#{plugin}"
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Returns the module for the specified plugin. If the module is not
|
|
51
|
-
# defined, the corresponding plugin gem is automatically loaded.
|
|
52
|
-
def self.plugin_module(plugin) # :nodoc:
|
|
53
|
-
module_name = plugin.to_s.gsub(/(^|_)(.)/){|x| x[-1..-1].upcase}
|
|
54
|
-
if not Sequel::Plugins.const_defined?(module_name)
|
|
55
|
-
require plugin_gem(plugin)
|
|
56
|
-
end
|
|
57
|
-
Sequel::Plugins.const_get(module_name)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
private_class_method :plugin_gem, :plugin_module
|
|
61
|
-
end
|
|
62
|
-
end
|
data/lib/sequel_model/record.rb
DELETED
|
@@ -1,568 +0,0 @@
|
|
|
1
|
-
module Sequel
|
|
2
|
-
class Model
|
|
3
|
-
# The setter methods (methods ending with =) that are never allowed
|
|
4
|
-
# to be called automatically via set.
|
|
5
|
-
RESTRICTED_SETTER_METHODS = %w"== === []= taguri= typecast_empty_string_to_nil= typecast_on_assignment= strict_param_setting= raise_on_save_failure= raise_on_typecast_failure="
|
|
6
|
-
|
|
7
|
-
# The hash of attribute values. Keys are symbols with the names of the
|
|
8
|
-
# underlying database columns.
|
|
9
|
-
attr_reader :values
|
|
10
|
-
|
|
11
|
-
class_attr_reader :columns, :dataset, :db, :primary_key, :str_columns
|
|
12
|
-
class_attr_overridable :db_schema, :raise_on_save_failure, :raise_on_typecast_failure, :strict_param_setting, :typecast_empty_string_to_nil, :typecast_on_assignment
|
|
13
|
-
remove_method :db_schema=
|
|
14
|
-
|
|
15
|
-
# Creates new instance with values set to passed-in Hash.
|
|
16
|
-
# If a block is given, yield the instance to the block unless
|
|
17
|
-
# from_db is true.
|
|
18
|
-
# This method runs the after_initialize hook after
|
|
19
|
-
# it has optionally yielded itself to the block.
|
|
20
|
-
#
|
|
21
|
-
# Arguments:
|
|
22
|
-
# * values - should be a hash with symbol keys, though
|
|
23
|
-
# string keys will work if from_db is false.
|
|
24
|
-
# * from_db - should only be set by Model.load, forget it
|
|
25
|
-
# exists.
|
|
26
|
-
def initialize(values = {}, from_db = false)
|
|
27
|
-
if from_db
|
|
28
|
-
@new = false
|
|
29
|
-
@values = values
|
|
30
|
-
else
|
|
31
|
-
@values = {}
|
|
32
|
-
@new = true
|
|
33
|
-
set(values)
|
|
34
|
-
changed_columns.clear
|
|
35
|
-
yield self if block_given?
|
|
36
|
-
end
|
|
37
|
-
after_initialize
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# Returns value of the column's attribute.
|
|
41
|
-
def [](column)
|
|
42
|
-
@values[column]
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Sets value of the column's attribute and marks the column as changed.
|
|
46
|
-
# If the column already has the same value, this is a no-op.
|
|
47
|
-
def []=(column, value)
|
|
48
|
-
# If it is new, it doesn't have a value yet, so we should
|
|
49
|
-
# definitely set the new value.
|
|
50
|
-
# If the column isn't in @values, we can't assume it is
|
|
51
|
-
# NULL in the database, so assume it has changed.
|
|
52
|
-
if new? || !@values.include?(column) || value != @values[column]
|
|
53
|
-
changed_columns << column unless changed_columns.include?(column)
|
|
54
|
-
@values[column] = typecast_value(column, value)
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Compares model instances by values.
|
|
59
|
-
def ==(obj)
|
|
60
|
-
(obj.class == model) && (obj.values == @values)
|
|
61
|
-
end
|
|
62
|
-
alias_method :eql?, :"=="
|
|
63
|
-
|
|
64
|
-
# If pk is not nil, true only if the objects have the same class and pk.
|
|
65
|
-
# If pk is nil, false.
|
|
66
|
-
def ===(obj)
|
|
67
|
-
pk.nil? ? false : (obj.class == model) && (obj.pk == pk)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# class is defined in Object, but it is also a keyword,
|
|
71
|
-
# and since a lot of instance methods call class methods,
|
|
72
|
-
# the model makes it so you can use model instead of
|
|
73
|
-
# self.class.
|
|
74
|
-
alias_method :model, :class
|
|
75
|
-
|
|
76
|
-
# The current cached associations. A hash with the keys being the
|
|
77
|
-
# association name symbols and the values being the associated object
|
|
78
|
-
# or nil (many_to_one), or the array of associated objects (*_to_many).
|
|
79
|
-
def associations
|
|
80
|
-
@associations ||= {}
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
# The columns that have been updated. This isn't completely accurate,
|
|
84
|
-
# see Model#[]=.
|
|
85
|
-
def changed_columns
|
|
86
|
-
@changed_columns ||= []
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# Deletes and returns self. Does not run destroy hooks.
|
|
90
|
-
# Look into using destroy instead.
|
|
91
|
-
def delete
|
|
92
|
-
before_delete
|
|
93
|
-
this.delete
|
|
94
|
-
self
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
# Like delete but runs hooks before and after delete.
|
|
98
|
-
# If before_destroy returns false, returns false without
|
|
99
|
-
# deleting the object the the database. Otherwise, deletes
|
|
100
|
-
# the item from the database and returns self.
|
|
101
|
-
def destroy
|
|
102
|
-
db.transaction do
|
|
103
|
-
return save_failure(:destroy) if before_destroy == false
|
|
104
|
-
delete
|
|
105
|
-
after_destroy
|
|
106
|
-
end
|
|
107
|
-
self
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
# Enumerates through all attributes.
|
|
111
|
-
#
|
|
112
|
-
# Example:
|
|
113
|
-
# Ticket.find(7).each { |k, v| puts "#{k} => #{v}" }
|
|
114
|
-
def each(&block)
|
|
115
|
-
@values.each(&block)
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
# Returns true when current instance exists, false otherwise.
|
|
119
|
-
def exists?
|
|
120
|
-
this.count > 0
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
# Unique for objects with the same class and pk (if pk is not nil), or
|
|
124
|
-
# the same class and values (if pk is nil).
|
|
125
|
-
def hash
|
|
126
|
-
[model, pk.nil? ? @values.sort_by{|k,v| k.to_s} : pk].hash
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
# Returns value for the :id attribute, even if the primary key is
|
|
130
|
-
# not id. To get the primary key value, use #pk.
|
|
131
|
-
def id
|
|
132
|
-
@values[:id]
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
# Returns a string representation of the model instance including
|
|
136
|
-
# the class name and values.
|
|
137
|
-
def inspect
|
|
138
|
-
"#<#{model.name} @values=#{inspect_values}>"
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
# Returns attribute names as an array of symbols.
|
|
142
|
-
def keys
|
|
143
|
-
@values.keys
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
# Returns true if the current instance represents a new record.
|
|
147
|
-
def new?
|
|
148
|
-
@new
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
# Returns the primary key value identifying the model instance.
|
|
152
|
-
# Raises an error if this model does not have a primary key.
|
|
153
|
-
# If the model has a composite primary key, returns an array of values.
|
|
154
|
-
def pk
|
|
155
|
-
raise(Error, "No primary key is associated with this model") unless key = primary_key
|
|
156
|
-
case key
|
|
157
|
-
when Array
|
|
158
|
-
key.collect{|k| @values[k]}
|
|
159
|
-
else
|
|
160
|
-
@values[key]
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
# Returns a hash identifying the model instance. It should be true that:
|
|
165
|
-
#
|
|
166
|
-
# Model[model_instance.pk_hash] === model_instance
|
|
167
|
-
def pk_hash
|
|
168
|
-
model.primary_key_hash(pk)
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
# Reloads attributes from database and returns self. Also clears all
|
|
172
|
-
# cached association information. Raises an Error if the record no longer
|
|
173
|
-
# exists in the database.
|
|
174
|
-
def refresh
|
|
175
|
-
@values = this.first || raise(Error, "Record not found")
|
|
176
|
-
changed_columns.clear
|
|
177
|
-
associations.clear
|
|
178
|
-
self
|
|
179
|
-
end
|
|
180
|
-
alias_method :reload, :refresh
|
|
181
|
-
|
|
182
|
-
# Creates or updates the record, after making sure the record
|
|
183
|
-
# is valid. If the record is not valid, or before_save,
|
|
184
|
-
# before_create (if new?), or before_update (if !new?) return
|
|
185
|
-
# false, returns nil unless raise_on_save_failure is true (if it
|
|
186
|
-
# is true, it raises an error).
|
|
187
|
-
# Otherwise, returns self. You can provide an optional list of
|
|
188
|
-
# columns to update, in which case it only updates those columns.
|
|
189
|
-
def save(*columns)
|
|
190
|
-
valid? ? save!(*columns) : save_failure(:invalid)
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
# Creates or updates the record, without attempting to validate
|
|
194
|
-
# it first. You can provide an optional list of columns to update,
|
|
195
|
-
# in which case it only updates those columns.
|
|
196
|
-
# If before_save, before_create (if new?), or before_update
|
|
197
|
-
# (if !new?) return false, returns nil unless raise_on_save_failure
|
|
198
|
-
# is true (if it is true, it raises an error). Otherwise, returns self.
|
|
199
|
-
def save!(*columns)
|
|
200
|
-
opts = columns.extract_options!
|
|
201
|
-
return save_failure(:save) if before_save == false
|
|
202
|
-
if new?
|
|
203
|
-
return save_failure(:create) if before_create == false
|
|
204
|
-
ds = model.dataset
|
|
205
|
-
if ds.respond_to?(:insert_select) and h = ds.insert_select(@values)
|
|
206
|
-
@values = h
|
|
207
|
-
@this = nil
|
|
208
|
-
else
|
|
209
|
-
iid = ds.insert(@values)
|
|
210
|
-
# if we have a regular primary key and it's not set in @values,
|
|
211
|
-
# we assume it's the last inserted id
|
|
212
|
-
if (pk = primary_key) && !(Array === pk) && !@values[pk]
|
|
213
|
-
@values[pk] = iid
|
|
214
|
-
end
|
|
215
|
-
@this = nil if pk
|
|
216
|
-
end
|
|
217
|
-
after_create
|
|
218
|
-
after_save
|
|
219
|
-
@new = false
|
|
220
|
-
refresh if pk
|
|
221
|
-
else
|
|
222
|
-
return save_failure(:update) if before_update == false
|
|
223
|
-
if columns.empty?
|
|
224
|
-
vals = opts[:changed] ? @values.reject{|k,v| !changed_columns.include?(k)} : @values
|
|
225
|
-
this.update(vals)
|
|
226
|
-
else # update only the specified columns
|
|
227
|
-
this.update(@values.reject{|k, v| !columns.include?(k)})
|
|
228
|
-
end
|
|
229
|
-
after_update
|
|
230
|
-
after_save
|
|
231
|
-
if columns.empty?
|
|
232
|
-
changed_columns.clear
|
|
233
|
-
else
|
|
234
|
-
changed_columns.reject!{|c| columns.include?(c)}
|
|
235
|
-
end
|
|
236
|
-
end
|
|
237
|
-
self
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
# Saves only changed columns or does nothing if no columns are marked as
|
|
241
|
-
# chanaged. If no columns have been changed, returns nil. If unable to
|
|
242
|
-
# save, returns false unless raise_on_save_failure is true.
|
|
243
|
-
def save_changes
|
|
244
|
-
save(:changed=>true) || false unless changed_columns.empty?
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
# Updates the instance with the supplied values with support for virtual
|
|
248
|
-
# attributes, raising an exception if a value is used that doesn't have
|
|
249
|
-
# a setter method (or ignoring it if strict_param_setting = false).
|
|
250
|
-
# Does not save the record.
|
|
251
|
-
#
|
|
252
|
-
# If no columns have been set for this model (very unlikely), assume symbol
|
|
253
|
-
# keys are valid column names, and assign the column value based on that.
|
|
254
|
-
def set(hash)
|
|
255
|
-
set_restricted(hash, nil, nil)
|
|
256
|
-
end
|
|
257
|
-
alias_method :set_with_params, :set
|
|
258
|
-
|
|
259
|
-
# Set all values using the entries in the hash, ignoring any setting of
|
|
260
|
-
# allowed_columns or restricted columns in the model.
|
|
261
|
-
def set_all(hash)
|
|
262
|
-
set_restricted(hash, false, false)
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
# Set all values using the entries in the hash, except for the keys
|
|
266
|
-
# given in except.
|
|
267
|
-
def set_except(hash, *except)
|
|
268
|
-
set_restricted(hash, false, except.flatten)
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
# Set the values using the entries in the hash, only if the key
|
|
272
|
-
# is included in only.
|
|
273
|
-
def set_only(hash, *only)
|
|
274
|
-
set_restricted(hash, only.flatten, false)
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
# Sets the value attributes without saving the record. Returns
|
|
278
|
-
# the values changed. Raises an error if the keys are not symbols
|
|
279
|
-
# or strings or a string key was passed that was not a valid column.
|
|
280
|
-
# This is a low level method that does not respect virtual attributes. It
|
|
281
|
-
# should probably be avoided. Look into using set instead.
|
|
282
|
-
def set_values(values)
|
|
283
|
-
s = str_columns
|
|
284
|
-
vals = values.inject({}) do |m, kv|
|
|
285
|
-
k, v = kv
|
|
286
|
-
k = case k
|
|
287
|
-
when Symbol
|
|
288
|
-
k
|
|
289
|
-
when String
|
|
290
|
-
# Prevent denial of service via memory exhaustion by only
|
|
291
|
-
# calling to_sym if the symbol already exists.
|
|
292
|
-
raise(Error, "all string keys must be a valid columns") unless s.include?(k)
|
|
293
|
-
k.to_sym
|
|
294
|
-
else
|
|
295
|
-
raise(Error, "Only symbols and strings allows as keys")
|
|
296
|
-
end
|
|
297
|
-
m[k] = v
|
|
298
|
-
m
|
|
299
|
-
end
|
|
300
|
-
vals.each {|k, v| @values[k] = v}
|
|
301
|
-
vals
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
# Returns (naked) dataset that should return only this instance.
|
|
305
|
-
def this
|
|
306
|
-
@this ||= dataset.filter(pk_hash).limit(1).naked
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
# Runs set with the passed hash and runs save_changes (which runs any callback methods).
|
|
310
|
-
def update(hash)
|
|
311
|
-
update_restricted(hash, nil, nil)
|
|
312
|
-
end
|
|
313
|
-
alias_method :update_with_params, :update
|
|
314
|
-
|
|
315
|
-
# Update all values using the entries in the hash, ignoring any setting of
|
|
316
|
-
# allowed_columns or restricted columns in the model.
|
|
317
|
-
def update_all(hash)
|
|
318
|
-
update_restricted(hash, false, false)
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
# Update all values using the entries in the hash, except for the keys
|
|
322
|
-
# given in except.
|
|
323
|
-
def update_except(hash, *except)
|
|
324
|
-
update_restricted(hash, false, except.flatten)
|
|
325
|
-
end
|
|
326
|
-
|
|
327
|
-
# Update the values using the entries in the hash, only if the key
|
|
328
|
-
# is included in only.
|
|
329
|
-
def update_only(hash, *only)
|
|
330
|
-
update_restricted(hash, only.flatten, false)
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
# Sets the values attributes with set_values and then updates
|
|
334
|
-
# the record in the database using those values. This is a
|
|
335
|
-
# low level method that does not run the usual save callbacks.
|
|
336
|
-
# It should probably be avoided. Look into using update_with_params instead.
|
|
337
|
-
def update_values(values)
|
|
338
|
-
before_update_values
|
|
339
|
-
this.update(set_values(values))
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
private
|
|
343
|
-
|
|
344
|
-
# Backbone behind association_dataset
|
|
345
|
-
def _dataset(opts)
|
|
346
|
-
raise(Sequel::Error, "model object #{model} does not have a primary key") if opts.dataset_need_primary_key? && !pk
|
|
347
|
-
ds = send(opts._dataset_method)
|
|
348
|
-
ds.extend(Associations::DatasetMethods)
|
|
349
|
-
ds.model_object = self
|
|
350
|
-
ds.association_reflection = opts
|
|
351
|
-
opts[:extend].each{|m| ds.extend(m)}
|
|
352
|
-
ds = ds.select(*opts.select) if opts.select
|
|
353
|
-
ds = ds.filter(opts[:conditions]) if opts[:conditions]
|
|
354
|
-
ds = ds.order(*opts[:order]) if opts[:order]
|
|
355
|
-
ds = ds.limit(*opts[:limit]) if opts[:limit]
|
|
356
|
-
ds = ds.eager(*opts[:eager]) if opts[:eager]
|
|
357
|
-
ds = ds.eager_graph(opts[:eager_graph]) if opts[:eager_graph] && opts.eager_graph_lazy_dataset?
|
|
358
|
-
ds = send(opts.dataset_helper_method, ds) if opts[:block]
|
|
359
|
-
ds
|
|
360
|
-
end
|
|
361
|
-
|
|
362
|
-
# Add the given associated object to the given association
|
|
363
|
-
def add_associated_object(opts, o)
|
|
364
|
-
raise(Sequel::Error, "model object #{model} does not have a primary key") unless pk
|
|
365
|
-
raise(Sequel::Error, "associated object #{o.model} does not have a primary key") if opts.need_associated_primary_key? && !o.pk
|
|
366
|
-
return if run_association_callbacks(opts, :before_add, o) == false
|
|
367
|
-
send(opts._add_method, o)
|
|
368
|
-
associations[opts[:name]].push(o) if associations.include?(opts[:name])
|
|
369
|
-
add_reciprocal_object(opts, o)
|
|
370
|
-
run_association_callbacks(opts, :after_add, o)
|
|
371
|
-
o
|
|
372
|
-
end
|
|
373
|
-
|
|
374
|
-
# Add/Set the current object to/as the given object's reciprocal association.
|
|
375
|
-
def add_reciprocal_object(opts, o)
|
|
376
|
-
return unless reciprocal = opts.reciprocal
|
|
377
|
-
if opts.reciprocal_array?
|
|
378
|
-
if array = o.associations[reciprocal] and !array.include?(self)
|
|
379
|
-
array.push(self)
|
|
380
|
-
end
|
|
381
|
-
else
|
|
382
|
-
o.associations[reciprocal] = self
|
|
383
|
-
end
|
|
384
|
-
end
|
|
385
|
-
|
|
386
|
-
# Default inspection output for a record, overwrite to change the way #inspect prints the @values hash
|
|
387
|
-
def inspect_values
|
|
388
|
-
@values.inspect
|
|
389
|
-
end
|
|
390
|
-
|
|
391
|
-
# Load the associated objects using the dataset
|
|
392
|
-
def load_associated_objects(opts, reload=false)
|
|
393
|
-
name = opts[:name]
|
|
394
|
-
if associations.include?(name) and !reload
|
|
395
|
-
associations[name]
|
|
396
|
-
else
|
|
397
|
-
objs = if opts.returns_array?
|
|
398
|
-
send(opts.dataset_method).all
|
|
399
|
-
else
|
|
400
|
-
if !opts[:key]
|
|
401
|
-
send(opts.dataset_method).all.first
|
|
402
|
-
elsif send(opts[:key])
|
|
403
|
-
send(opts.dataset_method).first
|
|
404
|
-
end
|
|
405
|
-
end
|
|
406
|
-
run_association_callbacks(opts, :after_load, objs)
|
|
407
|
-
# Only one_to_many associations should set the reciprocal object
|
|
408
|
-
objs.each{|o| add_reciprocal_object(opts, o)} if opts.set_reciprocal_to_self?
|
|
409
|
-
associations[name] = objs
|
|
410
|
-
end
|
|
411
|
-
end
|
|
412
|
-
|
|
413
|
-
# Remove all associated objects from the given association
|
|
414
|
-
def remove_all_associated_objects(opts)
|
|
415
|
-
raise(Sequel::Error, "model object #{model} does not have a primary key") unless pk
|
|
416
|
-
send(opts._remove_all_method)
|
|
417
|
-
ret = associations[opts[:name]].each{|o| remove_reciprocal_object(opts, o)} if associations.include?(opts[:name])
|
|
418
|
-
associations[opts[:name]] = []
|
|
419
|
-
ret
|
|
420
|
-
end
|
|
421
|
-
|
|
422
|
-
# Remove the given associated object from the given association
|
|
423
|
-
def remove_associated_object(opts, o)
|
|
424
|
-
raise(Sequel::Error, "model object #{model} does not have a primary key") unless pk
|
|
425
|
-
raise(Sequel::Error, "associated object #{o.model} does not have a primary key") if opts.need_associated_primary_key? && !o.pk
|
|
426
|
-
return if run_association_callbacks(opts, :before_remove, o) == false
|
|
427
|
-
send(opts._remove_method, o)
|
|
428
|
-
associations[opts[:name]].delete_if{|x| o === x} if associations.include?(opts[:name])
|
|
429
|
-
remove_reciprocal_object(opts, o)
|
|
430
|
-
run_association_callbacks(opts, :after_remove, o)
|
|
431
|
-
o
|
|
432
|
-
end
|
|
433
|
-
|
|
434
|
-
# Remove/unset the current object from/as the given object's reciprocal association.
|
|
435
|
-
def remove_reciprocal_object(opts, o)
|
|
436
|
-
return unless reciprocal = opts.reciprocal
|
|
437
|
-
if opts.reciprocal_array?
|
|
438
|
-
if array = o.associations[reciprocal]
|
|
439
|
-
array.delete_if{|x| self === x}
|
|
440
|
-
end
|
|
441
|
-
else
|
|
442
|
-
o.associations[reciprocal] = nil
|
|
443
|
-
end
|
|
444
|
-
end
|
|
445
|
-
|
|
446
|
-
# Run the callback for the association with the object.
|
|
447
|
-
def run_association_callbacks(reflection, callback_type, object)
|
|
448
|
-
raise_error = raise_on_save_failure || !reflection.returns_array?
|
|
449
|
-
stop_on_false = [:before_add, :before_remove].include?(callback_type)
|
|
450
|
-
reflection[callback_type].each do |cb|
|
|
451
|
-
res = case cb
|
|
452
|
-
when Symbol
|
|
453
|
-
send(cb, object)
|
|
454
|
-
when Proc
|
|
455
|
-
cb.call(self, object)
|
|
456
|
-
else
|
|
457
|
-
raise Error, "callbacks should either be Procs or Symbols"
|
|
458
|
-
end
|
|
459
|
-
if res == false and stop_on_false
|
|
460
|
-
raise(BeforeHookFailed, "Unable to modify association for record: one of the #{callback_type} hooks returned false") if raise_error
|
|
461
|
-
return false
|
|
462
|
-
end
|
|
463
|
-
end
|
|
464
|
-
end
|
|
465
|
-
|
|
466
|
-
# Raise an error if raise_on_save_failure is true
|
|
467
|
-
def save_failure(type)
|
|
468
|
-
if raise_on_save_failure
|
|
469
|
-
if type == :invalid
|
|
470
|
-
raise ValidationFailed, errors.full_messages.join(', ')
|
|
471
|
-
else
|
|
472
|
-
raise BeforeHookFailed, "one of the before_#{type} hooks returned false"
|
|
473
|
-
end
|
|
474
|
-
end
|
|
475
|
-
end
|
|
476
|
-
|
|
477
|
-
# Set the given object as the associated object for the given association
|
|
478
|
-
def set_associated_object(opts, o)
|
|
479
|
-
raise(Sequel::Error, "model object #{model} does not have a primary key") if o && !o.pk
|
|
480
|
-
old_val = send(opts.association_method)
|
|
481
|
-
return o if old_val == o
|
|
482
|
-
return if old_val and run_association_callbacks(opts, :before_remove, old_val) == false
|
|
483
|
-
return if o and run_association_callbacks(opts, :before_add, o) == false
|
|
484
|
-
send(opts._setter_method, o)
|
|
485
|
-
associations[opts[:name]] = o
|
|
486
|
-
remove_reciprocal_object(opts, old_val) if old_val
|
|
487
|
-
if o
|
|
488
|
-
add_reciprocal_object(opts, o)
|
|
489
|
-
run_association_callbacks(opts, :after_add, o)
|
|
490
|
-
end
|
|
491
|
-
run_association_callbacks(opts, :after_remove, old_val) if old_val
|
|
492
|
-
o
|
|
493
|
-
end
|
|
494
|
-
|
|
495
|
-
# Set the columns, filtered by the only and except arrays.
|
|
496
|
-
def set_restricted(hash, only, except)
|
|
497
|
-
columns_not_set = model.instance_variable_get(:@columns).blank?
|
|
498
|
-
meths = setter_methods(only, except)
|
|
499
|
-
strict = strict_param_setting
|
|
500
|
-
hash.each do |k,v|
|
|
501
|
-
m = "#{k}="
|
|
502
|
-
if meths.include?(m)
|
|
503
|
-
send(m, v)
|
|
504
|
-
elsif columns_not_set && (Symbol === k)
|
|
505
|
-
self[k] = v
|
|
506
|
-
elsif strict
|
|
507
|
-
raise Error, "method #{m} doesn't exist or access is restricted to it"
|
|
508
|
-
end
|
|
509
|
-
end
|
|
510
|
-
self
|
|
511
|
-
end
|
|
512
|
-
|
|
513
|
-
# Returns all methods that can be used for attribute
|
|
514
|
-
# assignment (those that end with =), modified by the only
|
|
515
|
-
# and except arguments:
|
|
516
|
-
#
|
|
517
|
-
# * only
|
|
518
|
-
# * false - Don't modify the results
|
|
519
|
-
# * nil - if the model has allowed_columns, use only these, otherwise, don't modify
|
|
520
|
-
# * Array - allow only the given methods to be used
|
|
521
|
-
# * except
|
|
522
|
-
# * false - Don't modify the results
|
|
523
|
-
# * nil - if the model has restricted_columns, remove these, otherwise, don't modify
|
|
524
|
-
# * Array - remove the given methods
|
|
525
|
-
#
|
|
526
|
-
# only takes precedence over except, and if only is not used, certain methods are always
|
|
527
|
-
# restricted (RESTRICTED_SETTER_METHODS). The primary key is restricted by default as
|
|
528
|
-
# well, see Model.unrestrict_primary_key to change this.
|
|
529
|
-
def setter_methods(only, except)
|
|
530
|
-
only = only.nil? ? model.allowed_columns : only
|
|
531
|
-
except = except.nil? ? model.restricted_columns : except
|
|
532
|
-
if only
|
|
533
|
-
only.map{|x| "#{x}="}
|
|
534
|
-
else
|
|
535
|
-
meths = methods.collect{|x| x.to_s}.grep(/=\z/) - RESTRICTED_SETTER_METHODS
|
|
536
|
-
meths -= Array(primary_key).map{|x| "#{x}="} if primary_key && model.restrict_primary_key?
|
|
537
|
-
meths -= except.map{|x| "#{x}="} if except
|
|
538
|
-
meths
|
|
539
|
-
end
|
|
540
|
-
end
|
|
541
|
-
|
|
542
|
-
# Typecast the value to the column's type if typecasting. Calls the database's
|
|
543
|
-
# typecast_value method, so database adapters can override/augment the handling
|
|
544
|
-
# for database specific column types.
|
|
545
|
-
def typecast_value(column, value)
|
|
546
|
-
return value unless typecast_on_assignment && db_schema && (col_schema = db_schema[column]) && !model.serialized?(column)
|
|
547
|
-
value = nil if value == '' and typecast_empty_string_to_nil and col_schema[:type] and ![:string, :blob].include?(col_schema[:type])
|
|
548
|
-
raise(Error::InvalidValue, "nil/NULL is not allowed for the #{column} column") if raise_on_typecast_failure && value.nil? && (col_schema[:allow_null] == false)
|
|
549
|
-
begin
|
|
550
|
-
model.db.typecast_value(col_schema[:type], value)
|
|
551
|
-
rescue Error::InvalidValue
|
|
552
|
-
raise_on_typecast_failure ? raise : value
|
|
553
|
-
end
|
|
554
|
-
end
|
|
555
|
-
|
|
556
|
-
# Call uniq! on the given array. This is used by the :uniq option,
|
|
557
|
-
# and is an actual method for memory reasons.
|
|
558
|
-
def array_uniq!(a)
|
|
559
|
-
a.uniq!
|
|
560
|
-
end
|
|
561
|
-
|
|
562
|
-
# Set the columns, filtered by the only and except arrays.
|
|
563
|
-
def update_restricted(hash, only, except)
|
|
564
|
-
set_restricted(hash, only, except)
|
|
565
|
-
save_changes
|
|
566
|
-
end
|
|
567
|
-
end
|
|
568
|
-
end
|