dynamini 1.10.2 → 1.10.4

Sign up to get free protection for your applications and to get access to all the features.
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