Class: Dynamini::Base
- Inherits:
-
Object
show all
- Includes:
- ActiveModel::Validations
- Defined in:
- lib/dynamini/base.rb
Overview
Constant Summary
collapse
- BATCH_SIZE =
25
- GETTER_PROCS =
{
integer: proc { |v| v.to_i },
date: proc { |v| v.is_a?(Date) ? v : Time.at(v).to_date },
time: proc { |v| Time.at(v.to_f) },
float: proc { |v| v.to_f },
symbol: proc { |v| v.to_sym },
string: proc { |v| v },
boolean: proc { |v| v }
}
- SETTER_PROCS =
{
integer: proc { |v| v.to_i },
time: proc { |v| v.to_f },
float: proc { |v| v.to_f },
symbol: proc { |v| v.to_s },
string: proc { |v| v },
boolean: proc { |v| v },
date: proc { |v| v.to_time.to_f }
}
Class Attribute Summary collapse
Instance Attribute Summary collapse
Class Method Summary
collapse
-
.batch_find(ids = []) ⇒ Object
-
.client ⇒ Object
-
.create(attributes, options = {}) ⇒ Object
-
.create!(attributes, options = {}) ⇒ Object
-
.create_key_hash(hash_value, range_value = nil) ⇒ Object
-
.define_handled_getter(column, format_class, options = {}) ⇒ Object
-
.define_handled_setter(column, format_class) ⇒ Object
-
.dynamo_batch_get(key_struct) ⇒ Object
-
.dynamo_batch_save(model_array) ⇒ Object
-
.enqueue_for_save(attributes, options = {}) ⇒ Object
-
.exists?(hash_value, range_value = nil) ⇒ Boolean
-
.find(hash_value, range_value = nil) ⇒ Object
-
.find_or_new(hash_value, range_value = nil) ⇒ Object
-
.flush_queue! ⇒ Object
-
.handle(column, format_class, options = {}) ⇒ Object
-
.hash_key ⇒ Object
-
.set_hash_key(key) ⇒ Object
-
.set_range_key(key) ⇒ Object
-
.set_table_name(name) ⇒ Object
-
.table_name ⇒ Object
Instance Method Summary
collapse
Constructor Details
#initialize(attributes = {}, new_record = true) ⇒ Base
146
147
148
149
150
151
152
153
154
|
# File 'lib/dynamini/base.rb', line 146
def initialize(attributes = {}, new_record = true)
@changed = Set.new
@new_record = new_record
@attributes = {}
attributes.each do |k, v|
write_attribute(k, v, new_record)
end
end
|
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args, &block) ⇒ Object
354
355
356
357
358
359
360
361
362
363
364
|
# File 'lib/dynamini/base.rb', line 354
def method_missing(name, *args, &block)
if write_method?(name)
attribute = name[0..-2].to_sym
new_value = args.first
write_attribute(attribute, new_value)
elsif read_method?(name)
read_attribute(name)
else
super
end
end
|
Class Attribute Details
.batch_write_queue ⇒ Object
61
62
63
|
# File 'lib/dynamini/base.rb', line 61
def batch_write_queue
@batch_write_queue ||= []
end
|
.in_memory ⇒ Object
57
58
59
|
# File 'lib/dynamini/base.rb', line 57
def in_memory
@in_memory || false
end
|
.range_key ⇒ Object
Returns the value of attribute range_key.
30
31
32
|
# File 'lib/dynamini/base.rb', line 30
def range_key
@range_key
end
|
Instance Attribute Details
#attributes ⇒ Object
Returns the value of attribute attributes.
5
6
7
|
# File 'lib/dynamini/base.rb', line 5
def attributes
@attributes
end
|
Class Method Details
.batch_find(ids = []) ⇒ Object
113
114
115
116
117
118
119
120
121
122
123
|
# File 'lib/dynamini/base.rb', line 113
def batch_find(ids = [])
return [] if ids.length < 1
objects = []
fail StandardError, 'Batch is limited to 100 items' if ids.length > 100
key_structure = ids.map { |i| { hash_key => i.to_s } }
response = dynamo_batch_get(key_structure)
response.responses[table_name].each do |item|
objects << new(item.symbolize_keys, false)
end
objects
end
|
.create(attributes, options = {}) ⇒ Object
77
78
79
80
|
# File 'lib/dynamini/base.rb', line 77
def create(attributes, options = {})
model = new(attributes, true)
model if model.save(options)
end
|
.create!(attributes, options = {}) ⇒ Object
82
83
84
85
|
# File 'lib/dynamini/base.rb', line 82
def create!(attributes, options = {})
model = new(attributes, true)
model if model.save!(options)
end
|
.create_key_hash(hash_value, range_value = nil) ⇒ Object
314
315
316
317
318
|
# File 'lib/dynamini/base.rb', line 314
def self.create_key_hash(hash_value, range_value = nil)
key_hash = { self.hash_key => hash_value }
key_hash[self.range_key] = range_value if self.range_key
key_hash
end
|
.define_handled_getter(column, format_class, options = {}) ⇒ Object
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
|
# File 'lib/dynamini/base.rb', line 374
def self.define_handled_getter(column, format_class, options = {})
proc = GETTER_PROCS[format_class]
fail 'Unsupported data type: ' + format_class.to_s if proc.nil?
define_method(column) do
if @attributes.key?(column)
v = read_attribute(column)
if v.is_a? Array
v.map{ |e| proc.call(e) }
else
proc.call(read_attribute(column))
end
else
options[:default] || nil
end
end
end
|
.define_handled_setter(column, format_class) ⇒ Object
391
392
393
394
395
396
397
398
399
400
401
402
|
# File 'lib/dynamini/base.rb', line 391
def self.define_handled_setter(column, format_class)
setter_symbol = (column.to_s + '=').to_sym
proc = SETTER_PROCS[format_class]
fail 'Unsupported data type: ' + format_class.to_s if proc.nil?
define_method(setter_symbol) do |value|
if value.is_a? Array
write_attribute(column, value.map{ |e| proc.call(e) })
else
write_attribute(column, proc.call(value))
end
end
end
|
.dynamo_batch_get(key_struct) ⇒ Object
287
288
289
290
291
292
293
|
# File 'lib/dynamini/base.rb', line 287
def self.dynamo_batch_get(key_struct)
client.batch_get_item(
request_items: {
table_name => { keys: key_struct }
}
)
end
|
.dynamo_batch_save(model_array) ⇒ Object
295
296
297
298
299
300
301
302
303
304
305
306
|
# File 'lib/dynamini/base.rb', line 295
def self.dynamo_batch_save(model_array)
put_requests = []
model_array.each do |model|
put_requests << { put_request: {
item: model.attributes.reject{ |_k, v| v.blank? }.stringify_keys
} }
end
request_options = { request_items: {
"#{table_name}" => put_requests }
}
client.batch_write_item(request_options)
end
|
.enqueue_for_save(attributes, options = {}) ⇒ Object
125
126
127
128
129
130
131
132
133
134
|
# File 'lib/dynamini/base.rb', line 125
def enqueue_for_save(attributes, options = {})
model = new(attributes, true)
model.generate_timestamps! unless options[:skip_timestamps]
if model.valid?
batch_write_queue << model
flush_queue! if batch_write_queue.length == BATCH_SIZE
return true
end
false
end
|
.exists?(hash_value, range_value = nil) ⇒ Boolean
94
95
96
97
98
99
|
# File 'lib/dynamini/base.rb', line 94
def exists?(hash_value, range_value = nil)
fail 'Range key cannot be blank.' if range_key && range_value.nil?
r = client.get_item(table_name: table_name, key: create_key_hash(hash_value, range_value))
r.item.present?
end
|
.find(hash_value, range_value = nil) ⇒ Object
87
88
89
90
91
92
|
# File 'lib/dynamini/base.rb', line 87
def find(hash_value, range_value = nil)
fail 'Range key cannot be blank.' if range_key && range_value.nil?
response = client.get_item(table_name: table_name, key: create_key_hash(hash_value, range_value))
raise 'Item not found.' unless response.item
new(response.item.symbolize_keys, false)
end
|
.find_or_new(hash_value, range_value = nil) ⇒ Object
101
102
103
104
105
106
107
108
109
110
111
|
# File 'lib/dynamini/base.rb', line 101
def find_or_new(hash_value, range_value = nil)
fail 'Key cannot be blank.' if (hash_value.nil? || hash_value == '')
fail 'Range key cannot be blank.' if range_key && range_value.nil?
r = client.get_item(table_name: table_name, key: create_key_hash(hash_value, range_value))
if r.item
new(r.item.symbolize_keys, false)
else
range_key ? new(hash_key => hash_value.to_s, range_key => range_value.to_s) : new(hash_key => hash_value.to_s)
end
end
|
.flush_queue! ⇒ Object
136
137
138
139
140
|
# File 'lib/dynamini/base.rb', line 136
def flush_queue!
response = dynamo_batch_save(batch_write_queue)
self.batch_write_queue = []
response
end
|
.handle(column, format_class, options = {}) ⇒ Object
48
49
50
51
|
# File 'lib/dynamini/base.rb', line 48
def handle(column, format_class, options = {})
define_handled_getter(column, format_class, options)
define_handled_setter(column, format_class)
end
|
.hash_key ⇒ Object
53
54
55
|
# File 'lib/dynamini/base.rb', line 53
def hash_key
@hash_key || :id
end
|
.set_hash_key(key) ⇒ Object
40
41
42
|
# File 'lib/dynamini/base.rb', line 40
def set_hash_key(key)
@hash_key = key
end
|
.set_range_key(key) ⇒ Object
44
45
46
|
# File 'lib/dynamini/base.rb', line 44
def set_range_key(key)
@range_key = key
end
|
.set_table_name(name) ⇒ Object
36
37
38
|
# File 'lib/dynamini/base.rb', line 36
def set_table_name(name)
@table_name = name
end
|
.table_name ⇒ Object
32
33
34
|
# File 'lib/dynamini/base.rb', line 32
def table_name
@table_name ||= name.demodulize.tableize
end
|
Instance Method Details
#==(other) ⇒ Object
156
157
158
|
# File 'lib/dynamini/base.rb', line 156
def ==(other)
hash_key == other.hash_key if other.is_a?(self.class)
end
|
#assign_attributes(attributes) ⇒ Object
160
161
162
163
164
165
|
# File 'lib/dynamini/base.rb', line 160
def assign_attributes(attributes)
attributes.each do |key, value|
write_attribute(key, value)
end
nil
end
|
#changed ⇒ Object
221
222
223
|
# File 'lib/dynamini/base.rb', line 221
def changed
@changed.to_a
end
|
#changes ⇒ Object
214
215
216
217
218
219
|
# File 'lib/dynamini/base.rb', line 214
def changes
@attributes.select { |attribute| @changed.include?(attribute.to_s) &&
attribute != self.class.hash_key &&
attribute != self.class.range_key
}
end
|
#delete ⇒ Object
209
210
211
212
|
# File 'lib/dynamini/base.rb', line 209
def delete
delete_from_dynamo
self
end
|
#increment!(attribute_increments, opts = {}) ⇒ Object
202
203
204
205
206
207
|
# File 'lib/dynamini/base.rb', line 202
def increment!(attribute_increments, opts = {})
attribute_increments.each do |a, v|
validate_incrementable_attribute(a, v)
end
increment_to_dynamo(attribute_increments, opts)
end
|
#new_record? ⇒ Boolean
225
226
227
|
# File 'lib/dynamini/base.rb', line 225
def new_record?
@new_record
end
|
#save(options = {}) ⇒ Object
177
178
179
|
# File 'lib/dynamini/base.rb', line 177
def save(options = {})
@changed.empty? || (valid? && trigger_save(options))
end
|
#save!(options = {}) ⇒ Object
181
182
183
184
185
186
187
188
189
190
191
|
# File 'lib/dynamini/base.rb', line 181
def save!(options = {})
options[:validate] = true if options[:validate].nil?
unless @changed.empty?
if (options[:validate] && valid?) || !options[:validate]
trigger_save(options)
else
raise StandardError, errors.full_messages
end
end
end
|
#touch(options = {validate: true}) ⇒ Object
193
194
195
196
197
198
199
200
|
# File 'lib/dynamini/base.rb', line 193
def touch(options = {validate: true})
raise RuntimeError, 'Cannot touch a new record.' if new_record?
if (options[:validate] && valid?) || !options[:validate]
trigger_touch
else
raise StandardError, errors.full_messages
end
end
|
#update_attribute(key, value, options = {}) ⇒ Object
167
168
169
170
|
# File 'lib/dynamini/base.rb', line 167
def update_attribute(key, value, options = {})
write_attribute(key, value)
save!(options)
end
|
#update_attributes(attributes, options = {}) ⇒ Object
172
173
174
175
|
# File 'lib/dynamini/base.rb', line 172
def update_attributes(attributes, options = {})
assign_attributes(attributes)
save!(options)
end
|