dynamoid 0.6.1 → 0.7.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/.travis.yml +4 -0
- data/Gemfile +3 -2
- data/Gemfile.lock +40 -45
- data/README.markdown +55 -25
- data/Rakefile +31 -0
- data/VERSION +1 -1
- data/doc/Dynamoid.html +58 -42
- data/doc/Dynamoid/Adapter.html +666 -179
- data/doc/Dynamoid/Adapter/AwsSdk.html +752 -236
- data/doc/Dynamoid/Associations.html +28 -21
- data/doc/Dynamoid/Associations/Association.html +102 -49
- data/doc/Dynamoid/Associations/BelongsTo.html +28 -25
- data/doc/Dynamoid/Associations/ClassMethods.html +95 -52
- data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +28 -25
- data/doc/Dynamoid/Associations/HasMany.html +28 -25
- data/doc/Dynamoid/Associations/HasOne.html +28 -25
- data/doc/Dynamoid/Associations/ManyAssociation.html +138 -94
- data/doc/Dynamoid/Associations/SingleAssociation.html +67 -38
- data/doc/Dynamoid/Components.html +60 -22
- data/doc/Dynamoid/Config.html +61 -44
- data/doc/Dynamoid/Config/Options.html +90 -61
- data/doc/Dynamoid/Criteria.html +28 -21
- data/doc/Dynamoid/Criteria/Chain.html +508 -100
- data/doc/Dynamoid/Criteria/ClassMethods.html +26 -19
- data/doc/Dynamoid/Dirty.html +424 -0
- data/doc/Dynamoid/Dirty/ClassMethods.html +174 -0
- data/doc/Dynamoid/Document.html +451 -84
- data/doc/Dynamoid/Document/ClassMethods.html +281 -102
- data/doc/Dynamoid/Errors.html +29 -22
- data/doc/Dynamoid/Errors/ConditionalCheckFailedException.html +141 -0
- data/doc/Dynamoid/Errors/DocumentNotValid.html +36 -25
- data/doc/Dynamoid/Errors/Error.html +27 -20
- data/doc/Dynamoid/Errors/InvalidField.html +27 -19
- data/doc/Dynamoid/Errors/InvalidQuery.html +131 -0
- data/doc/Dynamoid/Errors/MissingRangeKey.html +27 -19
- data/doc/Dynamoid/Fields.html +94 -77
- data/doc/Dynamoid/Fields/ClassMethods.html +166 -37
- data/doc/Dynamoid/Finders.html +28 -21
- data/doc/Dynamoid/Finders/ClassMethods.html +505 -78
- data/doc/Dynamoid/IdentityMap.html +492 -0
- data/doc/Dynamoid/IdentityMap/ClassMethods.html +534 -0
- data/doc/Dynamoid/Indexes.html +41 -28
- data/doc/Dynamoid/Indexes/ClassMethods.html +45 -29
- data/doc/Dynamoid/Indexes/Index.html +100 -62
- data/doc/Dynamoid/Middleware.html +115 -0
- data/doc/Dynamoid/Middleware/IdentityMap.html +264 -0
- data/doc/Dynamoid/Persistence.html +326 -85
- data/doc/Dynamoid/Persistence/ClassMethods.html +275 -109
- data/doc/Dynamoid/Validations.html +47 -31
- data/doc/_index.html +116 -71
- data/doc/class_list.html +13 -7
- data/doc/css/full_list.css +4 -2
- data/doc/css/style.css +60 -44
- data/doc/file.LICENSE.html +26 -19
- data/doc/file.README.html +152 -48
- data/doc/file_list.html +14 -8
- data/doc/frames.html +20 -5
- data/doc/index.html +152 -48
- data/doc/js/app.js +52 -43
- data/doc/js/full_list.js +14 -9
- data/doc/js/jquery.js +4 -16
- data/doc/method_list.html +446 -540
- data/doc/top-level-namespace.html +27 -20
- data/{Dynamoid.gemspec → dynamoid.gemspec} +21 -8
- data/lib/dynamoid/adapter.rb +11 -10
- data/lib/dynamoid/adapter/aws_sdk.rb +40 -19
- data/lib/dynamoid/components.rb +2 -1
- data/lib/dynamoid/criteria/chain.rb +29 -11
- data/lib/dynamoid/dirty.rb +6 -0
- data/lib/dynamoid/document.rb +34 -19
- data/lib/dynamoid/fields.rb +36 -30
- data/lib/dynamoid/finders.rb +7 -5
- data/lib/dynamoid/persistence.rb +37 -10
- data/spec/app/models/address.rb +2 -0
- data/spec/app/models/camel_case.rb +10 -0
- data/spec/app/models/car.rb +6 -0
- data/spec/app/models/nuclear_submarine.rb +5 -0
- data/spec/app/models/subscription.rb +2 -2
- data/spec/app/models/vehicle.rb +7 -0
- data/spec/dynamoid/adapter/aws_sdk_spec.rb +20 -11
- data/spec/dynamoid/adapter_spec.rb +67 -82
- data/spec/dynamoid/associations/association_spec.rb +30 -30
- data/spec/dynamoid/criteria/chain_spec.rb +56 -9
- data/spec/dynamoid/criteria_spec.rb +3 -0
- data/spec/dynamoid/dirty_spec.rb +8 -0
- data/spec/dynamoid/document_spec.rb +109 -47
- data/spec/dynamoid/fields_spec.rb +32 -3
- data/spec/dynamoid/finders_spec.rb +12 -0
- data/spec/dynamoid/persistence_spec.rb +73 -8
- data/spec/spec_helper.rb +1 -0
- data/spec/support/with_partitioning.rb +15 -0
- metadata +22 -9
data/lib/dynamoid/dirty.rb
CHANGED
|
@@ -13,6 +13,12 @@ module Dynamoid
|
|
|
13
13
|
clear_changes { super }
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
def update!(*)
|
|
17
|
+
ret = super
|
|
18
|
+
clear_changes #update! completely reloads all fields on the class, so any extant changes are wiped out
|
|
19
|
+
ret
|
|
20
|
+
end
|
|
21
|
+
|
|
16
22
|
def reload
|
|
17
23
|
super.tap { clear_changes }
|
|
18
24
|
end
|
data/lib/dynamoid/document.rb
CHANGED
|
@@ -8,9 +8,10 @@ module Dynamoid #:nodoc:
|
|
|
8
8
|
include Dynamoid::Components
|
|
9
9
|
|
|
10
10
|
included do
|
|
11
|
-
class_attribute :options, :read_only_attributes
|
|
11
|
+
class_attribute :options, :read_only_attributes, :base_class
|
|
12
12
|
self.options = {}
|
|
13
13
|
self.read_only_attributes = []
|
|
14
|
+
self.base_class = self
|
|
14
15
|
|
|
15
16
|
Dynamoid::Config.included_models << self
|
|
16
17
|
end
|
|
@@ -28,6 +29,7 @@ module Dynamoid #:nodoc:
|
|
|
28
29
|
# @since 0.4.0
|
|
29
30
|
def table(options = {})
|
|
30
31
|
self.options = options
|
|
32
|
+
super if defined? super
|
|
31
33
|
end
|
|
32
34
|
|
|
33
35
|
def attr_readonly(*read_only_attributes)
|
|
@@ -55,6 +57,13 @@ module Dynamoid #:nodoc:
|
|
|
55
57
|
options[:key] || :id
|
|
56
58
|
end
|
|
57
59
|
|
|
60
|
+
# Returns the number of items for this class.
|
|
61
|
+
#
|
|
62
|
+
# @since 0.6.1
|
|
63
|
+
def count
|
|
64
|
+
Dynamoid::Adapter::AwsSdk.count(table_name)
|
|
65
|
+
end
|
|
66
|
+
|
|
58
67
|
# Initialize a new object and immediately save it to the database.
|
|
59
68
|
#
|
|
60
69
|
# @param [Hash] attrs Attributes with which to create the object.
|
|
@@ -63,7 +72,7 @@ module Dynamoid #:nodoc:
|
|
|
63
72
|
#
|
|
64
73
|
# @since 0.2.0
|
|
65
74
|
def create(attrs = {})
|
|
66
|
-
new(attrs).tap(&:save)
|
|
75
|
+
attrs[:type] ? attrs[:type].constantize.new(attrs).tap(&:save) : new(attrs).tap(&:save)
|
|
67
76
|
end
|
|
68
77
|
|
|
69
78
|
# Initialize a new object and immediately save it to the database. Raise an exception if persistence failed.
|
|
@@ -74,7 +83,7 @@ module Dynamoid #:nodoc:
|
|
|
74
83
|
#
|
|
75
84
|
# @since 0.2.0
|
|
76
85
|
def create!(attrs = {})
|
|
77
|
-
new(attrs).tap(&:save!)
|
|
86
|
+
attrs[:type] ? attrs[:type].constantize.new(attrs).tap(&:save!) : new(attrs).tap(&:save!)
|
|
78
87
|
end
|
|
79
88
|
|
|
80
89
|
# Initialize a new object.
|
|
@@ -85,18 +94,21 @@ module Dynamoid #:nodoc:
|
|
|
85
94
|
#
|
|
86
95
|
# @since 0.2.0
|
|
87
96
|
def build(attrs = {})
|
|
88
|
-
new(attrs)
|
|
97
|
+
attrs[:type] ? attrs[:type].constantize.new(attrs) : new(attrs)
|
|
89
98
|
end
|
|
90
99
|
|
|
91
100
|
# Does this object exist?
|
|
92
101
|
#
|
|
93
|
-
# @param [
|
|
102
|
+
# @param [Mixed] id_or_conditions the id of the object or a hash with the options to filter from.
|
|
94
103
|
#
|
|
95
104
|
# @return [Boolean] true/false
|
|
96
105
|
#
|
|
97
106
|
# @since 0.2.0
|
|
98
|
-
def exists?(
|
|
99
|
-
|
|
107
|
+
def exists?(id_or_conditions = {})
|
|
108
|
+
case id_or_conditions
|
|
109
|
+
when Hash then ! where(id_or_conditions).all.empty?
|
|
110
|
+
else !! find(id_or_conditions)
|
|
111
|
+
end
|
|
100
112
|
end
|
|
101
113
|
end
|
|
102
114
|
|
|
@@ -109,8 +121,6 @@ module Dynamoid #:nodoc:
|
|
|
109
121
|
# @since 0.2.0
|
|
110
122
|
def initialize(attrs = {})
|
|
111
123
|
run_callbacks :initialize do
|
|
112
|
-
self.class.send(:field, self.class.hash_key) unless self.respond_to?(self.class.hash_key)
|
|
113
|
-
|
|
114
124
|
@new_record = true
|
|
115
125
|
@attributes ||= {}
|
|
116
126
|
@associations ||= {}
|
|
@@ -131,18 +141,27 @@ module Dynamoid #:nodoc:
|
|
|
131
141
|
super
|
|
132
142
|
else
|
|
133
143
|
return false if other.nil?
|
|
134
|
-
other.
|
|
144
|
+
other.is_a?(Dynamoid::Document) && self.hash_key == other.hash_key && self.range_value == other.range_value
|
|
135
145
|
end
|
|
136
146
|
end
|
|
137
147
|
|
|
148
|
+
def eql?(other)
|
|
149
|
+
self == other
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def hash
|
|
153
|
+
hash_key.hash ^ range_value.hash
|
|
154
|
+
end
|
|
155
|
+
|
|
138
156
|
# Reload an object from the database -- if you suspect the object has changed in the datastore and you need those
|
|
139
|
-
# changes to be reflected immediately, you would call this method.
|
|
157
|
+
# changes to be reflected immediately, you would call this method. This is a consistent read.
|
|
140
158
|
#
|
|
141
159
|
# @return [Dynamoid::Document] the document this method was called on
|
|
142
160
|
#
|
|
143
161
|
# @since 0.2.0
|
|
144
162
|
def reload
|
|
145
|
-
|
|
163
|
+
range_key_value = range_value ? dumped_range_value : nil
|
|
164
|
+
self.attributes = self.class.find(hash_key, :range_key => range_key_value, :consistent_read => true).attributes
|
|
146
165
|
@associations.values.each(&:reset)
|
|
147
166
|
self
|
|
148
167
|
end
|
|
@@ -171,14 +190,10 @@ module Dynamoid #:nodoc:
|
|
|
171
190
|
self.send("#{self.class.range_key}=", value)
|
|
172
191
|
end
|
|
173
192
|
|
|
174
|
-
|
|
175
|
-
if range_key = self.class.range_key
|
|
176
|
-
self.send(range_key)
|
|
177
|
-
end
|
|
178
|
-
end
|
|
193
|
+
private
|
|
179
194
|
|
|
180
|
-
def
|
|
181
|
-
self.
|
|
195
|
+
def dumped_range_value
|
|
196
|
+
dump_field(range_value, self.class.attributes[self.class.range_key])
|
|
182
197
|
end
|
|
183
198
|
end
|
|
184
199
|
end
|
data/lib/dynamoid/fields.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
module Dynamoid #:nodoc:
|
|
3
3
|
|
|
4
|
-
# All fields on a Dynamoid::Document must be explicitly defined -- if you have fields in the database that are not
|
|
4
|
+
# All fields on a Dynamoid::Document must be explicitly defined -- if you have fields in the database that are not
|
|
5
5
|
# specified with field, then they will be ignored.
|
|
6
6
|
module Fields
|
|
7
7
|
extend ActiveSupport::Concern
|
|
@@ -14,11 +14,13 @@ module Dynamoid #:nodoc:
|
|
|
14
14
|
self.attributes = {}
|
|
15
15
|
field :created_at, :datetime
|
|
16
16
|
field :updated_at, :datetime
|
|
17
|
+
|
|
18
|
+
field :id #Default primary key
|
|
17
19
|
end
|
|
18
|
-
|
|
20
|
+
|
|
19
21
|
module ClassMethods
|
|
20
|
-
|
|
21
|
-
# Specify a field for a document. Its type determines how it is coerced when read in and out of the datastore:
|
|
22
|
+
|
|
23
|
+
# Specify a field for a document. Its type determines how it is coerced when read in and out of the datastore:
|
|
22
24
|
# default is string, but you can also specify :integer, :float, :set, :array, :datetime, and :serialized.
|
|
23
25
|
#
|
|
24
26
|
# @param [Symbol] name the name of the field
|
|
@@ -28,7 +30,7 @@ module Dynamoid #:nodoc:
|
|
|
28
30
|
# @since 0.2.0
|
|
29
31
|
def field(name, type = :string, options = {})
|
|
30
32
|
named = name.to_s
|
|
31
|
-
self.attributes
|
|
33
|
+
self.attributes = attributes.merge(name => {:type => type}.merge(options))
|
|
32
34
|
|
|
33
35
|
define_method(named) { read_attribute(named) }
|
|
34
36
|
define_method("#{named}?") { !read_attribute(named).nil? }
|
|
@@ -39,8 +41,24 @@ module Dynamoid #:nodoc:
|
|
|
39
41
|
field(name, type)
|
|
40
42
|
self.range_key = name
|
|
41
43
|
end
|
|
44
|
+
|
|
45
|
+
def table(options)
|
|
46
|
+
#a default 'id' column is created when Dynamoid::Document is included
|
|
47
|
+
unless(attributes.has_key? hash_key)
|
|
48
|
+
remove_field :id
|
|
49
|
+
field(hash_key)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def remove_field(field)
|
|
54
|
+
field = field.to_sym
|
|
55
|
+
attributes.delete(field) or raise "No such field"
|
|
56
|
+
remove_method field
|
|
57
|
+
remove_method :"#{field}="
|
|
58
|
+
remove_method :"#{field}?"
|
|
59
|
+
end
|
|
42
60
|
end
|
|
43
|
-
|
|
61
|
+
|
|
44
62
|
# You can access the attributes of an object directly on its attributes method, which is by default an empty hash.
|
|
45
63
|
attr_accessor :attributes
|
|
46
64
|
alias :raw_attributes :attributes
|
|
@@ -80,24 +98,8 @@ module Dynamoid #:nodoc:
|
|
|
80
98
|
#
|
|
81
99
|
# @since 0.2.0
|
|
82
100
|
def update_attributes(attributes)
|
|
83
|
-
attributes.each {|attribute, value| self.write_attribute(attribute, value)}
|
|
84
|
-
|
|
85
|
-
save
|
|
86
|
-
else # update attributes if we have saved.
|
|
87
|
-
# next if self.read_only_attributes.include? attribute.to_s put this back in.
|
|
88
|
-
run_callbacks(:save) do
|
|
89
|
-
update! do |u|
|
|
90
|
-
attributes.each do |attribute, value|
|
|
91
|
-
u.set attribute => dump_field(
|
|
92
|
-
self.read_attribute(attribute),
|
|
93
|
-
self.class.attributes[attribute.to_sym]
|
|
94
|
-
)
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
save
|
|
100
|
-
end
|
|
101
|
+
attributes.each {|attribute, value| self.write_attribute(attribute, value)} unless attributes.nil? || attributes.empty?
|
|
102
|
+
save
|
|
101
103
|
end
|
|
102
104
|
|
|
103
105
|
# Update a single attribute, saving the object afterwards.
|
|
@@ -110,9 +112,9 @@ module Dynamoid #:nodoc:
|
|
|
110
112
|
write_attribute(attribute, value)
|
|
111
113
|
save
|
|
112
114
|
end
|
|
113
|
-
|
|
115
|
+
|
|
114
116
|
private
|
|
115
|
-
|
|
117
|
+
|
|
116
118
|
# Automatically called during the created callback to set the created_at time.
|
|
117
119
|
#
|
|
118
120
|
# @since 0.2.0
|
|
@@ -122,11 +124,15 @@ module Dynamoid #:nodoc:
|
|
|
122
124
|
|
|
123
125
|
# Automatically called during the save callback to set the updated_at time.
|
|
124
126
|
#
|
|
125
|
-
# @since 0.2.0
|
|
127
|
+
# @since 0.2.0
|
|
126
128
|
def set_updated_at
|
|
127
129
|
self.updated_at = DateTime.now
|
|
128
130
|
end
|
|
129
|
-
|
|
131
|
+
|
|
132
|
+
def set_type
|
|
133
|
+
self.type ||= self.class.to_s if self.class.attributes[:type]
|
|
134
|
+
end
|
|
135
|
+
|
|
130
136
|
end
|
|
131
|
-
|
|
132
|
-
end
|
|
137
|
+
|
|
138
|
+
end
|
data/lib/dynamoid/finders.rb
CHANGED
|
@@ -31,19 +31,21 @@ module Dynamoid
|
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
#
|
|
34
|
+
# Return objects found by the given array of ids, either hash keys, or hash/range key combinations using BatchGet.
|
|
35
|
+
# Returns empty array if no results found.
|
|
35
36
|
#
|
|
36
37
|
# @param [Array<ID>] ids
|
|
38
|
+
# @param [Hash] options: Passed to the underlying query.
|
|
37
39
|
#
|
|
38
40
|
# @example
|
|
39
41
|
# find all the user with hash key
|
|
40
42
|
# User.find_all(['1', '2', '3'])
|
|
41
43
|
#
|
|
42
|
-
# find all the tweets using hash key and range key
|
|
43
|
-
# Tweet.find_all([['1', 'red'], ['1', 'green'])
|
|
44
|
-
def find_all(ids)
|
|
44
|
+
# find all the tweets using hash key and range key with consistent read
|
|
45
|
+
# Tweet.find_all([['1', 'red'], ['1', 'green']], :consistent_read => true)
|
|
46
|
+
def find_all(ids, options = {})
|
|
45
47
|
items = Dynamoid::Adapter.read(self.table_name, ids, options)
|
|
46
|
-
items[self.table_name].
|
|
48
|
+
items ? items[self.table_name].map{|i| from_database(i)} : []
|
|
47
49
|
end
|
|
48
50
|
|
|
49
51
|
# Find one object directly by id.
|
data/lib/dynamoid/persistence.rb
CHANGED
|
@@ -13,11 +13,8 @@ module Dynamoid
|
|
|
13
13
|
|
|
14
14
|
module ClassMethods
|
|
15
15
|
|
|
16
|
-
# Returns the name of the table the class is for.
|
|
17
|
-
#
|
|
18
|
-
# @since 0.2.0
|
|
19
16
|
def table_name
|
|
20
|
-
"#{Dynamoid::Config.namespace}_#{options[:name]
|
|
17
|
+
@table_name ||= "#{Dynamoid::Config.namespace}_#{options[:name] || base_class.name.split('::').last.downcase.pluralize}"
|
|
21
18
|
end
|
|
22
19
|
|
|
23
20
|
# Creates a table.
|
|
@@ -57,7 +54,8 @@ module Dynamoid
|
|
|
57
54
|
end
|
|
58
55
|
|
|
59
56
|
def from_database(attrs = {})
|
|
60
|
-
|
|
57
|
+
clazz = attrs[:type] ? obj = attrs[:type].constantize : self
|
|
58
|
+
clazz.new(attrs).tap { |r| r.new_record = false }
|
|
61
59
|
end
|
|
62
60
|
|
|
63
61
|
# Undump an object into a hash, converting each type from a string representation of itself into the type specified by the field.
|
|
@@ -170,10 +168,24 @@ module Dynamoid
|
|
|
170
168
|
self
|
|
171
169
|
end
|
|
172
170
|
|
|
171
|
+
#
|
|
172
|
+
# update!() will increment the lock_version if the table has the column, but will not check it. Thus, a concurrent save will
|
|
173
|
+
# never cause an update! to fail, but an update! may cause a concurrent save to fail.
|
|
174
|
+
#
|
|
175
|
+
#
|
|
173
176
|
def update!(conditions = {}, &block)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
+
run_callbacks(:update) do
|
|
178
|
+
options = range_key ? {:range_key => dump_field(self.read_attribute(range_key), self.class.attributes[range_key])} : {}
|
|
179
|
+
new_attrs = Dynamoid::Adapter.update_item(self.class.table_name, self.hash_key, options.merge(:conditions => conditions)) do |t|
|
|
180
|
+
if(self.class.attributes[:lock_version])
|
|
181
|
+
raise "Optimistic locking cannot be used with Partitioning" if(Dynamoid::Config.partitioning)
|
|
182
|
+
t.add(lock_version: 1)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
yield t
|
|
186
|
+
end
|
|
187
|
+
load(new_attrs)
|
|
188
|
+
end
|
|
177
189
|
end
|
|
178
190
|
|
|
179
191
|
def update(conditions = {}, &block)
|
|
@@ -245,7 +257,7 @@ module Dynamoid
|
|
|
245
257
|
raise ArgumentError, "Unknown type #{options[:type]}"
|
|
246
258
|
end
|
|
247
259
|
end
|
|
248
|
-
|
|
260
|
+
|
|
249
261
|
# Persist the object into the datastore. Assign it an id first if it doesn't have one; then afterwards,
|
|
250
262
|
# save its indexes.
|
|
251
263
|
#
|
|
@@ -253,13 +265,28 @@ module Dynamoid
|
|
|
253
265
|
def persist(conditions = nil)
|
|
254
266
|
run_callbacks(:save) do
|
|
255
267
|
self.hash_key = SecureRandom.uuid if self.hash_key.nil? || self.hash_key.blank?
|
|
268
|
+
|
|
269
|
+
# Add an exists check to prevent overwriting existing records with new ones
|
|
270
|
+
if(new_record?)
|
|
271
|
+
conditions ||= {}
|
|
272
|
+
(conditions[:unless_exists] ||= []) << self.class.hash_key
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# Add an optimistic locking check if the lock_version column exists
|
|
276
|
+
if(self.class.attributes[:lock_version])
|
|
277
|
+
conditions ||= {}
|
|
278
|
+
raise "Optimistic locking cannot be used with Partitioning" if(Dynamoid::Config.partitioning)
|
|
279
|
+
self.lock_version = (lock_version || 0) + 1
|
|
280
|
+
#Uses the original lock_version value from ActiveModel::Dirty in case user changed lock_version manually
|
|
281
|
+
(conditions[:if] ||= {})[:lock_version] = changes[:lock_version][0] if(changes[:lock_version][0])
|
|
282
|
+
end
|
|
283
|
+
|
|
256
284
|
Dynamoid::Adapter.write(self.class.table_name, self.dump, conditions)
|
|
257
285
|
save_indexes
|
|
258
286
|
@new_record = false
|
|
259
287
|
true
|
|
260
288
|
end
|
|
261
289
|
end
|
|
262
|
-
|
|
263
290
|
end
|
|
264
291
|
|
|
265
292
|
end
|
data/spec/app/models/address.rb
CHANGED
|
@@ -10,6 +10,8 @@ class CamelCase
|
|
|
10
10
|
|
|
11
11
|
before_create :doing_before_create
|
|
12
12
|
after_create :doing_after_create
|
|
13
|
+
before_update :doing_before_update
|
|
14
|
+
after_update :doing_after_update
|
|
13
15
|
|
|
14
16
|
private
|
|
15
17
|
|
|
@@ -21,4 +23,12 @@ class CamelCase
|
|
|
21
23
|
true
|
|
22
24
|
end
|
|
23
25
|
|
|
26
|
+
def doing_before_update
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def doing_after_update
|
|
31
|
+
true
|
|
32
|
+
end
|
|
33
|
+
|
|
24
34
|
end
|
|
@@ -50,23 +50,27 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
it 'performs query on a table with a range and selects items in a range' do
|
|
53
|
-
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_value => 0.0..3.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
|
53
|
+
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_value => 0.0..3.0).to_a.should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'performs query on a table with a range and selects items in a range with :select option' do
|
|
57
|
+
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_value => 0.0..3.0, :select => :all).to_a.should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
|
54
58
|
end
|
|
55
59
|
|
|
56
60
|
it 'performs query on a table with a range and selects items greater than' do
|
|
57
|
-
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_greater_than => 1.0).should =~ [{:id => '1', :range => BigDecimal.new(3)}]
|
|
61
|
+
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_greater_than => 1.0).to_a.should =~ [{:id => '1', :range => BigDecimal.new(3)}]
|
|
58
62
|
end
|
|
59
63
|
|
|
60
64
|
it 'performs query on a table with a range and selects items less than' do
|
|
61
|
-
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_less_than => 2.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}]
|
|
65
|
+
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_less_than => 2.0).to_a.should =~ [{:id => '1', :range => BigDecimal.new(1)}]
|
|
62
66
|
end
|
|
63
67
|
|
|
64
68
|
it 'performs query on a table with a range and selects items gte' do
|
|
65
|
-
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_gte => 1.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
|
69
|
+
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_gte => 1.0).to_a.should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
|
66
70
|
end
|
|
67
71
|
|
|
68
72
|
it 'performs query on a table with a range and selects items lte' do
|
|
69
|
-
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_lte => 3.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
|
73
|
+
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_lte => 3.0).to_a.should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
|
70
74
|
end
|
|
71
75
|
end
|
|
72
76
|
|
|
@@ -85,7 +89,7 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
|
85
89
|
end
|
|
86
90
|
|
|
87
91
|
it 'performs query on a table with a range and selects items less than that is in the correct order, scan_index_forward true' do
|
|
88
|
-
query = Dynamoid::Adapter.query(test_table4, :hash_value => '1', :range_greater_than => 0, :scan_index_forward => true)
|
|
92
|
+
query = Dynamoid::Adapter.query(test_table4, :hash_value => '1', :range_greater_than => 0, :scan_index_forward => true).to_a
|
|
89
93
|
query[0].should == {:id => '1', :order => 1, :range => BigDecimal.new(1)}
|
|
90
94
|
query[1].should == {:id => '1', :order => 2, :range => BigDecimal.new(2)}
|
|
91
95
|
query[2].should == {:id => '1', :order => 3, :range => BigDecimal.new(3)}
|
|
@@ -95,7 +99,7 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
|
95
99
|
end
|
|
96
100
|
|
|
97
101
|
it 'performs query on a table with a range and selects items less than that is in the correct order, scan_index_forward false' do
|
|
98
|
-
query = Dynamoid::Adapter.query(test_table4, :hash_value => '1', :range_greater_than => 0, :scan_index_forward => false)
|
|
102
|
+
query = Dynamoid::Adapter.query(test_table4, :hash_value => '1', :range_greater_than => 0, :scan_index_forward => false).to_a
|
|
99
103
|
query[5].should == {:id => '1', :order => 1, :range => BigDecimal.new(1)}
|
|
100
104
|
query[4].should == {:id => '1', :order => 2, :range => BigDecimal.new(2)}
|
|
101
105
|
query[3].should == {:id => '1', :order => 3, :range => BigDecimal.new(3)}
|
|
@@ -157,6 +161,11 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
|
157
161
|
end
|
|
158
162
|
|
|
159
163
|
# BatchGetItem
|
|
164
|
+
it 'passes options to underlying BatchGet call' do
|
|
165
|
+
AWS::DynamoDB::BatchGet.any_instance.expects(:table).with(test_table1, :all, ['1', '2'], :consistent_read => true)
|
|
166
|
+
described_class.batch_get_item({test_table1 => ['1', '2']}, :consistent_read => true)
|
|
167
|
+
end
|
|
168
|
+
|
|
160
169
|
it "performs BatchGetItem with singular keys" do
|
|
161
170
|
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
|
162
171
|
Dynamoid::Adapter.put_item(test_table2, {:id => '1', :name => 'Justin'})
|
|
@@ -259,14 +268,14 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
|
259
268
|
it 'performs query on a table and returns items' do
|
|
260
269
|
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
|
261
270
|
|
|
262
|
-
Dynamoid::Adapter.query(test_table1, :hash_value => '1').should == { :id=> '1', :name=>"Josh" }
|
|
271
|
+
Dynamoid::Adapter.query(test_table1, :hash_value => '1').first.should == { :id=> '1', :name=>"Josh" }
|
|
263
272
|
end
|
|
264
273
|
|
|
265
274
|
it 'performs query on a table and returns items if there are multiple items' do
|
|
266
275
|
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
|
267
276
|
Dynamoid::Adapter.put_item(test_table1, {:id => '2', :name => 'Justin'})
|
|
268
277
|
|
|
269
|
-
Dynamoid::Adapter.query(test_table1, :hash_value => '1').should == { :id=> '1', :name=>"Josh" }
|
|
278
|
+
Dynamoid::Adapter.query(test_table1, :hash_value => '1').first.should == { :id=> '1', :name=>"Josh" }
|
|
270
279
|
end
|
|
271
280
|
|
|
272
281
|
it_behaves_like 'range queries'
|
|
@@ -275,14 +284,14 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
|
275
284
|
it 'performs scan on a table and returns items' do
|
|
276
285
|
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
|
277
286
|
|
|
278
|
-
Dynamoid::Adapter.scan(test_table1, :name => 'Josh').should == [{ :id=> '1', :name=>"Josh" }]
|
|
287
|
+
Dynamoid::Adapter.scan(test_table1, :name => 'Josh').to_a.should == [{ :id=> '1', :name=>"Josh" }]
|
|
279
288
|
end
|
|
280
289
|
|
|
281
290
|
it 'performs scan on a table and returns items if there are multiple items but only one match' do
|
|
282
291
|
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
|
283
292
|
Dynamoid::Adapter.put_item(test_table1, {:id => '2', :name => 'Justin'})
|
|
284
293
|
|
|
285
|
-
Dynamoid::Adapter.scan(test_table1, :name => 'Josh').should == [{ :id=> '1', :name=>"Josh" }]
|
|
294
|
+
Dynamoid::Adapter.scan(test_table1, :name => 'Josh').to_a.should == [{ :id=> '1', :name=>"Josh" }]
|
|
286
295
|
end
|
|
287
296
|
|
|
288
297
|
it 'performs scan on a table and returns multiple items if there are multiple matches' do
|