Skip to content

Commit

Permalink
Add Model#set_fields and update_fields, similar to set_only and updat…
Browse files Browse the repository at this point in the history
…e_only but ignoring other keys in the hash

set_fields and update_fields behave similarly to set_only and
update_only with strict_param_setting set to false.  That is, they
only set the fields given, and ignore the other entries in the
hash.  They don't check the strict_param_setting flag, so if you
have a hash that has other unrelated keys and you only want to
use the keys you care about (and don't want to set
strict_param_setting to false), this is the method to use.

These methods don't use the framework the other set and update
methods use, so if you try specify a field that doesn't have a setter
method, you'll get a NoMethodError instead of a Sequel::Error.
The other set and update methods try each entry in the hash and
check if it is allowed, set_fields and update_fields just iterate
through the given array.

Another difference between the *_fields methods and the *_only
methods is how they handle entries in the array that aren't in
the hash.  set_only will ignore the entries, since it iterates
over the hash.  set_fields will call the setter method with
the default value of the hash (or whatever is returned by #[]),
since it iterates over the array.
  • Loading branch information
jeremyevans committed May 13, 2010
1 parent d3a0f66 commit 9b28b3b
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
@@ -1,5 +1,7 @@
=== HEAD

* Add Model#set_fields and update_fields, similar to set_only and update_only but ignoring other keys in the hash (jeremyevans)

* Add Model.qualified_primary_key_hash, similar to primary_key_hash but with qualified columns (jeremyevans)

* Make Model::Errors#empty? handle attributes with empty error arrays (jeremyevans)
Expand Down
14 changes: 14 additions & 0 deletions lib/sequel/model/base.rb
Expand Up @@ -780,6 +780,13 @@ def set_except(hash, *except)
set_restricted(hash, false, except.flatten)
end

# For each of the fields in the given array +fields+, call the setter
# method with the value of that +hash+ entry for the field. Returns self.
def set_fields(hash, fields)
fields.each{|f| send("#{f}=", hash[f])}
self
end

# Set the values using the entries in the hash, only if the key
# is included in only.
def set_only(hash, *only)
Expand Down Expand Up @@ -808,6 +815,13 @@ def update_except(hash, *except)
update_restricted(hash, false, except.flatten)
end

# Update the instances values by calling +set_fields+ with the +hash+
# and +fields+, then save any changes to the record. Returns self.
def update_fields(hash, fields)
set_fields(hash, fields)
save_changes
end

# Update the values using the entries in the hash, only if the key
# is included in only.
def update_only(hash, *only)
Expand Down
74 changes: 71 additions & 3 deletions spec/model/record_spec.rb
Expand Up @@ -737,6 +737,54 @@ def o.modified?; false; end
end
end

describe Sequel::Model, "#set_fields" do
before do
@c = Class.new(Sequel::Model(:items))
@c.class_eval do
set_primary_key :id
columns :x, :y, :z, :id
end
@c.strict_param_setting = true
@o1 = @c.new
MODEL_DB.reset
end

it "should set only the given fields" do
@o1.set_fields({:x => 1, :y => 2, :z=>3, :id=>4}, [:x, :y])
@o1.values.should == {:x => 1, :y => 2}
@o1.set_fields({:x => 9, :y => 8, :z=>6, :id=>7}, [:x, :y, :id])
@o1.values.should == {:x => 9, :y => 8, :id=>7}
MODEL_DB.sqls.should == []
end
end

describe Sequel::Model, "#update_fields" do
before do
@c = Class.new(Sequel::Model(:items))
@c.class_eval do
set_primary_key :id
columns :x, :y, :z, :id
def _refresh(ds); end
end
@c.strict_param_setting = true
@o1 = @c.load(:id=>1)
MODEL_DB.reset
end

it "should set only the given fields, and then save the changes to the record" do
@o1.update_fields({:x => 1, :y => 2, :z=>3, :id=>4}, [:x, :y])
@o1.values.should == {:x => 1, :y => 2, :id=>1}
MODEL_DB.sqls.first.should =~ /UPDATE items SET [xy] = [12], [xy] = [12] WHERE \(id = 1\)/
MODEL_DB.sqls.length.should == 1
MODEL_DB.reset

@o1.update_fields({:x => 1, :y => 5, :z=>6, :id=>7}, [:x, :y])
@o1.values.should == {:x => 1, :y => 5, :id=>1}
MODEL_DB.sqls.should == ["UPDATE items SET y = 5 WHERE (id = 1)"]
MODEL_DB.reset
end
end

describe Sequel::Model, "#(set|update)_(all|except|only)" do
before do
MODEL_DB.reset
Expand All @@ -752,7 +800,25 @@ def o.modified?; false; end
@o1 = @c.new
end

it "#set_all should set all attributes" do
it "should raise errors if not all hash fields can be set and strict_param_setting is true" do
@c.strict_param_setting = true

proc{@c.new.set_all(:x => 1, :y => 2, :z=>3, :id=>4)}.should raise_error(Sequel::Error)
(o = @c.new).set_all(:x => 1, :y => 2, :z=>3)
o.values.should == {:x => 1, :y => 2, :z=>3}

proc{@c.new.set_only({:x => 1, :y => 2, :z=>3, :id=>4}, :x, :y)}.should raise_error(Sequel::Error)
proc{@c.new.set_only({:x => 1, :y => 2, :z=>3}, :x, :y)}.should raise_error(Sequel::Error)
(o = @c.new).set_only({:x => 1, :y => 2}, :x, :y)
o.values.should == {:x => 1, :y => 2}

proc{@c.new.set_except({:x => 1, :y => 2, :z=>3, :id=>4}, :x, :y)}.should raise_error(Sequel::Error)
proc{@c.new.set_except({:x => 1, :y => 2, :z=>3}, :x, :y)}.should raise_error(Sequel::Error)
(o = @c.new).set_except({:z => 3}, :x, :y)
o.values.should == {:z=>3}
end

it "#set_all should set all attributes except the primary key" do
@o1.set_all(:x => 1, :y => 2, :z=>3, :id=>4)
@o1.values.should == {:x => 1, :y => 2, :z=>3}
end
Expand All @@ -762,9 +828,11 @@ def o.modified?; false; end
@o1.values.should == {:x => 1, :y => 2}
@o1.set_only({:x => 4, :y => 5, :z=>6, :id=>7}, :x, :y)
@o1.values.should == {:x => 4, :y => 5}
@o1.set_only({:x => 9, :y => 8, :z=>6, :id=>7}, :x, :y, :id)
@o1.values.should == {:x => 9, :y => 8, :id=>7}
end

it "#set_except should not set given attributes" do
it "#set_except should not set given attributes or the primary key" do
@o1.set_except({:x => 1, :y => 2, :z=>3, :id=>4}, [:y, :z])
@o1.values.should == {:x => 1}
@o1.set_except({:x => 4, :y => 2, :z=>3, :id=>4}, :y, :z)
Expand Down Expand Up @@ -1497,4 +1565,4 @@ def ds.fetch_rows(sql)
called.should == true
MODEL_DB.sqls.should == ["SELECT * FROM items WHERE (id = 1) LIMIT 1 FOR UPDATE"]
end
end
end

0 comments on commit 9b28b3b

Please sign in to comment.