sequel 1.5.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +30 -0
- data/README +12 -15
- data/Rakefile +9 -20
- data/lib/sequel_model.rb +47 -72
- data/lib/sequel_model/association_reflection.rb +59 -0
- data/lib/sequel_model/associations.rb +99 -94
- data/lib/sequel_model/base.rb +308 -102
- data/lib/sequel_model/caching.rb +72 -27
- data/lib/sequel_model/eager_loading.rb +308 -300
- data/lib/sequel_model/hooks.rb +51 -49
- data/lib/sequel_model/inflector.rb +186 -182
- data/lib/sequel_model/plugins.rb +54 -40
- data/lib/sequel_model/record.rb +185 -220
- data/lib/sequel_model/schema.rb +27 -34
- data/lib/sequel_model/validations.rb +54 -73
- data/spec/association_reflection_spec.rb +85 -0
- data/spec/associations_spec.rb +160 -73
- data/spec/base_spec.rb +3 -3
- data/spec/eager_loading_spec.rb +132 -35
- data/spec/hooks_spec.rb +120 -20
- data/spec/inflector_spec.rb +2 -2
- data/spec/model_spec.rb +110 -78
- data/spec/plugins_spec.rb +4 -0
- data/spec/rcov.opts +1 -1
- data/spec/record_spec.rb +160 -59
- data/spec/spec.opts +0 -5
- data/spec/spec_helper.rb +12 -0
- data/spec/validations_spec.rb +23 -0
- metadata +60 -50
- data/lib/sequel_model/deprecated.rb +0 -81
- data/lib/sequel_model/inflections.rb +0 -112
- data/spec/deprecated_relations_spec.rb +0 -113
data/lib/sequel_model/plugins.rb
CHANGED
@@ -1,48 +1,62 @@
|
|
1
1
|
module Sequel
|
2
|
-
|
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
|
3
16
|
|
4
17
|
class Model
|
5
|
-
class
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
dataset.metaclass.send(:include, m::DatasetMethods)
|
27
|
-
end
|
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.metaclass.send(:include, m::DatasetMethods)
|
38
|
+
def_dataset_method(*m::DatasetMethods.instance_methods)
|
28
39
|
end
|
29
|
-
|
30
|
-
|
31
|
-
private
|
32
|
-
# Returns the module for the specified plugin. If the module is not
|
33
|
-
# defined, the corresponding plugin gem is automatically loaded.
|
34
|
-
def plugin_module(plugin)
|
35
|
-
module_name = plugin.to_s.gsub(/(^|_)(.)/) {$2.upcase}
|
36
|
-
if not Sequel::Plugins.const_defined?(module_name)
|
37
|
-
require plugin_gem(plugin)
|
38
|
-
end
|
39
|
-
Sequel::Plugins.const_get(module_name)
|
40
|
-
end
|
40
|
+
end
|
41
|
+
metaalias :is_a, :is
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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)
|
46
58
|
end
|
59
|
+
|
60
|
+
metaprivate :plugin_gem, :plugin_module
|
47
61
|
end
|
48
62
|
end
|
data/lib/sequel_model/record.rb
CHANGED
@@ -1,13 +1,56 @@
|
|
1
|
+
# This file holds general instance methods for Sequel::Model
|
2
|
+
|
1
3
|
module Sequel
|
2
4
|
class Model
|
3
|
-
|
5
|
+
# The columns that have been updated. This isn't completely accurate,
|
6
|
+
# see Model#[]=.
|
4
7
|
attr_reader :changed_columns
|
5
8
|
|
6
|
-
#
|
9
|
+
# The hash of attribute values. Keys are symbols with the names of the
|
10
|
+
# underlying database columns.
|
11
|
+
attr_reader :values
|
12
|
+
|
13
|
+
# Whether this model instance should typecast on attribute assignment
|
14
|
+
attr_writer :typecast_on_assignment
|
15
|
+
|
16
|
+
class_attr_reader :columns, :dataset, :db, :primary_key, :str_columns
|
17
|
+
|
18
|
+
# Creates new instance with values set to passed-in Hash.
|
19
|
+
# If a block is given, yield the instance to the block.
|
20
|
+
# This method runs the after_initialize hook after
|
21
|
+
# it has optionally yielded itself to the block.
|
22
|
+
#
|
23
|
+
# Arguments:
|
24
|
+
# * values - should be a hash with symbol keys, though
|
25
|
+
# string keys will work if from_db is false.
|
26
|
+
# * from_db - should only be set by Model.load, forget it
|
27
|
+
# exists.
|
28
|
+
def initialize(values = nil, from_db = false, &block)
|
29
|
+
values ||= {}
|
30
|
+
@changed_columns = []
|
31
|
+
@typecast_on_assignment = model.typecast_on_assignment
|
32
|
+
@db_schema = model.db_schema
|
33
|
+
if from_db
|
34
|
+
@new = false
|
35
|
+
@values = values
|
36
|
+
else
|
37
|
+
@values = {}
|
38
|
+
@new = true
|
39
|
+
set_with_params(values)
|
40
|
+
end
|
41
|
+
@changed_columns.clear
|
42
|
+
|
43
|
+
yield self if block
|
44
|
+
after_initialize
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns value of the column's attribute.
|
7
48
|
def [](column)
|
8
49
|
@values[column]
|
9
50
|
end
|
10
|
-
|
51
|
+
|
52
|
+
# Sets value of the column's attribute and marks the column as changed.
|
53
|
+
# If the column already has the same value, this is a no-op.
|
11
54
|
def []=(column, value)
|
12
55
|
# If it is new, it doesn't have a value yet, so we should
|
13
56
|
# definitely set the new value.
|
@@ -15,27 +58,10 @@ module Sequel
|
|
15
58
|
# NULL in the database, so assume it has changed.
|
16
59
|
if new? || !@values.include?(column) || value != @values[column]
|
17
60
|
@changed_columns << column unless @changed_columns.include?(column)
|
18
|
-
@values[column] = value
|
61
|
+
@values[column] = typecast_value(column, value)
|
19
62
|
end
|
20
63
|
end
|
21
64
|
|
22
|
-
# Enumerates through all attributes.
|
23
|
-
#
|
24
|
-
# === Example:
|
25
|
-
# Ticket.find(7).each { |k, v| puts "#{k} => #{v}" }
|
26
|
-
def each(&block)
|
27
|
-
@values.each(&block)
|
28
|
-
end
|
29
|
-
# Returns attribute names.
|
30
|
-
def keys
|
31
|
-
@values.keys
|
32
|
-
end
|
33
|
-
|
34
|
-
# Returns value for <tt>:id</tt> attribute.
|
35
|
-
def id
|
36
|
-
@values[:id]
|
37
|
-
end
|
38
|
-
|
39
65
|
# Compares model instances by values.
|
40
66
|
def ==(obj)
|
41
67
|
(obj.class == model) && (obj.values == @values)
|
@@ -48,201 +74,126 @@ module Sequel
|
|
48
74
|
pk.nil? ? false : (obj.class == model) && (obj.pk == pk)
|
49
75
|
end
|
50
76
|
|
51
|
-
#
|
52
|
-
#
|
53
|
-
|
54
|
-
|
55
|
-
|
77
|
+
# class is defined in Object, but it is also a keyword,
|
78
|
+
# and since a lot of instance methods call class methods,
|
79
|
+
# the model makes it so you can use model instead of
|
80
|
+
# self.class.
|
81
|
+
alias_method :model, :class
|
56
82
|
|
57
|
-
#
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
def self.primary_key_hash(value)
|
64
|
-
{:id => value}
|
83
|
+
# Deletes and returns self. Does not run destroy hooks.
|
84
|
+
# Look into using destroy instead.
|
85
|
+
def delete
|
86
|
+
before_delete
|
87
|
+
this.delete
|
88
|
+
self
|
65
89
|
end
|
66
90
|
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
# # regular key
|
77
|
-
# set_primary_key :person_id
|
78
|
-
# end
|
79
|
-
#
|
80
|
-
# <i>You can even set it to nil!</i>
|
81
|
-
def self.set_primary_key(*key)
|
82
|
-
# if k is nil, we go to no_primary_key
|
83
|
-
if key.empty? || (key.size == 1 && key.first == nil)
|
84
|
-
return no_primary_key
|
85
|
-
end
|
86
|
-
|
87
|
-
# backwards compat
|
88
|
-
key = (key.length == 1) ? key[0] : key.flatten
|
89
|
-
|
90
|
-
# redefine primary_key
|
91
|
-
meta_def(:primary_key) {key}
|
92
|
-
|
93
|
-
unless key.is_a? Array # regular primary key
|
94
|
-
class_def(:this) do
|
95
|
-
@this ||= dataset.filter(key => @values[key]).limit(1).naked
|
96
|
-
end
|
97
|
-
class_def(:pk) do
|
98
|
-
@pk ||= @values[key]
|
99
|
-
end
|
100
|
-
class_def(:pk_hash) do
|
101
|
-
@pk ||= {key => @values[key]}
|
102
|
-
end
|
103
|
-
class_def(:cache_key) do
|
104
|
-
pk = @values[key] || (raise Error, 'no primary key for this record')
|
105
|
-
@cache_key ||= "#{self.class}:#{pk}"
|
106
|
-
end
|
107
|
-
meta_def(:primary_key_hash) do |v|
|
108
|
-
{key => v}
|
109
|
-
end
|
110
|
-
else # composite key
|
111
|
-
exp_list = key.map {|k| "#{k.inspect} => @values[#{k.inspect}]"}
|
112
|
-
block = eval("proc {@this ||= self.class.dataset.filter(#{exp_list.join(',')}).limit(1).naked}")
|
113
|
-
class_def(:this, &block)
|
114
|
-
|
115
|
-
exp_list = key.map {|k| "@values[#{k.inspect}]"}
|
116
|
-
block = eval("proc {@pk ||= [#{exp_list.join(',')}]}")
|
117
|
-
class_def(:pk, &block)
|
118
|
-
|
119
|
-
exp_list = key.map {|k| "#{k.inspect} => @values[#{k.inspect}]"}
|
120
|
-
block = eval("proc {@this ||= {#{exp_list.join(',')}}}")
|
121
|
-
class_def(:pk_hash, &block)
|
122
|
-
|
123
|
-
exp_list = key.map {|k| '#{@values[%s]}' % k.inspect}.join(',')
|
124
|
-
block = eval('proc {@cache_key ||= "#{self.class}:%s"}' % exp_list)
|
125
|
-
class_def(:cache_key, &block)
|
126
|
-
|
127
|
-
meta_def(:primary_key_hash) do |v|
|
128
|
-
key.inject({}) {|m, i| m[i] = v.shift; m}
|
129
|
-
end
|
91
|
+
# Like delete but runs hooks before and after delete.
|
92
|
+
# If before_destroy returns false, returns false without
|
93
|
+
# deleting the object the the database. Otherwise, deletes
|
94
|
+
# the item from the database and returns self.
|
95
|
+
def destroy
|
96
|
+
db.transaction do
|
97
|
+
return false if before_destroy == false
|
98
|
+
delete
|
99
|
+
after_destroy
|
130
100
|
end
|
101
|
+
self
|
131
102
|
end
|
132
103
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
class_def(:cache_key) {raise Error, "No primary key is associated with this model"}
|
104
|
+
# Enumerates through all attributes.
|
105
|
+
#
|
106
|
+
# Example:
|
107
|
+
# Ticket.find(7).each { |k, v| puts "#{k} => #{v}" }
|
108
|
+
def each(&block)
|
109
|
+
@values.each(&block)
|
140
110
|
end
|
141
|
-
|
142
|
-
#
|
143
|
-
|
144
|
-
|
145
|
-
obj = new(values, &block)
|
146
|
-
obj.save
|
147
|
-
obj
|
111
|
+
|
112
|
+
# Returns true when current instance exists, false otherwise.
|
113
|
+
def exists?
|
114
|
+
this.count > 0
|
148
115
|
end
|
149
116
|
|
150
|
-
#
|
151
|
-
#
|
152
|
-
|
153
|
-
|
154
|
-
# If no columns have been set for this model (very unlikely), assume symbol
|
155
|
-
# keys are valid column names, and assign the column value based on that.
|
156
|
-
def set_with_params(hash)
|
157
|
-
columns_not_set = !model.instance_variable_get(:@columns)
|
158
|
-
meths = setter_methods
|
159
|
-
hash.each do |k,v|
|
160
|
-
m = "#{k}="
|
161
|
-
if meths.include?(m)
|
162
|
-
send(m, v)
|
163
|
-
elsif columns_not_set && (Symbol === k)
|
164
|
-
self[k] = v
|
165
|
-
end
|
166
|
-
end
|
117
|
+
# Unique for objects with the same class and pk (if pk is not nil), or
|
118
|
+
# the same class and values (if pk is nil).
|
119
|
+
def hash
|
120
|
+
[model, pk.nil? ? @values.sort_by{|k,v| k.to_s} : pk].hash
|
167
121
|
end
|
168
122
|
|
169
|
-
#
|
170
|
-
|
171
|
-
|
172
|
-
|
123
|
+
# Returns value for the :id attribute, even if the primary key is
|
124
|
+
# not id. To get the primary key value, use #pk.
|
125
|
+
def id
|
126
|
+
@values[:id]
|
173
127
|
end
|
174
128
|
|
175
|
-
# Returns
|
176
|
-
|
177
|
-
|
129
|
+
# Returns a string representation of the model instance including
|
130
|
+
# the class name and values.
|
131
|
+
def inspect
|
132
|
+
"#<#{model.name} @values=#{@values.inspect}>"
|
178
133
|
end
|
179
|
-
|
180
|
-
# Returns
|
181
|
-
def
|
182
|
-
|
183
|
-
@cache_key ||= "#{self.class}:#{pk}"
|
134
|
+
|
135
|
+
# Returns attribute names as an array of symbols.
|
136
|
+
def keys
|
137
|
+
@values.keys
|
184
138
|
end
|
185
139
|
|
186
|
-
# Returns
|
187
|
-
def
|
188
|
-
@
|
140
|
+
# Returns true if the current instance represents a new record.
|
141
|
+
def new?
|
142
|
+
@new
|
189
143
|
end
|
190
144
|
|
191
|
-
# Returns the primary key value identifying the model instance.
|
192
|
-
#
|
193
|
-
#
|
145
|
+
# Returns the primary key value identifying the model instance.
|
146
|
+
# Raises an error if this model does not have a primary key.
|
147
|
+
# If the model has a composite primary key, returns an array of values.
|
194
148
|
def pk
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
def pk_hash
|
200
|
-
@pk_hash ||= {:id => @values[:id]}
|
201
|
-
end
|
202
|
-
|
203
|
-
# Creates new instance with values set to passed-in Hash.
|
204
|
-
#
|
205
|
-
# This method guesses whether the record exists when
|
206
|
-
# <tt>new_record</tt> is set to false.
|
207
|
-
def initialize(values = nil, from_db = false, &block)
|
208
|
-
values ||= {}
|
209
|
-
@changed_columns = []
|
210
|
-
if from_db
|
211
|
-
@new = false
|
212
|
-
@values = values
|
149
|
+
raise(Error, "No primary key is associated with this model") unless key = primary_key
|
150
|
+
case key
|
151
|
+
when Array
|
152
|
+
key.collect{|k| @values[k]}
|
213
153
|
else
|
214
|
-
@values
|
215
|
-
@new = true
|
216
|
-
set_with_params(values)
|
154
|
+
@values[key]
|
217
155
|
end
|
218
|
-
@changed_columns.clear
|
219
|
-
|
220
|
-
yield self if block
|
221
|
-
after_initialize
|
222
156
|
end
|
223
157
|
|
224
|
-
#
|
225
|
-
#
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
# Returns true if the current instance represents a new record.
|
231
|
-
def new?
|
232
|
-
@new
|
158
|
+
# Returns a hash identifying the model instance. It should be true that:
|
159
|
+
#
|
160
|
+
# Model[model_instance.pk_hash] === model_instance
|
161
|
+
def pk_hash
|
162
|
+
model.primary_key_hash(pk)
|
233
163
|
end
|
234
164
|
|
235
|
-
#
|
236
|
-
|
237
|
-
|
165
|
+
# Reloads attributes from database and returns self. Also clears all
|
166
|
+
# cached association information. Raises an Error if the record no longer
|
167
|
+
# exists in the database.
|
168
|
+
def refresh
|
169
|
+
@values = this.first || raise(Error, "Record not found")
|
170
|
+
model.all_association_reflections.each do |r|
|
171
|
+
instance_variable_set("@#{r[:name]}", nil)
|
172
|
+
end
|
173
|
+
self
|
238
174
|
end
|
239
|
-
|
240
|
-
|
241
|
-
#
|
175
|
+
alias_method :reload, :refresh
|
176
|
+
|
177
|
+
# Creates or updates the record, after making sure the record
|
178
|
+
# is valid. If the record is not valid, returns false.
|
179
|
+
# If before_save, before_create (if new?), or before_update
|
180
|
+
# (if !new?) return false, returns false. Otherwise,
|
181
|
+
# returns self.
|
242
182
|
def save(*columns)
|
243
|
-
|
183
|
+
return false unless valid?
|
184
|
+
save!(*columns)
|
185
|
+
end
|
186
|
+
|
187
|
+
# Creates or updates the record, without attempting to validate
|
188
|
+
# it first. You can provide an optional list of columns to update,
|
189
|
+
# in which case it only updates those columns.
|
190
|
+
# If before_save, before_create (if new?), or before_update
|
191
|
+
# (if !new?) return false, returns false. Otherwise,
|
192
|
+
# returns self.
|
193
|
+
def save!(*columns)
|
194
|
+
return false if before_save == false
|
244
195
|
if @new
|
245
|
-
before_create
|
196
|
+
return false if before_create == false
|
246
197
|
iid = model.dataset.insert(@values)
|
247
198
|
# if we have a regular primary key and it's not set in @values,
|
248
199
|
# we assume it's the last inserted id
|
@@ -256,7 +207,7 @@ module Sequel
|
|
256
207
|
@new = false
|
257
208
|
after_create
|
258
209
|
else
|
259
|
-
before_update
|
210
|
+
return false if before_update == false
|
260
211
|
if columns.empty?
|
261
212
|
this.update(@values)
|
262
213
|
@changed_columns = []
|
@@ -291,10 +242,10 @@ module Sequel
|
|
291
242
|
when String
|
292
243
|
# Prevent denial of service via memory exhaustion by only
|
293
244
|
# calling to_sym if the symbol already exists.
|
294
|
-
raise(
|
245
|
+
raise(Error, "all string keys must be a valid columns") unless s.include?(k)
|
295
246
|
k.to_sym
|
296
247
|
else
|
297
|
-
raise(
|
248
|
+
raise(Error, "Only symbols and strings allows as keys")
|
298
249
|
end
|
299
250
|
m[k] = v
|
300
251
|
m
|
@@ -303,46 +254,60 @@ module Sequel
|
|
303
254
|
vals
|
304
255
|
end
|
305
256
|
|
257
|
+
# Updates the instance with the supplied values with support for virtual
|
258
|
+
# attributes, ignoring any values for which no setter method is available.
|
259
|
+
# Does not save the record.
|
260
|
+
#
|
261
|
+
# If no columns have been set for this model (very unlikely), assume symbol
|
262
|
+
# keys are valid column names, and assign the column value based on that.
|
263
|
+
def set_with_params(hash)
|
264
|
+
columns_not_set = model.instance_variable_get(:@columns).blank?
|
265
|
+
meths = setter_methods
|
266
|
+
hash.each do |k,v|
|
267
|
+
m = "#{k}="
|
268
|
+
if meths.include?(m)
|
269
|
+
send(m, v)
|
270
|
+
elsif columns_not_set && (Symbol === k)
|
271
|
+
self[k] = v
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
# Returns (naked) dataset that should return only this instance.
|
277
|
+
def this
|
278
|
+
@this ||= dataset.filter(pk_hash).limit(1).naked
|
279
|
+
end
|
280
|
+
|
306
281
|
# Sets the values attributes with set_values and then updates
|
307
282
|
# the record in the database using those values. This is a
|
308
283
|
# low level method that does not run the usual save callbacks.
|
309
284
|
# It should probably be avoided. Look into using update_with_params instead.
|
310
285
|
def update_values(values)
|
286
|
+
before_update_values
|
311
287
|
this.update(set_values(values))
|
312
288
|
end
|
313
289
|
|
314
|
-
#
|
315
|
-
def
|
316
|
-
|
317
|
-
|
318
|
-
instance_variable_set("@#{r[:name]}", nil)
|
319
|
-
end
|
320
|
-
self
|
290
|
+
# Runs set_with_params and runs save_changes (which runs any callback methods).
|
291
|
+
def update_with_params(values)
|
292
|
+
set_with_params(values)
|
293
|
+
save_changes
|
321
294
|
end
|
322
|
-
alias_method :reload, :refresh
|
323
295
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
end
|
331
|
-
self
|
296
|
+
private
|
297
|
+
|
298
|
+
# Returns all methods that can be used for attribute
|
299
|
+
# assignment (those that end with =)
|
300
|
+
def setter_methods
|
301
|
+
methods.grep(/=\z/)
|
332
302
|
end
|
333
|
-
|
334
|
-
#
|
335
|
-
#
|
336
|
-
|
337
|
-
|
338
|
-
|
303
|
+
|
304
|
+
# Typecast the value to the column's type if typecasting. Calls the database's
|
305
|
+
# typecast_value method, so database adapters can override/augment the handling
|
306
|
+
# for database specific column types.
|
307
|
+
def typecast_value(column, value)
|
308
|
+
return value unless @typecast_on_assignment && @db_schema && (col_schema = @db_schema[column])
|
309
|
+
raise(Error, "nil/NULL is not allowed for the #{column} column") if value.nil? && (col_schema[:allow_null] == false)
|
310
|
+
model.db.typecast_value(col_schema[:type], value)
|
339
311
|
end
|
340
|
-
|
341
|
-
private
|
342
|
-
# Returns all methods that can be used for attribute
|
343
|
-
# assignment (those that end with =)
|
344
|
-
def setter_methods
|
345
|
-
methods.grep(/=\z/)
|
346
|
-
end
|
347
312
|
end
|
348
313
|
end
|