dynamoid 0.4.1 → 0.5.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/Dynamoid.gemspec +18 -8
- data/Gemfile +3 -1
- data/Gemfile.lock +48 -24
- data/README.markdown +6 -3
- data/VERSION +1 -1
- data/lib/dynamoid.rb +4 -0
- data/lib/dynamoid/adapter.rb +3 -3
- data/lib/dynamoid/adapter/aws_sdk.rb +19 -13
- data/lib/dynamoid/components.rb +5 -4
- data/lib/dynamoid/config.rb +7 -4
- data/lib/dynamoid/criteria/chain.rb +22 -13
- data/lib/dynamoid/dirty.rb +41 -0
- data/lib/dynamoid/document.rb +55 -26
- data/lib/dynamoid/errors.rb +5 -0
- data/lib/dynamoid/fields.rb +0 -5
- data/lib/dynamoid/finders.rb +60 -12
- data/lib/dynamoid/identity_map.rb +96 -0
- data/lib/dynamoid/indexes/index.rb +1 -1
- data/lib/dynamoid/middleware/identity_map.rb +16 -0
- data/lib/dynamoid/persistence.rb +45 -6
- data/spec/app/models/message.rb +9 -0
- data/spec/app/models/tweet.rb +3 -0
- data/spec/dynamoid/adapter/aws_sdk_spec.rb +34 -34
- data/spec/dynamoid/criteria/chain_spec.rb +17 -9
- data/spec/dynamoid/criteria_spec.rb +8 -2
- data/spec/dynamoid/dirty_spec.rb +49 -0
- data/spec/dynamoid/document_spec.rb +5 -1
- data/spec/dynamoid/fields_spec.rb +47 -17
- data/spec/dynamoid/finders_spec.rb +27 -11
- data/spec/dynamoid/identity_map_spec.rb +45 -0
- data/spec/dynamoid/indexes/index_spec.rb +0 -2
- data/spec/dynamoid/persistence_spec.rb +65 -29
- data/spec/dynamoid_spec.rb +4 -0
- data/spec/spec_helper.rb +21 -25
- metadata +54 -18
- data/lib/dynamoid/adapter/local.rb +0 -196
- data/spec/dynamoid/adapter/local_spec.rb +0 -242
@@ -48,7 +48,7 @@ module Dynamoid #:nodoc:
|
|
48
48
|
#
|
49
49
|
# @since 0.2.0
|
50
50
|
def table_name
|
51
|
-
"#{Dynamoid::Config.namespace}_index_#{
|
51
|
+
"#{Dynamoid::Config.namespace}_index_" + source.table_name.sub("#{Dynamoid::Config.namespace}_", '').singularize + "_#{name.collect(&:to_s).collect(&:pluralize).join('_and_')}"
|
52
52
|
end
|
53
53
|
|
54
54
|
# Given either an object or a list of attributes, generate a hash key and a range key for the index. Optionally pass in
|
data/lib/dynamoid/persistence.rb
CHANGED
@@ -32,8 +32,7 @@ module Dynamoid
|
|
32
32
|
# @since 0.4.0
|
33
33
|
def create_table(options = {})
|
34
34
|
if self.range_key
|
35
|
-
|
36
|
-
range_key_hash = { range_key => range_key_type}
|
35
|
+
range_key_hash = { range_key => dynamo_type(attributes[range_key][:type]) }
|
37
36
|
else
|
38
37
|
range_key_hash = nil
|
39
38
|
end
|
@@ -57,6 +56,10 @@ module Dynamoid
|
|
57
56
|
Dynamoid::Adapter.tables.include?(table_name)
|
58
57
|
end
|
59
58
|
|
59
|
+
def from_database(attrs = {})
|
60
|
+
new(attrs).tap { |r| r.new_record = false }
|
61
|
+
end
|
62
|
+
|
60
63
|
# Undump an object into a hash, converting each type from a string representation of itself into the type specified by the field.
|
61
64
|
#
|
62
65
|
# @since 0.2.0
|
@@ -75,7 +78,11 @@ module Dynamoid
|
|
75
78
|
#
|
76
79
|
# @since 0.2.0
|
77
80
|
def undump_field(value, options)
|
78
|
-
|
81
|
+
if value.nil? && (default_value = options[:default])
|
82
|
+
value = default_value.respond_to?(:call) ? default_value.call : default_value
|
83
|
+
else
|
84
|
+
return if value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
85
|
+
end
|
79
86
|
|
80
87
|
case options[:type]
|
81
88
|
when :string
|
@@ -105,6 +112,26 @@ module Dynamoid
|
|
105
112
|
end
|
106
113
|
end
|
107
114
|
|
115
|
+
def dynamo_type(type)
|
116
|
+
case type
|
117
|
+
when :integer, :float, :datetime
|
118
|
+
:number
|
119
|
+
when :string, :serialized
|
120
|
+
:string
|
121
|
+
else
|
122
|
+
raise 'unknown type'
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
# Set updated_at and any passed in field to current DateTime. Useful for things like last_login_at, etc.
|
129
|
+
#
|
130
|
+
def touch(name = nil)
|
131
|
+
now = DateTime.now
|
132
|
+
self.updated_at = now
|
133
|
+
attributes[name] = now if name
|
134
|
+
save
|
108
135
|
end
|
109
136
|
|
110
137
|
# Is this object persisted in the datastore? Required for some ActiveModel integration stuff.
|
@@ -120,8 +147,6 @@ module Dynamoid
|
|
120
147
|
def save(options = {})
|
121
148
|
self.class.create_table
|
122
149
|
|
123
|
-
@previously_changed = changes
|
124
|
-
|
125
150
|
if new_record?
|
126
151
|
run_callbacks(:create) { persist }
|
127
152
|
else
|
@@ -131,6 +156,19 @@ module Dynamoid
|
|
131
156
|
self
|
132
157
|
end
|
133
158
|
|
159
|
+
def update!(conditions = {}, &block)
|
160
|
+
options = range_key ? {:range_key => dump_field(self.read_attribute(range_key), self.class.attributes[range_key])} : {}
|
161
|
+
new_attrs = Dynamoid::Adapter.update_item(self.class.table_name, self.hash_key, options.merge(:conditions => conditions), &block)
|
162
|
+
load(new_attrs)
|
163
|
+
end
|
164
|
+
|
165
|
+
def update(conditions = {}, &block)
|
166
|
+
update!(conditions, &block)
|
167
|
+
true
|
168
|
+
rescue Dynamoid::Errors::ConditionalCheckFailedException
|
169
|
+
false
|
170
|
+
end
|
171
|
+
|
134
172
|
# Delete this object, but only after running callbacks for it.
|
135
173
|
#
|
136
174
|
# @since 0.2.0
|
@@ -146,7 +184,8 @@ module Dynamoid
|
|
146
184
|
# @since 0.2.0
|
147
185
|
def delete
|
148
186
|
delete_indexes
|
149
|
-
|
187
|
+
options = range_key ? {:range_key => dump_field(self.read_attribute(range_key), self.class.attributes[range_key])} : {}
|
188
|
+
Dynamoid::Adapter.delete(self.class.table_name, self.hash_key, options)
|
150
189
|
end
|
151
190
|
|
152
191
|
# Dump this object's attributes into hash form, fit to be persisted into the datastore.
|
data/spec/app/models/tweet.rb
CHANGED
@@ -2,20 +2,20 @@ require 'dynamoid/adapter/aws_sdk'
|
|
2
2
|
require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
|
3
3
|
|
4
4
|
describe Dynamoid::Adapter::AwsSdk do
|
5
|
-
|
5
|
+
|
6
6
|
if ENV['ACCESS_KEY'] && ENV['SECRET_KEY']
|
7
|
-
|
7
|
+
|
8
8
|
context 'without a preexisting table' do
|
9
9
|
# CreateTable and DeleteTable
|
10
10
|
it 'performs CreateTable and DeleteTable' do
|
11
11
|
table = Dynamoid::Adapter.create_table('CreateTable', :id, :range_key => { :created_at => :number })
|
12
|
-
|
12
|
+
|
13
13
|
Dynamoid::Adapter.connection.tables.collect{|t| t.name}.should include 'CreateTable'
|
14
|
-
|
14
|
+
|
15
15
|
Dynamoid::Adapter.delete_table('CreateTable')
|
16
16
|
end
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
context 'with a preexisting table' do
|
20
20
|
before(:all) do
|
21
21
|
Dynamoid::Adapter.create_table('dynamoid_tests_TestTable1', :id) unless Dynamoid::Adapter.list_tables.include?('dynamoid_tests_TestTable1')
|
@@ -34,20 +34,20 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
34
34
|
Dynamoid::Adapter.get_item('dynamoid_tests_TestTable1', '1').should == {:name => 'Josh', :id => '1'}
|
35
35
|
|
36
36
|
Dynamoid::Adapter.delete_item('dynamoid_tests_TestTable1', '1')
|
37
|
-
|
37
|
+
|
38
38
|
Dynamoid::Adapter.get_item('dynamoid_tests_TestTable1', '1').should be_nil
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
it 'performs GetItem for an item that does exist with a range key' do
|
42
42
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '1', :name => 'Josh', :range => 2.0})
|
43
43
|
|
44
44
|
Dynamoid::Adapter.get_item('dynamoid_tests_TestTable3', '1', :range_key => 2.0).should == {:name => 'Josh', :id => '1', :range => 2.0}
|
45
45
|
|
46
46
|
Dynamoid::Adapter.delete_item('dynamoid_tests_TestTable3', '1', :range_key => 2.0)
|
47
|
-
|
48
|
-
Dynamoid::Adapter.get_item('dynamoid_tests_TestTable3', '1', :range_key => 2.0).should be_nil
|
47
|
+
|
48
|
+
Dynamoid::Adapter.get_item('dynamoid_tests_TestTable3', '1', :range_key => 2.0).should be_nil
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
it 'performs DeleteItem for an item that does not exist' do
|
52
52
|
Dynamoid::Adapter.delete_item('dynamoid_tests_TestTable1', '1')
|
53
53
|
|
@@ -59,53 +59,53 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
59
59
|
|
60
60
|
Dynamoid::Adapter.get_item('dynamoid_tests_TestTable1', '1').should == {:id => '1', :name => 'Josh'}
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
# BatchGetItem
|
64
64
|
it "performs BatchGetItem with singular keys" do
|
65
65
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '1', :name => 'Josh'})
|
66
66
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable2', {:id => '1', :name => 'Justin'})
|
67
|
-
|
67
|
+
|
68
68
|
results = Dynamoid::Adapter.batch_get_item('dynamoid_tests_TestTable1' => '1', 'dynamoid_tests_TestTable2' => '1')
|
69
69
|
results.size.should == 2
|
70
70
|
results['dynamoid_tests_TestTable1'].should include({:name => 'Josh', :id => '1'})
|
71
71
|
results['dynamoid_tests_TestTable2'].should include({:name => 'Justin', :id => '1'})
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
it "performs BatchGetItem with multiple keys" do
|
75
75
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '1', :name => 'Josh'})
|
76
76
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '2', :name => 'Justin'})
|
77
|
-
|
77
|
+
|
78
78
|
results = Dynamoid::Adapter.batch_get_item('dynamoid_tests_TestTable1' => ['1', '2'])
|
79
79
|
results.size.should == 1
|
80
80
|
results['dynamoid_tests_TestTable1'].should include({:name => 'Josh', :id => '1'})
|
81
81
|
results['dynamoid_tests_TestTable1'].should include({:name => 'Justin', :id => '2'})
|
82
82
|
end
|
83
|
-
|
83
|
+
|
84
84
|
it 'performs BatchGetItem with one ranged key' do
|
85
85
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '1', :name => 'Josh', :range => 1.0})
|
86
86
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '2', :name => 'Justin', :range => 2.0})
|
87
|
-
|
87
|
+
|
88
88
|
results = Dynamoid::Adapter.batch_get_item('dynamoid_tests_TestTable3' => [['1', 1.0]])
|
89
89
|
results.size.should == 1
|
90
90
|
results['dynamoid_tests_TestTable3'].should include({:name => 'Josh', :id => '1', :range => 1.0})
|
91
91
|
end
|
92
|
-
|
92
|
+
|
93
93
|
it 'performs BatchGetItem with multiple ranged keys' do
|
94
94
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '1', :name => 'Josh', :range => 1.0})
|
95
95
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '2', :name => 'Justin', :range => 2.0})
|
96
|
-
|
96
|
+
|
97
97
|
results = Dynamoid::Adapter.batch_get_item('dynamoid_tests_TestTable3' => [['1', 1.0],['2', 2.0]])
|
98
98
|
results.size.should == 1
|
99
99
|
results['dynamoid_tests_TestTable3'].should include({:name => 'Josh', :id => '1', :range => 1.0})
|
100
100
|
results['dynamoid_tests_TestTable3'].should include({:name => 'Justin', :id => '2', :range => 2.0})
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
# ListTables
|
104
104
|
it 'performs ListTables' do
|
105
105
|
Dynamoid::Adapter.list_tables.should include 'dynamoid_tests_TestTable1'
|
106
106
|
Dynamoid::Adapter.list_tables.should include 'dynamoid_tests_TestTable2'
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
109
|
# Query
|
110
110
|
it 'performs query on a table and returns items' do
|
111
111
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '1', :name => 'Josh'})
|
@@ -119,30 +119,30 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
119
119
|
|
120
120
|
Dynamoid::Adapter.query('dynamoid_tests_TestTable1', :hash_value => '1').should == { :id=> '1', :name=>"Josh" }
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
context 'range queries' do
|
124
124
|
before do
|
125
125
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '1', :range => 1.0})
|
126
126
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '1', :range => 3.0})
|
127
127
|
end
|
128
128
|
|
129
|
-
it 'performs query on a table with a range and selects items in a range' do
|
129
|
+
it 'performs query on a table with a range and selects items in a range' do
|
130
130
|
Dynamoid::Adapter.query('dynamoid_tests_TestTable3', :hash_value => '1', :range_value => 0.0..3.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
131
131
|
end
|
132
132
|
|
133
|
-
it 'performs query on a table with a range and selects items greater than' do
|
133
|
+
it 'performs query on a table with a range and selects items greater than' do
|
134
134
|
Dynamoid::Adapter.query('dynamoid_tests_TestTable3', :hash_value => '1', :range_greater_than => 1.0).should =~ [{:id => '1', :range => BigDecimal.new(3)}]
|
135
135
|
end
|
136
136
|
|
137
|
-
it 'performs query on a table with a range and selects items less than' do
|
137
|
+
it 'performs query on a table with a range and selects items less than' do
|
138
138
|
Dynamoid::Adapter.query('dynamoid_tests_TestTable3', :hash_value => '1', :range_less_than => 2.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}]
|
139
139
|
end
|
140
140
|
|
141
|
-
it 'performs query on a table with a range and selects items gte' do
|
141
|
+
it 'performs query on a table with a range and selects items gte' do
|
142
142
|
Dynamoid::Adapter.query('dynamoid_tests_TestTable3', :hash_value => '1', :range_gte => 1.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
143
143
|
end
|
144
144
|
|
145
|
-
it 'performs query on a table with a range and selects items lte' do
|
145
|
+
it 'performs query on a table with a range and selects items lte' do
|
146
146
|
Dynamoid::Adapter.query('dynamoid_tests_TestTable3', :hash_value => '1', :range_lte => 3.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
147
147
|
end
|
148
148
|
end
|
@@ -165,22 +165,22 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
165
165
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '1', :name => 'Josh'})
|
166
166
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '2', :name => 'Josh'})
|
167
167
|
|
168
|
-
Dynamoid::Adapter.scan('dynamoid_tests_TestTable1', :name => 'Josh').should
|
168
|
+
Dynamoid::Adapter.scan('dynamoid_tests_TestTable1', :name => 'Josh').should include({:name=>"Josh", :id=>"2"}, {:name=>"Josh", :id=>"1"})
|
169
169
|
end
|
170
|
-
|
170
|
+
|
171
171
|
it 'performs scan on a table and returns all items if no criteria are specified' do
|
172
172
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '1', :name => 'Josh'})
|
173
173
|
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '2', :name => 'Josh'})
|
174
174
|
|
175
|
-
Dynamoid::Adapter.scan('dynamoid_tests_TestTable1', {}).should
|
176
|
-
end
|
175
|
+
Dynamoid::Adapter.scan('dynamoid_tests_TestTable1', {}).should include({:name=>"Josh", :id=>"2"}, {:name=>"Josh", :id=>"1"})
|
176
|
+
end
|
177
177
|
end
|
178
|
-
|
178
|
+
|
179
179
|
# DescribeTable
|
180
|
-
|
180
|
+
|
181
181
|
# UpdateItem
|
182
|
-
|
182
|
+
|
183
183
|
# UpdateTable
|
184
|
-
|
184
|
+
|
185
185
|
end
|
186
186
|
end
|
@@ -73,6 +73,14 @@ describe "Dynamoid::Associations::Chain" do
|
|
73
73
|
@chain.send(:records_without_index).should == [@user]
|
74
74
|
end
|
75
75
|
|
76
|
+
it "doesn't crash if it finds a nil id in the index" do
|
77
|
+
@chain.query = {:name => 'Josh', "created_at.gt" => @time - 1.day}
|
78
|
+
Dynamoid::Adapter.expects(:query).
|
79
|
+
with("dynamoid_tests_index_user_created_ats_and_names", kind_of(Hash)).
|
80
|
+
returns([{ids: nil}, {ids: Set.new([42])}])
|
81
|
+
@chain.send(:ids_from_index).should == Set.new([42])
|
82
|
+
end
|
83
|
+
|
76
84
|
it 'defines each' do
|
77
85
|
@chain.query = {:name => 'Josh'}
|
78
86
|
@chain.each {|u| u.update_attribute(:name, 'Justin')}
|
@@ -88,10 +96,10 @@ describe "Dynamoid::Associations::Chain" do
|
|
88
96
|
|
89
97
|
it 'finds range querys' do
|
90
98
|
@chain = Dynamoid::Criteria::Chain.new(Tweet)
|
91
|
-
@chain.query = { :
|
99
|
+
@chain.query = { :tweet_id => 'test' }
|
92
100
|
@chain.send(:range?).should be_true
|
93
101
|
|
94
|
-
@chain.query = {:
|
102
|
+
@chain.query = {:tweet_id => 'test', :group => 'xx'}
|
95
103
|
@chain.send(:range?).should be_true
|
96
104
|
|
97
105
|
@chain.query = { :group => 'xx' }
|
@@ -100,32 +108,32 @@ describe "Dynamoid::Associations::Chain" do
|
|
100
108
|
@chain.query = { :group => 'xx', :msg => 'hai' }
|
101
109
|
@chain.send(:range?).should be_false
|
102
110
|
end
|
103
|
-
|
111
|
+
|
104
112
|
context 'range queries' do
|
105
113
|
before do
|
106
114
|
@tweet1 = Tweet.create(:tweet_id => "x", :group => "one")
|
107
115
|
@tweet2 = Tweet.create(:tweet_id => "x", :group => "two")
|
108
|
-
@tweet3 = Tweet.create(:tweet_id => "xx", :group => "two")
|
116
|
+
@tweet3 = Tweet.create(:tweet_id => "xx", :group => "two")
|
109
117
|
@chain = Dynamoid::Criteria::Chain.new(Tweet)
|
110
118
|
end
|
111
|
-
|
119
|
+
|
112
120
|
it 'finds tweets with a simple range query' do
|
113
121
|
@chain.query = { :tweet_id => "x" }
|
114
122
|
@chain.send(:records_with_range).size.should == 2
|
115
123
|
@chain.all.size.should == 2
|
116
|
-
@chain.limit(1).size.should == 1
|
124
|
+
@chain.limit(1).size.should == 1
|
117
125
|
end
|
118
|
-
|
126
|
+
|
119
127
|
it 'finds tweets with a start' do
|
120
128
|
@chain.query = { :tweet_id => "x" }
|
121
129
|
@chain.start(@tweet1)
|
122
130
|
@chain.all.should =~ [@tweet2]
|
123
131
|
end
|
124
|
-
|
132
|
+
|
125
133
|
it 'finds one specific tweet' do
|
126
134
|
@chain = Dynamoid::Criteria::Chain.new(Tweet)
|
127
135
|
@chain.query = { :tweet_id => "xx", :group => "two" }
|
128
|
-
@chain.send(:records_with_range).should == [@tweet3]
|
136
|
+
@chain.send(:records_with_range).should == [@tweet3]
|
129
137
|
end
|
130
138
|
end
|
131
139
|
|
@@ -57,10 +57,16 @@ describe "Dynamoid::Criteria" do
|
|
57
57
|
User.where(:name => 'x').consistent.first
|
58
58
|
|
59
59
|
Dynamoid::Adapter.expects(:query).with { |table_name, options| options[:consistent_read] == true }.returns([])
|
60
|
-
Tweet.where(:
|
60
|
+
Tweet.where(:tweet_id => 'xx', :group => 'two').consistent.all
|
61
61
|
|
62
62
|
Dynamoid::Adapter.expects(:query).with { |table_name, options| options[:consistent_read] == false }.returns([])
|
63
|
-
Tweet.where(:
|
63
|
+
Tweet.where(:tweet_id => 'xx', :group => 'two').all
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'raises exception when consistent_read is used with scan' do
|
67
|
+
expect do
|
68
|
+
User.where(:password => 'password').consistent.first
|
69
|
+
end.to raise_error(Dynamoid::Errors::InvalidQuery)
|
64
70
|
end
|
65
71
|
|
66
72
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe 'Dynamoid::Dirty' do
|
4
|
+
|
5
|
+
context 'changes' do
|
6
|
+
it 'should be empty' do
|
7
|
+
tweet = Tweet.new
|
8
|
+
tweet.msg_changed?.should be_false
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should not be empty' do
|
12
|
+
tweet = Tweet.new(:tweet_id => "1", :group => 'abc')
|
13
|
+
tweet.changed?.should be_true
|
14
|
+
tweet.group_was.should be_nil
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should be empty when loaded from database' do
|
18
|
+
Tweet.create!(:tweet_id => "1", :group => 'abc')
|
19
|
+
tweet = Tweet.where(:tweet_id => "1", :group => 'abc').first
|
20
|
+
tweet.changed?.should be_false
|
21
|
+
tweet.group = 'abc'
|
22
|
+
tweet.reload
|
23
|
+
tweet.changed?.should be_false
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'track changes after saves' do
|
27
|
+
tweet = Tweet.new(:tweet_id => "1", :group => 'abc')
|
28
|
+
tweet.save!
|
29
|
+
tweet.changed?.should be_false
|
30
|
+
|
31
|
+
tweet.user_name = 'xyz'
|
32
|
+
tweet.user_name_changed?.should be_true
|
33
|
+
tweet.user_name_was.should be_nil
|
34
|
+
tweet.save!
|
35
|
+
|
36
|
+
tweet.user_name_changed?.should be_false
|
37
|
+
tweet.user_name = 'abc'
|
38
|
+
tweet.user_name_was.should == 'xyz'
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'clear changes on save' do
|
42
|
+
tweet = Tweet.new(:tweet_id => "1", :group => 'abc')
|
43
|
+
tweet.group = 'xyz'
|
44
|
+
tweet.group_changed?.should be_true
|
45
|
+
tweet.save!
|
46
|
+
tweet.group_changed?.should be_false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|