dynamini 1.5.2 → 1.5.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 +4 -4
- data/lib/dynamini/base.rb +88 -64
- data/lib/dynamini/configuration.rb +2 -1
- data/lib/dynamini/test_client.rb +12 -9
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e3b7806d587712702fe4d97bfa6e61c30e31227
|
4
|
+
data.tar.gz: d9420a6dded6bdeb3116abc6498afff11a825c5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f66f26a56d22e788797901d058183a087909e46545bfb3cc09ee2db0f23d5c351dbd472d5a6a373540925fc07f65ca57826dd57606585059f780f11f39b5529
|
7
|
+
data.tar.gz: a239e9829dda149d4a73e981b9d15eeee8d9281d70d83ed97620053259f099ca5d1cb3d807174833fde6ff910cf161021c9cfd7df6a5d33284a1177709ae0f3a
|
data/lib/dynamini/base.rb
CHANGED
@@ -1,26 +1,27 @@
|
|
1
1
|
module Dynamini
|
2
|
+
# Core db interface class.
|
2
3
|
class Base
|
3
4
|
include ActiveModel::Validations
|
4
5
|
attr_reader :attributes
|
5
6
|
|
6
7
|
BATCH_SIZE = 25
|
7
8
|
GETTER_PROCS = {
|
8
|
-
integer:
|
9
|
-
datetime:
|
10
|
-
float:
|
11
|
-
symbol:
|
12
|
-
string:
|
13
|
-
boolean:
|
14
|
-
array:
|
9
|
+
integer: proc { |v| v.to_i },
|
10
|
+
datetime: proc { |v| Time.at(v.to_f) },
|
11
|
+
float: proc { |v| v.to_f },
|
12
|
+
symbol: proc { |v| v.to_sym },
|
13
|
+
string: proc { |v| v },
|
14
|
+
boolean: proc { |v| ['true', '1', '1.0'].include? v },
|
15
|
+
array: proc { |v| v ? (v.is_a?(String) ? JSON.parse(v) : v) : [] }
|
15
16
|
}
|
16
17
|
SETTER_PROCS = {
|
17
|
-
datetime:
|
18
|
-
array:
|
18
|
+
datetime: proc { |v| v.to_f },
|
19
|
+
array: proc { |v| v if v.is_a? Array }
|
19
20
|
}
|
20
21
|
|
21
22
|
class << self
|
22
|
-
|
23
23
|
attr_writer :batch_write_queue, :in_memory
|
24
|
+
attr_reader :range_key
|
24
25
|
|
25
26
|
def table_name
|
26
27
|
@table_name ||= name.demodulize.tableize
|
@@ -38,7 +39,7 @@ module Dynamini
|
|
38
39
|
@range_key = key
|
39
40
|
end
|
40
41
|
|
41
|
-
def handle(column, format_class, options={})
|
42
|
+
def handle(column, format_class, options = {})
|
42
43
|
define_handled_getter(column, format_class, options)
|
43
44
|
define_handled_setter(column, format_class)
|
44
45
|
end
|
@@ -47,10 +48,6 @@ module Dynamini
|
|
47
48
|
@hash_key || :id
|
48
49
|
end
|
49
50
|
|
50
|
-
def range_key
|
51
|
-
@range_key
|
52
|
-
end
|
53
|
-
|
54
51
|
def in_memory
|
55
52
|
@in_memory || false
|
56
53
|
end
|
@@ -66,57 +63,56 @@ module Dynamini
|
|
66
63
|
@client ||= Aws::DynamoDB::Client.new(
|
67
64
|
region: Dynamini.configuration.region,
|
68
65
|
access_key_id: Dynamini.configuration.access_key_id,
|
69
|
-
secret_access_key: Dynamini.configuration.secret_access_key
|
66
|
+
secret_access_key: Dynamini.configuration.secret_access_key
|
67
|
+
)
|
70
68
|
end
|
71
69
|
end
|
72
70
|
|
73
|
-
def create(attributes, options={})
|
74
|
-
model =
|
71
|
+
def create(attributes, options = {})
|
72
|
+
model = new(attributes, true)
|
75
73
|
model if model.save(options)
|
76
74
|
end
|
77
75
|
|
78
|
-
def create!(attributes, options={})
|
79
|
-
model =
|
76
|
+
def create!(attributes, options = {})
|
77
|
+
model = new(attributes, true)
|
80
78
|
model if model.save!(options)
|
81
79
|
end
|
82
80
|
|
83
81
|
def find(hash_value, range_value = nil)
|
84
|
-
|
82
|
+
fail 'Range key cannot be blank.' if range_key && range_value.nil?
|
85
83
|
response = client.get_item(table_name: table_name, key: create_key_hash(hash_value, range_value))
|
86
84
|
raise 'Item not found.' unless response.item
|
87
|
-
|
85
|
+
new(response.item.symbolize_keys, false)
|
88
86
|
end
|
89
87
|
|
90
88
|
def exists?(key)
|
91
|
-
|
92
|
-
|
89
|
+
r = client.get_item(table_name: table_name, key: { hash_key => key.to_s })
|
90
|
+
r.item.present?
|
93
91
|
end
|
94
92
|
|
95
93
|
def find_or_new(key)
|
96
|
-
|
97
|
-
if
|
98
|
-
|
94
|
+
r = client.get_item(table_name: table_name, key: { hash_key => key.to_s })
|
95
|
+
if r.item
|
96
|
+
new(r.item.symbolize_keys, false)
|
99
97
|
else
|
100
|
-
|
98
|
+
new(hash_key => key.to_s)
|
101
99
|
end
|
102
100
|
end
|
103
101
|
|
104
102
|
def batch_find(ids = [])
|
105
103
|
return [] if ids.length < 1
|
106
104
|
objects = []
|
107
|
-
if ids.length > 100
|
108
|
-
raise StandardError, 'Batch find is limited to 100 items'
|
109
|
-
end
|
105
|
+
fail StandardError, 'Batch is limited to 100 items' if ids.length > 100
|
110
106
|
key_structure = ids.map { |i| { hash_key => i.to_s } }
|
111
|
-
response =
|
107
|
+
response = dynamo_batch_get(key_structure)
|
112
108
|
response.responses[table_name].each do |item|
|
113
|
-
objects <<
|
109
|
+
objects << new(item.symbolize_keys, false)
|
114
110
|
end
|
115
111
|
objects
|
116
112
|
end
|
117
113
|
|
118
114
|
def enqueue_for_save(attributes, options = {})
|
119
|
-
model =
|
115
|
+
model = new(attributes, true)
|
120
116
|
model.generate_timestamps! unless options[:skip_timestamps]
|
121
117
|
if model.valid?
|
122
118
|
batch_write_queue << model
|
@@ -127,7 +123,7 @@ module Dynamini
|
|
127
123
|
end
|
128
124
|
|
129
125
|
def flush_queue!
|
130
|
-
response =
|
126
|
+
response = dynamo_batch_save(batch_write_queue)
|
131
127
|
self.batch_write_queue = []
|
132
128
|
response
|
133
129
|
end
|
@@ -136,7 +132,7 @@ module Dynamini
|
|
136
132
|
|
137
133
|
#### Instance Methods
|
138
134
|
|
139
|
-
def initialize(attributes={}, new_record = true)
|
135
|
+
def initialize(attributes = {}, new_record = true)
|
140
136
|
@changed = Set.new
|
141
137
|
@new_record = new_record
|
142
138
|
@attributes = {}
|
@@ -146,9 +142,8 @@ module Dynamini
|
|
146
142
|
end
|
147
143
|
end
|
148
144
|
|
149
|
-
|
150
|
-
|
151
|
-
hash_key == object.hash_key if object.is_a?(self.class)
|
145
|
+
def ==(other)
|
146
|
+
hash_key == other.hash_key if other.is_a?(self.class)
|
152
147
|
end
|
153
148
|
|
154
149
|
def assign_attributes(attributes)
|
@@ -173,8 +168,7 @@ module Dynamini
|
|
173
168
|
end
|
174
169
|
|
175
170
|
def save!(options = {})
|
176
|
-
|
177
|
-
options[:validate]= true if options[:validate].nil?
|
171
|
+
options[:validate] = true if options[:validate].nil?
|
178
172
|
|
179
173
|
unless @changed.empty?
|
180
174
|
if (options[:validate] && valid?) || !options[:validate]
|
@@ -207,7 +201,10 @@ module Dynamini
|
|
207
201
|
end
|
208
202
|
|
209
203
|
def changes
|
210
|
-
@attributes.select { |attribute| @changed.include?(attribute.to_s) &&
|
204
|
+
@attributes.select { |attribute| @changed.include?(attribute.to_s) &&
|
205
|
+
attribute != self.class.hash_key &&
|
206
|
+
attribute != self.class.range_key
|
207
|
+
}
|
211
208
|
end
|
212
209
|
|
213
210
|
def changed
|
@@ -239,34 +236,57 @@ module Dynamini
|
|
239
236
|
end
|
240
237
|
|
241
238
|
def generate_timestamps!
|
242
|
-
self.updated_at= Time.now.to_f
|
243
|
-
self.created_at= Time.now.to_f if new_record?
|
239
|
+
self.updated_at = Time.now.to_f
|
240
|
+
self.created_at = Time.now.to_f if new_record?
|
244
241
|
end
|
245
242
|
|
246
243
|
def save_to_dynamo
|
247
|
-
self.class.client.update_item(
|
244
|
+
self.class.client.update_item(
|
245
|
+
table_name: self.class.table_name,
|
246
|
+
key: key,
|
247
|
+
attribute_updates: attribute_updates
|
248
|
+
)
|
248
249
|
end
|
249
250
|
|
250
251
|
def touch_to_dynamo
|
251
|
-
self.class.client.update_item(
|
252
|
+
self.class.client.update_item(
|
253
|
+
table_name: self.class.table_name,
|
254
|
+
key: key,
|
255
|
+
attribute_updates:
|
256
|
+
{ updated_at:
|
257
|
+
{ value: Time.now.to_f,
|
258
|
+
action: 'PUT'
|
259
|
+
}
|
260
|
+
}
|
261
|
+
)
|
252
262
|
end
|
253
263
|
|
254
264
|
def delete_from_dynamo
|
255
265
|
self.class.client.delete_item(table_name: self.class.table_name, key: key)
|
256
266
|
end
|
257
267
|
|
258
|
-
def increment_to_dynamo(attribute_increments, opts={})
|
259
|
-
self.class.client.update_item(
|
268
|
+
def increment_to_dynamo(attribute_increments, opts = {})
|
269
|
+
self.class.client.update_item(
|
270
|
+
table_name: self.class.table_name,
|
271
|
+
key: key,
|
272
|
+
attribute_updates: increment_updates(attribute_increments, opts)
|
273
|
+
)
|
260
274
|
end
|
261
275
|
|
262
|
-
def self.dynamo_batch_get(
|
263
|
-
client.batch_get_item(
|
276
|
+
def self.dynamo_batch_get(key_struct)
|
277
|
+
client.batch_get_item(
|
278
|
+
request_items: {
|
279
|
+
table_name => { keys: key_struct }
|
280
|
+
}
|
281
|
+
)
|
264
282
|
end
|
265
283
|
|
266
284
|
def self.dynamo_batch_save(model_array)
|
267
285
|
put_requests = []
|
268
286
|
model_array.each do |model|
|
269
|
-
put_requests << { put_request: {
|
287
|
+
put_requests << { put_request: {
|
288
|
+
item: model.attributes.reject{ |_k, v| v.blank? }.stringify_keys
|
289
|
+
} }
|
270
290
|
end
|
271
291
|
request_options = { request_items: {
|
272
292
|
"#{table_name}" => put_requests }
|
@@ -293,13 +313,13 @@ module Dynamini
|
|
293
313
|
end
|
294
314
|
end
|
295
315
|
|
296
|
-
def increment_updates(attribute_increments, opts={})
|
316
|
+
def increment_updates(attribute_increments, opts = {})
|
297
317
|
updates = {}
|
298
318
|
attribute_increments.each do |k,v|
|
299
|
-
updates[k] = {value: v, action: 'ADD'}
|
319
|
+
updates[k] = { value: v, action: 'ADD' }
|
300
320
|
end
|
301
|
-
updates[:updated_at] = {value: Time.now.to_f, action: 'PUT'} unless opts[:skip_timestamps]
|
302
|
-
updates[:created_at] = {value: Time.now.to_f, action: 'PUT'} unless attributes[:created_at]
|
321
|
+
updates[:updated_at] = { value: Time.now.to_f, action: 'PUT' } unless opts[:skip_timestamps]
|
322
|
+
updates[:created_at] = { value: Time.now.to_f, action: 'PUT' } unless attributes[:created_at]
|
303
323
|
updates
|
304
324
|
end
|
305
325
|
|
@@ -307,10 +327,14 @@ module Dynamini
|
|
307
327
|
if value.is_a?(Integer) || value.is_a?(Float)
|
308
328
|
current_value = self.send(attribute)
|
309
329
|
unless current_value.nil? || current_value.is_a?(Integer) || current_value.is_a?(Float)
|
310
|
-
|
330
|
+
fail StandardError, "Cannot increment a non-numeric non-nil value:
|
331
|
+
#{attribute} is currently #{current_value}.
|
332
|
+
If your current value is a numeric string,
|
333
|
+
use :handle to autocast it as a number."
|
311
334
|
end
|
312
335
|
else
|
313
|
-
|
336
|
+
fail StandardError, "You cannot increment an attribute by a
|
337
|
+
non-numeric value: #{value}"
|
314
338
|
end
|
315
339
|
end
|
316
340
|
|
@@ -338,11 +362,11 @@ module Dynamini
|
|
338
362
|
name =~ /^([a-zA-Z][-_\w]*)=.*$/
|
339
363
|
end
|
340
364
|
|
341
|
-
def self.define_handled_getter(column, format_class, options={})
|
365
|
+
def self.define_handled_getter(column, format_class, options = {})
|
342
366
|
proc = GETTER_PROCS[format_class]
|
343
|
-
|
367
|
+
fail 'Unsupported data type: ' + format_class.to_s if proc.nil?
|
344
368
|
define_method(column) do
|
345
|
-
if @attributes.
|
369
|
+
if @attributes.key?(column)
|
346
370
|
proc.call(read_attribute(column))
|
347
371
|
else
|
348
372
|
options[:default] || nil
|
@@ -364,14 +388,14 @@ module Dynamini
|
|
364
388
|
end
|
365
389
|
end
|
366
390
|
|
367
|
-
def respond_to_missing?(name, include_private=false)
|
391
|
+
def respond_to_missing?(name, include_private = false)
|
368
392
|
@attributes.keys.include?(name) || write_method?(name) || super
|
369
393
|
end
|
370
394
|
|
371
|
-
def write_attribute(attribute, new_value, record_change=true)
|
395
|
+
def write_attribute(attribute, new_value, record_change = true)
|
372
396
|
old_value = @attributes[attribute]
|
373
|
-
@attributes[attribute] = (new_value.nil? ? nil : new_value
|
374
|
-
record_change(attribute, new_value
|
397
|
+
@attributes[attribute] = (new_value.nil? ? nil : new_value)
|
398
|
+
record_change(attribute, new_value, old_value) if record_change
|
375
399
|
end
|
376
400
|
|
377
401
|
def record_change(attribute, new_value, old_value)
|
data/lib/dynamini/test_client.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Dynamini
|
2
2
|
require 'ostruct'
|
3
3
|
|
4
|
+
# In-memory database client for test purposes.
|
4
5
|
class TestClient
|
5
6
|
|
6
7
|
attr_reader :hash_key
|
@@ -12,12 +13,14 @@ module Dynamini
|
|
12
13
|
|
13
14
|
def update_item(args = {})
|
14
15
|
table = args[:table_name]
|
15
|
-
updates = flatten_attribute_updates(args).merge(
|
16
|
+
updates = flatten_attribute_updates(args).merge(
|
17
|
+
hash_key => args[:key][hash_key].to_s
|
18
|
+
)
|
16
19
|
@data[table] ||= {}
|
17
|
-
if @data[table][args[:key][hash_key]].present?
|
18
|
-
@data[table][args[:key][hash_key]].merge!(updates)
|
20
|
+
if @data[table][args[:key][hash_key].to_s].present?
|
21
|
+
@data[table][args[:key][hash_key].to_s].merge!(updates)
|
19
22
|
else
|
20
|
-
@data[table][args[:key][hash_key]] = updates
|
23
|
+
@data[table][args[:key][hash_key].to_s] = updates
|
21
24
|
end
|
22
25
|
end
|
23
26
|
|
@@ -68,14 +71,14 @@ module Dynamini
|
|
68
71
|
attribute_hash = {}
|
69
72
|
|
70
73
|
args[:attribute_updates].each do |k, v|
|
71
|
-
if v[:action] == 'ADD' && @data[args[:table_name]][args[:key][hash_key]]
|
72
|
-
|
74
|
+
if v[:action] == 'ADD' && @data[args[:table_name]][args[:key][hash_key]]
|
75
|
+
# if record has been saved
|
76
|
+
attribute_hash[k] = (v[:value] + @data[args[:table_name]][args[:key][hash_key]][k].to_f).to_s
|
73
77
|
else
|
74
|
-
attribute_hash[k] = v[:value]
|
78
|
+
attribute_hash[k] = v[:value].to_s
|
75
79
|
end
|
76
80
|
end
|
77
81
|
attribute_hash
|
78
82
|
end
|
79
|
-
|
80
83
|
end
|
81
|
-
end
|
84
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynamini
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.
|
4
|
+
version: 1.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Greg Ward
|
@@ -15,7 +15,7 @@ authors:
|
|
15
15
|
autorequire:
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
|
-
date: 2015-10-
|
18
|
+
date: 2015-10-22 00:00:00.000000000 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: activemodel
|
@@ -94,8 +94,9 @@ dependencies:
|
|
94
94
|
- !ruby/object:Gem::Version
|
95
95
|
version: '2'
|
96
96
|
description: |-
|
97
|
-
Lightweight DynamoDB interface gem designed as
|
98
|
-
|
97
|
+
Lightweight DynamoDB interface gem designed as
|
98
|
+
a drop-in replacement for ActiveRecord.
|
99
|
+
Built & maintained by the team at yroo.com.
|
99
100
|
email: dev@retailcommon.com
|
100
101
|
executables: []
|
101
102
|
extensions: []
|