dynamini 1.10.2 → 1.10.4

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: 8248aff788be3cda0502be12ccc3768cdf4fc3d4
4
- data.tar.gz: 860898330266f91bce5a52d1a4193edce7f64e07
3
+ metadata.gz: 77216b9785381180fbe3c6fb26fa9068b1875205
4
+ data.tar.gz: 377ad37843a21e5fd5cd8cb286df9d8897845bcd
5
5
  SHA512:
6
- metadata.gz: 9dc5d37aefc854902b172a271a2b80b5ab22310f507ad2f5c234a60bb81d00b5a2f0a69bdd2ef8fe6c426830fe06d9f985f67d51db62b83a98d4eb8d6a956bee
7
- data.tar.gz: 9efb1fd623f05c5eba81660ea04e46873d222634b5aca361b69205e75eccb1ad2c1fef2d53cf44555514eb5eae68aa559aec1ddebdc2a03dd53a49219a6c86ad
6
+ metadata.gz: 5357921d66fed581b203a729210a8e9a94c30110133f561c03ff1ed44382069926797e8b77ffbd3319b6471f04e7771ee301fdc0bbec24710ad7353fa1fb05c8
7
+ data.tar.gz: acf65739006b37541d869bd48bacf44bf6c911a1d800a7e79be4f74a09bd6e46634dd0b75f65b0e05babd7c5781519626796950dadfe65473a6df1ebe0dd4af6
@@ -1,17 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dynamini (1.10.2)
4
+ dynamini (1.10.4)
5
5
  activemodel (>= 3, < 5.0)
6
6
  aws-sdk (~> 2)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activemodel (4.2.5)
12
- activesupport (= 4.2.5)
11
+ activemodel (4.2.4)
12
+ activesupport (= 4.2.4)
13
13
  builder (~> 3.1)
14
- activesupport (4.2.5)
14
+ activesupport (4.2.4)
15
15
  i18n (~> 0.7)
16
16
  json (~> 1.7, >= 1.7.7)
17
17
  minitest (~> 5.1)
@@ -56,7 +56,7 @@ GEM
56
56
  rb-inotify (>= 0.9)
57
57
  lumberjack (1.0.9)
58
58
  method_source (0.8.2)
59
- minitest (5.8.3)
59
+ minitest (5.8.2)
60
60
  nenv (0.2.0)
61
61
  notiffany (0.0.8)
62
62
  nenv (~> 0.1)
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'dynamini'
3
- s.version = '1.10.2'
4
- s.date = '2015-01-07'
3
+ s.version = '1.10.4'
4
+ s.date = '2015-01-11'
5
5
  s.summary = 'DynamoDB interface'
6
6
  s.description = 'Lightweight DynamoDB interface gem designed as
7
7
  a drop-in replacement for ActiveRecord.
@@ -1,5 +1,9 @@
1
1
  require_relative 'batch_operations'
2
2
  require_relative 'querying'
3
+ require_relative 'client_interface'
4
+ require_relative 'dirty'
5
+ require_relative 'increment'
6
+ require_relative 'type_handler'
3
7
 
4
8
  module Dynamini
5
9
  # Core db interface class.
@@ -7,38 +11,22 @@ module Dynamini
7
11
  include ActiveModel::Validations
8
12
  extend Dynamini::BatchOperations
9
13
  extend Dynamini::Querying
14
+ include Dynamini::ClientInterface
15
+ include Dynamini::Dirty
16
+ include Dynamini::Increment
17
+ include Dynamini::TypeHandler
10
18
 
11
- attr_reader :attributes
12
19
 
20
+ attr_reader :attributes
13
21
  class_attribute :handles
14
22
 
15
23
  self.handles = {
16
- created_at: { format: :time, options: {} },
17
- updated_at: { format: :time, options: {} }
18
- }
19
-
20
- GETTER_PROCS = {
21
- integer: proc { |v| v.to_i },
22
- date: proc { |v| v.is_a?(Date) ? v : Time.at(v).to_date },
23
- time: proc { |v| Time.at(v.to_f) },
24
- float: proc { |v| v.to_f },
25
- symbol: proc { |v| v.to_sym },
26
- string: proc { |v| v },
27
- boolean: proc { |v| v }
28
- }
29
-
30
- SETTER_PROCS = {
31
- integer: proc { |v| v.to_i },
32
- time: proc { |v| (v.is_a?(Date) ? v.to_time : v).to_f },
33
- float: proc { |v| v.to_f },
34
- symbol: proc { |v| v.to_s },
35
- string: proc { |v| v },
36
- boolean: proc { |v| v },
37
- date: proc { |v| v.to_time.to_f }
24
+ created_at: { format: :time, options: {} },
25
+ updated_at: { format: :time, options: {} }
38
26
  }
39
27
 
40
28
  class << self
41
- attr_writer :in_memory
29
+
42
30
  attr_reader :range_key
43
31
 
44
32
  def table_name
@@ -57,33 +45,10 @@ module Dynamini
57
45
  @range_key = key
58
46
  end
59
47
 
60
- def handle(column, format_class, options = {})
61
- self.handles = self.handles.merge(column => { format: format_class, options: options })
62
-
63
- define_handled_getter(column, format_class, options)
64
- define_handled_setter(column, format_class)
65
- end
66
-
67
48
  def hash_key
68
49
  @hash_key || :id
69
50
  end
70
51
 
71
- def in_memory
72
- @in_memory || false
73
- end
74
-
75
- def client
76
- if in_memory
77
- @client ||= Dynamini::TestClient.new(hash_key, range_key)
78
- else
79
- @client ||= Aws::DynamoDB::Client.new(
80
- region: Dynamini.configuration.region,
81
- access_key_id: Dynamini.configuration.access_key_id,
82
- secret_access_key: Dynamini.configuration.secret_access_key
83
- )
84
- end
85
- end
86
-
87
52
  def create(attributes, options = {})
88
53
  model = new(attributes, true)
89
54
  model if model.save(options)
@@ -110,15 +75,6 @@ module Dynamini
110
75
  [self.class.hash_key, self.class.range_key]
111
76
  end
112
77
 
113
- def changes
114
- @changes.delete_if { |attr, value| keys.include?(attr) }
115
- .stringify_keys
116
- end
117
-
118
- def changed
119
- changes.keys.map(&:to_s)
120
- end
121
-
122
78
  def ==(other)
123
79
  hash_key == other.hash_key if other.is_a?(self.class)
124
80
  end
@@ -165,23 +121,11 @@ module Dynamini
165
121
  end
166
122
  end
167
123
 
168
- def increment!(attributes, opts = {})
169
- attributes.each do |attr, value|
170
- validate_incrementable_attribute(attr, value)
171
- end
172
- increment_to_dynamo(attributes, opts)
173
- end
174
-
175
124
  def delete
176
125
  delete_from_dynamo
177
126
  self
178
127
  end
179
128
 
180
-
181
- def new_record?
182
- @new_record
183
- end
184
-
185
129
  private
186
130
 
187
131
  def trigger_save(options = {})
@@ -203,39 +147,6 @@ module Dynamini
203
147
  self.created_at = Time.now.to_f if new_record?
204
148
  end
205
149
 
206
- def save_to_dynamo
207
- self.class.client.update_item(
208
- table_name: self.class.table_name,
209
- key: key,
210
- attribute_updates: attribute_updates
211
- )
212
- end
213
-
214
- def touch_to_dynamo
215
- self.class.client.update_item(
216
- table_name: self.class.table_name,
217
- key: key,
218
- attribute_updates:
219
- { updated_at:
220
- { value: Time.now.to_f,
221
- action: 'PUT'
222
- }
223
- }
224
- )
225
- end
226
-
227
- def delete_from_dynamo
228
- self.class.client.delete_item(table_name: self.class.table_name, key: key)
229
- end
230
-
231
- def increment_to_dynamo(attributes, opts = {})
232
- self.class.client.update_item(
233
- table_name: self.class.table_name,
234
- key: key,
235
- attribute_updates: increment_updates(attributes, opts)
236
- )
237
- end
238
-
239
150
  def key
240
151
  key_hash = { self.class.hash_key => @attributes[self.class.hash_key] }
241
152
  key_hash[self.class.range_key] = @attributes[self.class.range_key] if self.class.range_key
@@ -256,33 +167,6 @@ module Dynamini
256
167
  end
257
168
  end
258
169
 
259
- def increment_updates(attributes, opts = {})
260
- updates = {}
261
- attributes.each do |attr,value|
262
- updates[attr] = { value: value, action: 'ADD' }
263
- end
264
- updates[:updated_at] = { value: Time.now.to_f, action: 'PUT' } unless opts[:skip_timestamps]
265
- updates[:created_at] = { value: Time.now.to_f, action: 'PUT' } unless @attributes[:created_at]
266
- updates.stringify_keys
267
- end
268
-
269
- def validate_incrementable_attribute(attribute, value)
270
- if value.is_a?(Integer) || value.is_a?(Float)
271
- current_value = read_attribute(attribute)
272
- unless current_value.nil? || current_value.is_a?(Integer) || current_value.is_a?(Float) || current_value.is_a?(BigDecimal)
273
- fail StandardError, "Cannot increment a non-numeric non-nil value:
274
- #{attribute} is currently #{current_value}, a #{current_value.class}."
275
- end
276
- else
277
- fail StandardError, "You cannot increment an attribute by a
278
- non-numeric value: #{value}"
279
- end
280
- end
281
-
282
- def clear_changes
283
- @changes = Hash.new { |hash, key| hash[key] = Array.new(2) }
284
- end
285
-
286
170
  def method_missing(name, *args, &block)
287
171
  if write_method?(name)
288
172
  write_attribute(attribute_name(name), args.first)
@@ -307,29 +191,6 @@ module Dynamini
307
191
  name =~ /^([a-zA-Z][-_\w]*)=.*$/
308
192
  end
309
193
 
310
- def was_method?(name)
311
- method_name = name.to_s
312
- read_method?(method_name) && method_name.end_with?('_was')
313
- end
314
-
315
- def self.define_handled_getter(column, format_class, options = {})
316
- proc = GETTER_PROCS[format_class]
317
- fail 'Unsupported data type: ' + format_class.to_s if proc.nil?
318
-
319
- define_method(column) do
320
- read_attribute(column)
321
- end
322
- end
323
-
324
- def self.define_handled_setter(column, format_class)
325
- method_name = (column.to_s + '=')
326
- proc = SETTER_PROCS[format_class]
327
- fail 'Unsupported data type: ' + format_class.to_s if proc.nil?
328
- define_method(method_name) do |value|
329
- write_attribute(column, value)
330
- end
331
- end
332
-
333
194
  def respond_to_missing?(name, include_private = false)
334
195
  @attributes.keys.include?(name) || write_method?(name) || was_method?(name) || super
335
196
  end
@@ -343,10 +204,6 @@ module Dynamini
343
204
  record_change(attribute, new_value, old_value) if change && new_value != old_value
344
205
  end
345
206
 
346
- def record_change(attribute, new_value, old_value)
347
- @changes[attribute] = [old_value, new_value]
348
- end
349
-
350
207
  def read_attribute(name)
351
208
  value = @attributes[name]
352
209
  if (handle = handles[name.to_sym])
@@ -360,20 +217,5 @@ module Dynamini
360
217
  callback = procs[handle[:format]]
361
218
  value.is_a?(Array) ? value.map { |e| callback.call(e) } : callback.call(value)
362
219
  end
363
-
364
- def __was(name)
365
- attr_name = name[0..-5].to_sym
366
- raise ArgumentError unless (@attributes[attr_name] || handles[attr_name])
367
- @changes[attr_name].compact.present? ? @changes[attr_name][0] : read_attribute(attr_name)
368
- end
369
-
370
- def handles
371
- self.class.handles
372
- end
373
-
374
- def self.range_is_numeric?
375
- handles[@range_key] && [:integer, :time, :float, :date].include?(handles[@range_key][:format])
376
- end
377
-
378
220
  end
379
221
  end
@@ -0,0 +1,61 @@
1
+ module Dynamini
2
+ module ClientInterface
3
+ module ClassMethods
4
+
5
+ attr_writer :in_memory
6
+
7
+ def client
8
+ if in_memory
9
+ @client ||= Dynamini::TestClient.new(hash_key, range_key)
10
+ else
11
+ @client ||= Aws::DynamoDB::Client.new(
12
+ region: Dynamini.configuration.region,
13
+ access_key_id: Dynamini.configuration.access_key_id,
14
+ secret_access_key: Dynamini.configuration.secret_access_key
15
+ )
16
+ end
17
+ end
18
+
19
+ def in_memory
20
+ @in_memory || false
21
+ end
22
+ end
23
+
24
+ def save_to_dynamo
25
+ self.class.client.update_item(
26
+ table_name: self.class.table_name,
27
+ key: key,
28
+ attribute_updates: attribute_updates
29
+ )
30
+ end
31
+
32
+ def touch_to_dynamo
33
+ self.class.client.update_item(
34
+ table_name: self.class.table_name,
35
+ key: key,
36
+ attribute_updates:
37
+ { updated_at:
38
+ { value: Time.now.to_f,
39
+ action: 'PUT'
40
+ }
41
+ }
42
+ )
43
+ end
44
+
45
+ def delete_from_dynamo
46
+ self.class.client.delete_item(table_name: self.class.table_name, key: key)
47
+ end
48
+
49
+ def increment_to_dynamo(attributes, opts = {})
50
+ self.class.client.update_item(
51
+ table_name: self.class.table_name,
52
+ key: key,
53
+ attribute_updates: increment_updates(attributes, opts)
54
+ )
55
+ end
56
+
57
+ def self.included(base)
58
+ base.extend ClassMethods
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,38 @@
1
+ module Dynamini
2
+ module Dirty
3
+
4
+ def changes
5
+ @changes.delete_if { |attr, _value| keys.include?(attr) }
6
+ .stringify_keys
7
+ end
8
+
9
+ def changed
10
+ changes.keys.map(&:to_s)
11
+ end
12
+
13
+ def new_record?
14
+ @new_record
15
+ end
16
+
17
+ private
18
+
19
+ def record_change(attribute, new_value, old_value)
20
+ @changes[attribute] = [old_value, new_value]
21
+ end
22
+
23
+ def clear_changes
24
+ @changes = Hash.new { |hash, key| hash[key] = Array.new(2) }
25
+ end
26
+
27
+ def was_method?(name)
28
+ method_name = name.to_s
29
+ read_method?(method_name) && method_name.end_with?('_was')
30
+ end
31
+
32
+ def __was(name)
33
+ attr_name = name[0..-5].to_sym
34
+ raise ArgumentError unless (@attributes[attr_name] || handles[attr_name])
35
+ @changes[attr_name].compact.present? ? @changes[attr_name][0] : read_attribute(attr_name)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,44 @@
1
+ module Dynamini
2
+ module Increment
3
+
4
+ def increment!(attributes, opts = {})
5
+ attributes.each do |attr, value|
6
+ validate_incrementable_attribute(attr, value)
7
+ end
8
+ increment_to_dynamo(attributes, opts)
9
+ end
10
+
11
+ private
12
+
13
+ def increment_updates(attributes, opts = {})
14
+ updates = {}
15
+ attributes.each do |attr,value|
16
+ updates[attr] = { value: value, action: 'ADD' }
17
+ end
18
+ updates[:updated_at] = { value: Time.now.to_f, action: 'PUT' } unless opts[:skip_timestamps]
19
+ updates[:created_at] = { value: Time.now.to_f, action: 'PUT' } unless @attributes[:created_at]
20
+ updates.stringify_keys
21
+ end
22
+
23
+ def validate_incrementable_attribute(attribute, value)
24
+ validate_new_increment_value(value)
25
+ validate_current_increment_value(attribute )
26
+ end
27
+
28
+ def validate_new_increment_value(value)
29
+ unless value.is_a?(Integer) || value.is_a?(Float)
30
+ fail StandardError, "You cannot increment an attribute by a
31
+ non-numeric value: #{value}"
32
+ end
33
+ end
34
+
35
+ def validate_current_increment_value(attribute)
36
+ current_value = read_attribute(attribute)
37
+ unless current_value.nil? || current_value.is_a?(Integer) || current_value.is_a?(Float) || current_value.is_a?(BigDecimal)
38
+ fail StandardError, "Cannot increment a non-numeric non-nil value:
39
+ #{attribute} is currently #{current_value}, a #{current_value.class}."
40
+ end
41
+ end
42
+
43
+ end
44
+ end