ocean-dynamo 0.2.2 → 0.2.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 38c9f3db161b07ef4486141afad09f05af00b752
4
- data.tar.gz: 92a73810cedf7aceb64e31fde8582afd2e56fe18
3
+ metadata.gz: 8eaf6828f75761ed94d2acbfa5a28383b892c2d3
4
+ data.tar.gz: 9cc793dae4769417a4b87949f6c8a183679f6bc8
5
5
  SHA512:
6
- metadata.gz: 0116191369abb7f9124034727ea50dc32995cfbebd55a4c030ded15a963c3f5fd7a1ed244ce85971606af4e329cf78f942b84a2d81e270af94bc4eddd135c3b1
7
- data.tar.gz: 95861f8c29cd86c2018633549c21ce45b61adf65e8c2742496da04321ef6e2dd40447b8438c7d70ce36c40b35bcc87874bb65a50279ae835ef0f9a4d84b7cd5b
6
+ metadata.gz: ff59c0d44b7c45cdd07702f199b6816f1daedfa9998d0ffe8c6e75f8bff094c46ab55a144e81a57932d8775e758d0af0e378b922815959144294c715e53c3a40
7
+ data.tar.gz: ea2b09b9afa20d4a0cf0e6e6d0a7e51b739e0674dd06f9fbbf877a903c31a96e3311e00dad45578948b5a0c5601312f65ceb15539de33c73310a1c09f054a49c
@@ -72,7 +72,22 @@ Sets are represented as arrays and may not contain duplicates and may not be emp
72
72
  All attributes except the :string type can take the value nil. Storing nil for a string
73
73
  value will return the empty string, "".
74
74
 
75
- Also, dynamo_schema takes args and many options. Detailed documentation is forthcoming.
75
+ Also, dynamo_schema takes args and many options. Here's the full syntax:
76
+
77
+ dynamo_schema(
78
+ table_hash_key = :uuid,
79
+ table_range_key = nil,
80
+ table_name: compute_table_name,
81
+ table_name_prefix: nil,
82
+ table_name_suffix: nil,
83
+ read_capacity_units: 10,
84
+ write_capacity_units: 5,
85
+ connect: :late,
86
+ create: false,
87
+ locking: :lock_version,
88
+ timestamps: [:created_at, :updated_at],
89
+ &block
90
+ )
76
91
 
77
92
  At the moment, OceanDynamo is fully usable as an ActiveModel and can be used by Rails
78
93
  controllers. Furthermore, OceanDynamo implements much of the infrastructure of ActiveRecord;
@@ -15,10 +15,4 @@ require "ocean-dynamo/persistence"
15
15
 
16
16
  module OceanDynamo
17
17
 
18
- DEFAULT_ATTRIBUTES = [
19
- [:created_at, :datetime],
20
- [:updated_at, :datetime],
21
- [:lock_version, :integer, default: 0]
22
- ]
23
-
24
18
  end
@@ -16,9 +16,7 @@ module OceanDynamo
16
16
  write_attribute(name, evaluate_default(md[:default], md[:type]))
17
17
  self.class.class_eval "def #{name}; read_attribute('#{name.to_s}'); end"
18
18
  self.class.class_eval "def #{name}=(value); write_attribute('#{name.to_s}', value); end"
19
- if fields[name][:type] == :boolean
20
- self.class.class_eval "def #{name}?; read_attribute('#{name.to_s}'); end"
21
- end
19
+ self.class.class_eval "def #{name}?; read_attribute('#{name.to_s}').present?; end"
22
20
  end
23
21
  @dynamo_item = nil
24
22
  @destroyed = false
@@ -91,9 +89,7 @@ module OceanDynamo
91
89
  # raise ActiveModel::ForbiddenAttributesError
92
90
  # end
93
91
  # end
94
- values.each do |k, v|
95
- _assign_attribute(k, v)
96
- end
92
+ values.each { |k, v| _assign_attribute(k, v) }
97
93
  end
98
94
 
99
95
 
@@ -197,11 +193,11 @@ module OceanDynamo
197
193
 
198
194
  def _assign_attribute(k, v) # :nodoc:
199
195
  public_send("#{k}=", v)
200
- rescue ActiveModel::NoMethodError
196
+ rescue NoMethodError
201
197
  if respond_to?("#{k}=")
202
198
  raise
203
199
  else
204
- raise ActiveModel::UnknownAttributeError, "unknown attribute: #{k}"
200
+ raise UnknownAttributeError, "unknown attribute: #{k}"
205
201
  end
206
202
  end
207
203
 
@@ -4,5 +4,35 @@ module OceanDynamo
4
4
  include ActiveModel::Model
5
5
  include ActiveModel::Validations::Callbacks
6
6
 
7
+
8
+ def ==(comparison_object)
9
+ super ||
10
+ comparison_object.instance_of?(self.class) &&
11
+ id.present? &&
12
+ comparison_object.id == id
13
+ end
14
+ alias :eql? :==
15
+
16
+
17
+ # Clone and freeze the attributes hash such that associations are still
18
+ # accessible, even on destroyed records, but cloned models will not be
19
+ # frozen.
20
+ def freeze
21
+ @attributes = @attributes.clone.freeze
22
+ self
23
+ end
24
+
25
+ # Returns +true+ if the attributes hash has been frozen.
26
+ def frozen?
27
+ @attributes.frozen?
28
+ end
29
+
30
+ # Allows sort on objects
31
+ def <=>(other_object)
32
+ if other_object.is_a?(self.class)
33
+ self.to_key <=> other_object.to_key
34
+ end
35
+ end
36
+
7
37
  end
8
38
  end
@@ -43,5 +43,11 @@ module OceanDynamo
43
43
  class_attribute :table_create_policy, instance_writer: false
44
44
  self.table_create_policy = false
45
45
 
46
+ class_attribute :lock_attribute, instance_writer: false
47
+ self.lock_attribute = :lock_version
48
+
49
+ class_attribute :timestamp_attributes, instance_writer: false
50
+ self.timestamp_attributes = [:created_at, :updated_at]
51
+
46
52
  end
47
53
  end
@@ -108,9 +108,7 @@ module OceanDynamo
108
108
  run_callbacks :create do
109
109
  k = read_attribute(table_hash_key)
110
110
  write_attribute(table_hash_key, SecureRandom.uuid) if k == "" || k == nil
111
- t = Time.zone.now
112
- self.created_at ||= t
113
- self.updated_at ||= t
111
+ set_timestamps
114
112
  dynamo_persist
115
113
  true
116
114
  end
@@ -124,8 +122,8 @@ module OceanDynamo
124
122
  run_callbacks :commit do
125
123
  run_callbacks :save do
126
124
  run_callbacks :update do
127
- self.updated_at = Time.zone.now
128
- dynamo_persist
125
+ set_timestamps
126
+ dynamo_persist(lock: lock_attribute)
129
127
  true
130
128
  end
131
129
  end
@@ -148,12 +146,11 @@ module OceanDynamo
148
146
 
149
147
 
150
148
  def delete
151
- _connect_late?
152
149
  if persisted?
153
- @dynamo_item.delete
150
+ dynamo_delete(lock: lock_attribute)
154
151
  end
152
+ freeze
155
153
  @destroyed = true
156
- #freeze
157
154
  end
158
155
 
159
156
 
@@ -167,17 +164,16 @@ module OceanDynamo
167
164
 
168
165
  def touch(name=nil)
169
166
  raise DynamoError, "can not touch on a new record object" unless persisted?
170
- _connect_late?
167
+ _late_connect?
171
168
  run_callbacks :touch do
172
- attrs = ['updated_at']
173
- attrs << name if name
174
- t = Time.zone.now
175
- attrs.each { |k| write_attribute k, t }
176
- # TODO: handle lock_version
177
- dynamo_item.attributes.update do |u|
178
- attrs.each do |k|
179
- u.set(k => serialize_attribute(k, t))
169
+ begin
170
+ dynamo_item.attributes.update(_handle_locking) do |u|
171
+ set_timestamps(name).each do |k|
172
+ u.set(k => serialize_attribute(k, read_attribute(k)))
173
+ end
180
174
  end
175
+ rescue AWS::DynamoDB::Errors::ConditionalCheckFailedException
176
+ raise OceanDynamo::StaleObjectError
181
177
  end
182
178
  self
183
179
  end
@@ -187,7 +183,7 @@ module OceanDynamo
187
183
 
188
184
  protected
189
185
 
190
- def self._connect_late?
186
+ def self._late_connect?
191
187
  return false if table_connected
192
188
  return false unless table_connect_policy
193
189
  establish_db_connection
@@ -195,8 +191,8 @@ module OceanDynamo
195
191
  end
196
192
 
197
193
 
198
- def _connect_late?
199
- self.class._connect_late?
194
+ def _late_connect?
195
+ self.class._late_connect?
200
196
  end
201
197
 
202
198
 
@@ -205,16 +201,33 @@ module OceanDynamo
205
201
  end
206
202
 
207
203
 
208
- def dynamo_persist # :nodoc:
209
- _connect_late?
210
- @dynamo_item = dynamo_items.put(serialized_attributes)
204
+ def dynamo_persist(lock: nil) # :nodoc:
205
+ _late_connect?
206
+ begin
207
+ options = _handle_locking(lock)
208
+ @dynamo_item = dynamo_items.put(serialized_attributes, options)
209
+ rescue AWS::DynamoDB::Errors::ConditionalCheckFailedException
210
+ raise OceanDynamo::StaleObjectError
211
+ end
212
+
211
213
  @new_record = false
212
214
  true
213
215
  end
214
216
 
215
217
 
218
+ def dynamo_delete(lock: nil)
219
+ _late_connect?
220
+ begin
221
+ options = _handle_locking(lock)
222
+ @dynamo_item.delete(options)
223
+ rescue AWS::DynamoDB::Errors::ConditionalCheckFailedException
224
+ raise OceanDynamo::StaleObjectError
225
+ end
226
+ end
227
+
228
+
216
229
  def dynamo_unpersist(item, consistent) # :nodoc:
217
- _connect_late?
230
+ _late_connect?
218
231
  @dynamo_item = item
219
232
  @new_record = false
220
233
  assign_attributes(_dynamo_read_attributes(consistent_read: consistent))
@@ -237,5 +250,34 @@ module OceanDynamo
237
250
  end
238
251
 
239
252
 
253
+ def set_timestamps(name=nil)
254
+ attrs = []
255
+ attrs << timestamp_attributes[0] if timestamp_attributes && new_record?
256
+ attrs << timestamp_attributes[1] if timestamp_attributes
257
+ attrs << name if name
258
+ _set_timestamp_attributes(attrs)
259
+ attrs
260
+ end
261
+
262
+
263
+ def _set_timestamp_attributes(attrs)
264
+ return if attrs.blank?
265
+ t = Time.zone.now
266
+ attrs.each { |a| write_attribute a, t }
267
+ t
268
+ end
269
+
270
+
271
+ def _handle_locking(lock=lock_attribute)
272
+ _late_connect?
273
+ if lock
274
+ current_v = read_attribute(lock)
275
+ write_attribute(lock, current_v+1) unless frozen?
276
+ {if: {lock => current_v}}
277
+ else
278
+ {}
279
+ end
280
+ end
281
+
240
282
  end
241
283
  end
@@ -2,15 +2,22 @@ module OceanDynamo
2
2
  class Base
3
3
 
4
4
  def self.find(hash, range=nil, consistent: false)
5
- _connect_late?
5
+ _late_connect?
6
6
  item = dynamo_items[hash, range]
7
7
  raise RecordNotFound unless item.exists?
8
8
  new.send(:dynamo_unpersist, item, consistent)
9
9
  end
10
10
 
11
11
 
12
+ def self.find_by_key(*args)
13
+ find(*args)
14
+ rescue RecordNotFound
15
+ nil
16
+ end
17
+
18
+
12
19
  def self.count
13
- _connect_late?
20
+ _late_connect?
14
21
  dynamo_table.item_count || -1 # The || -1 is for fake_dynamo specs.
15
22
  end
16
23
 
@@ -2,7 +2,8 @@ module OceanDynamo
2
2
  class Base
3
3
 
4
4
 
5
- def self.dynamo_schema(table_hash_key=:uuid, table_range_key=nil,
5
+ def self.dynamo_schema(table_hash_key=:uuid,
6
+ table_range_key=nil,
6
7
  table_name: compute_table_name,
7
8
  table_name_prefix: nil,
8
9
  table_name_suffix: nil,
@@ -10,6 +11,8 @@ module OceanDynamo
10
11
  write_capacity_units: 5,
11
12
  connect: :late,
12
13
  create: false,
14
+ locking: :lock_version,
15
+ timestamps: [:created_at, :updated_at],
13
16
  &block)
14
17
  # Set class vars
15
18
  self.dynamo_client = nil
@@ -25,10 +28,13 @@ module OceanDynamo
25
28
  self.table_name_suffix = table_name_suffix
26
29
  self.table_read_capacity_units = read_capacity_units
27
30
  self.table_write_capacity_units = write_capacity_units
31
+ self.lock_attribute = locking
32
+ self.timestamp_attributes = timestamps
28
33
  # Init
29
34
  self.fields = HashWithIndifferentAccess.new
30
35
  attribute table_hash_key, :string, default: ''
31
- DEFAULT_ATTRIBUTES.each { |name, type, **pairs| attribute name, type, **pairs }
36
+ timestamp_attributes.each { |name| attribute name, :datetime } if timestamp_attributes
37
+ attribute lock_attribute, :integer, default: 0
32
38
  block.call
33
39
  # Connect to AWS
34
40
  establish_db_connection if connect == true
@@ -38,7 +38,6 @@ module OceanDynamo
38
38
  else
39
39
  raise UnknownTableStatus.new("Unknown DynamoDB table status '#{dynamo_table.status}'")
40
40
  end
41
- sleep 1
42
41
  end
43
42
  end
44
43
 
@@ -1,3 +1,3 @@
1
1
  module OceanDynamo
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.3"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ocean-dynamo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Bengtson