dynamini 2.6.4 → 2.6.5

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: aeef2ffc6acac0bce16107fb9ec281db9509bcb2
4
- data.tar.gz: c0757f84ebc577b1ea555c61ded01733acb2ee9a
3
+ metadata.gz: a58fb603731e3efd1d91be0295a9f9c6bb9ab563
4
+ data.tar.gz: 914d82aa5c7e4c923e1f5d14552043bfab6f966b
5
5
  SHA512:
6
- metadata.gz: b9fbb688330e9ad1f1c0330f6f45e0e04eff3e2a9524d99d7e3602b2e232fb548e4b5056d14862099206c6cd77a628f26bcc71008f87a8d406d45f66a8652c4f
7
- data.tar.gz: a610af70e44ce47b7cec2c80ee927300a9537ee85f52091342888280fce09b1c829b6f8ae3f3116fe3a1903964375bc56702991d8fb13b981063e1c22e6dce90
6
+ metadata.gz: 35cef4e720792c20f78a3e9db934fc7fc020de29d06c377641fc4a4484b0874822394c391f0bc1dfb7a39a2310054efe68d665171c7900d523bd21fe92276cf1
7
+ data.tar.gz: c39c01e1d41bbceade9bf3eac3561766389e0763b308dd841e750e7e0440802809d1bcee273abc6d6b618e854aa8aa7f5377aab69b943ac4c6377d0783575591
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dynamini (2.6.4)
4
+ dynamini (2.6.5)
5
5
  activemodel (>= 3, < 5.0)
6
6
  aws-sdk (~> 2)
7
7
 
@@ -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.9.0)
59
+ minitest (5.9.1)
60
60
  nenv (0.2.0)
61
61
  notiffany (0.0.8)
62
62
  nenv (~> 0.1)
data/dynamini.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'dynamini'
3
- s.version = '2.6.4'
3
+ s.version = '2.6.5'
4
4
  s.summary = 'DynamoDB interface'
5
5
  s.description = 'Lightweight DynamoDB interface gem designed as
6
6
  a drop-in replacement for ActiveRecord.
@@ -6,7 +6,7 @@ module Dynamini
6
6
  def add_to(attribute, value)
7
7
  complain_about(attribute) unless handles[attribute]
8
8
  old_value = read_attribute(attribute)
9
- add_value = attribute_callback(Dynamini::TypeHandler::SETTER_PROCS, handles[attribute], value)
9
+ add_value = self.class.attribute_callback(TypeHandler::SETTER_PROCS, handles[attribute], value)
10
10
  if ADDABLE_TYPES.include? handles[attribute][:format]
11
11
  @attributes[attribute] ? @attributes[attribute] += add_value : @attributes[attribute] = add_value
12
12
  else
data/lib/dynamini/base.rb CHANGED
@@ -14,10 +14,10 @@ module Dynamini
14
14
  extend ActiveModel::Callbacks
15
15
  extend Dynamini::BatchOperations
16
16
  extend Dynamini::Querying
17
+ extend Dynamini::TypeHandler
17
18
  include Dynamini::ClientInterface
18
19
  include Dynamini::Dirty
19
20
  include Dynamini::Increment
20
- include Dynamini::TypeHandler
21
21
  include Dynamini::Adder
22
22
 
23
23
  attr_reader :attributes
@@ -30,6 +30,8 @@ module Dynamini
30
30
 
31
31
  define_model_callbacks :save
32
32
 
33
+ alias :read_attribute_for_serialization :send
34
+
33
35
  class << self
34
36
 
35
37
  attr_reader :range_key, :secondary_index
@@ -42,12 +44,14 @@ module Dynamini
42
44
  @table_name = name
43
45
  end
44
46
 
45
- def set_hash_key(key)
47
+ def set_hash_key(key, format = nil)
46
48
  @hash_key = key
49
+ handle(key, format) if format
47
50
  end
48
51
 
49
- def set_range_key(key)
52
+ def set_range_key(key, format = nil)
50
53
  @range_key = key
54
+ handle(key, format) if format
51
55
  end
52
56
 
53
57
  def set_secondary_index(index_name, args)
@@ -168,8 +172,9 @@ module Dynamini
168
172
  end
169
173
 
170
174
  def self.create_key_hash(hash_value, range_value = nil)
171
- key_hash = {self.hash_key => hash_value}
172
- key_hash[self.range_key] = range_value if self.range_key
175
+
176
+ key_hash = {self.hash_key => handled_key(self.hash_key, hash_value)}
177
+ key_hash[self.range_key] = handled_key(self.range_key, range_value) if self.range_key
173
178
  key_hash
174
179
  end
175
180
 
@@ -211,8 +216,8 @@ module Dynamini
211
216
 
212
217
  def write_attribute(attribute, new_value, change: true, **options)
213
218
  old_value = read_attribute(attribute)
214
- if (handle = handles[attribute.to_sym]) && !new_value.nil?
215
- new_value = attribute_callback(SETTER_PROCS, handle, new_value)
219
+ if (handle = self.class.handles[attribute.to_sym]) && !new_value.nil?
220
+ new_value = self.class.attribute_callback(TypeHandler::SETTER_PROCS, handle, new_value)
216
221
  end
217
222
  @attributes[attribute] = new_value
218
223
  record_change(attribute, old_value, new_value, options[:action]) if change && new_value != old_value
@@ -220,9 +225,9 @@ module Dynamini
220
225
 
221
226
  def read_attribute(name)
222
227
  value = @attributes[name]
223
- if (handle = handles[name.to_sym])
228
+ if (handle = self.class.handles[name.to_sym])
224
229
  value = handle[:options][:default] if value.nil?
225
- value = attribute_callback(GETTER_PROCS, handle, value) unless value.nil?
230
+ value = self.class.attribute_callback(TypeHandler::GETTER_PROCS, handle, value) unless value.nil?
226
231
  end
227
232
  value
228
233
  end
@@ -3,6 +3,7 @@ module Dynamini
3
3
  OPTIONAL_QUERY_PARAMS = [:limit, :scan_index_forward]
4
4
 
5
5
  def find(hash_value, range_value = nil)
6
+ fail ArgumentError, 'Hash key cannot be nil or empty.' if (hash_value.nil? || hash_value.blank?)
6
7
  fail 'Range key cannot be blank.' if range_key && range_value.nil?
7
8
  response = client.get_item(table_name: table_name, key: create_key_hash(hash_value, range_value))
8
9
 
@@ -55,8 +55,6 @@ module Dynamini
55
55
  table[hash_key_value] ? table[hash_key_value].merge!(updates) : table[hash_key_value] = updates
56
56
  end
57
57
 
58
-
59
-
60
58
  def get_item(args = {})
61
59
  table = get_table(args[:table_name])
62
60
 
@@ -7,7 +7,7 @@ module Dynamini
7
7
  time: proc { |v| Time.at(v.to_f) },
8
8
  float: proc { |v| v.to_f },
9
9
  symbol: proc { |v| v.to_sym },
10
- string: proc { |v| v },
10
+ string: proc { |v| v.to_s },
11
11
  boolean: proc { |v| v },
12
12
  array: proc { |v| v.to_a },
13
13
  set: proc { |v| Set.new(v) }
@@ -18,66 +18,66 @@ module Dynamini
18
18
  time: proc { |v| (v.is_a?(Date) ? v.to_time : v).to_f },
19
19
  float: proc { |v| v.to_f },
20
20
  symbol: proc { |v| v.to_s },
21
- string: proc { |v| v },
21
+ string: proc { |v| v.to_s },
22
22
  boolean: proc { |v| v },
23
23
  date: proc { |v| v.to_time.to_f },
24
24
  array: proc { |v| v.to_a },
25
25
  set: proc { |v| Set.new(v) }
26
26
  }
27
27
 
28
- module ClassMethods
29
- def handle(column, format_class, options = {})
30
- validate_handle(format_class, options)
28
+ def handle(column, format_class, options = {})
29
+ validate_handle(format_class, options)
31
30
 
32
- options[:default] ||= format_default(format_class)
33
- options[:default] ||= Set.new if format_class == :set
31
+ options[:default] ||= format_default(format_class)
32
+ options[:default] ||= Set.new if format_class == :set
34
33
 
35
- self.handles = self.handles.merge(column => { format: format_class, options: options })
34
+ self.handles = self.handles.merge(column => { format: format_class, options: options })
36
35
 
37
- define_handled_getter(column, format_class, options)
38
- define_handled_setter(column, format_class)
39
- end
36
+ define_handled_getter(column, format_class, options)
37
+ define_handled_setter(column, format_class)
38
+ end
40
39
 
41
- def define_handled_getter(column, format_class, _options = {})
42
- proc = GETTER_PROCS[format_class]
43
- fail 'Unsupported data type: ' + format_class.to_s if proc.nil?
40
+ def define_handled_getter(column, format_class, _options = {})
41
+ proc = GETTER_PROCS[format_class]
42
+ fail 'Unsupported data type: ' + format_class.to_s if proc.nil?
44
43
 
45
- define_method(column) do
46
- read_attribute(column)
47
- end
44
+ define_method(column) do
45
+ read_attribute(column)
48
46
  end
47
+ end
49
48
 
50
- def define_handled_setter(column, format_class)
51
- method_name = (column.to_s + '=')
52
- proc = SETTER_PROCS[format_class]
53
- fail 'Unsupported data type: ' + format_class.to_s if proc.nil?
54
- define_method(method_name) do |value|
55
- write_attribute(column, value)
56
- end
49
+ def define_handled_setter(column, format_class)
50
+ method_name = (column.to_s + '=')
51
+ proc = SETTER_PROCS[format_class]
52
+ fail 'Unsupported data type: ' + format_class.to_s if proc.nil?
53
+ define_method(method_name) do |value|
54
+ write_attribute(column, value)
57
55
  end
56
+ end
58
57
 
59
- def format_default(format_class)
60
- case format_class
61
- when :array
62
- []
63
- when :set
64
- Set.new
65
- end
58
+ def format_default(format_class)
59
+ case format_class
60
+ when :array
61
+ []
62
+ when :set
63
+ Set.new
66
64
  end
65
+ end
67
66
 
68
- def validate_handle(format, options)
69
- if format == :set
70
- if options[:of] && [:set, :array].include?(options[:of])
71
- raise ArgumentError, 'Invalid handle: cannot store non-primitive datatypes within a set.'
72
- end
67
+ def validate_handle(format, options)
68
+ if format == :set
69
+ if options[:of] && [:set, :array].include?(options[:of])
70
+ raise ArgumentError, 'Invalid handle: cannot store non-primitive datatypes within a set.'
73
71
  end
74
72
  end
75
73
  end
76
74
 
77
- private
78
-
79
- def handles
80
- self.class.handles
75
+ def handled_key(column, value)
76
+ if handle = handles[column]
77
+ attribute_callback(GETTER_PROCS, handle, value)
78
+ else
79
+ value
80
+ end
81
81
  end
82
82
 
83
83
  def attribute_callback(procs, handle, value)
@@ -92,14 +92,6 @@ module Dynamini
92
92
  end
93
93
  end
94
94
 
95
- def handled_as?(handle, type)
96
- type.include? handle[:format]
97
- end
98
-
99
- def self.included(base)
100
- base.extend ClassMethods
101
- end
102
-
103
95
  def should_convert_elements?(handle, value)
104
96
  handle[:options][:of] && (value.is_a?(Array) || value.is_a?(Set))
105
97
  end
@@ -111,5 +103,9 @@ module Dynamini
111
103
  def convert_elements(enumerable, callback)
112
104
  enumerable.map { |e| callback.call(e) }
113
105
  end
106
+
107
+ def handled_as?(handle, type)
108
+ type.include? handle[:format]
109
+ end
114
110
  end
115
111
  end
@@ -45,7 +45,14 @@ describe Dynamini::Querying do
45
45
  TestClassWithRange.find('1', '2')
46
46
  end.to raise_error Dynamini::RecordNotFound, "Couldn't find TestClassWithRange with 'foo'=1 and 'bar'=2"
47
47
  end
48
+ end
48
49
 
50
+ context 'when finding a nil or empty id' do
51
+ it 'raises an error' do
52
+ expect{ Dynamini::Base.find('') }.to raise_error ArgumentError
53
+ expect{ Dynamini::Base.find([]) }.to raise_error ArgumentError
54
+ expect{ Dynamini::Base.find() }.to raise_error ArgumentError
55
+ end
49
56
  end
50
57
 
51
58
  context 'when retrieving a subclass' do
@@ -57,6 +64,62 @@ describe Dynamini::Querying do
57
64
  expect(Foo.find('1')).to be_a Foo
58
65
  end
59
66
  end
67
+
68
+ context 'when hash key is not handled' do
69
+ context 'when finding a record by integer when hash key was string' do
70
+ it 'should raise an error' do
71
+ Dynamini::Base.create!(id: '123', foo: 'bar')
72
+ expect{ Dynamini::Base.find(123) }.to raise_error(Dynamini::RecordNotFound)
73
+ end
74
+ end
75
+
76
+ context 'when finding a record by string when hash key was integer' do
77
+ it 'should not find the item' do
78
+ Dynamini::Base.create!(id: 123, foo: 'bar')
79
+ expect{ Dynamini::Base.find('123') }.to raise_error(Dynamini::RecordNotFound)
80
+ end
81
+ end
82
+ end
83
+
84
+ context 'when hash key is handled as string' do
85
+ class StringHandledHash < Dynamini::Base
86
+ set_hash_key :id, :string
87
+ end
88
+
89
+ context 'when finding a record by integer when hash key was string' do
90
+ it 'should find the item' do
91
+ StringHandledHash.create!(id: '123', foo: 'bar')
92
+ expect(StringHandledHash.find(123).foo).to eq('bar')
93
+ end
94
+ end
95
+
96
+ context 'when finding a record by string when hash key was integer' do
97
+ it 'should find the item' do
98
+ StringHandledHash.create!(id: 123, foo: 'bar')
99
+ expect(StringHandledHash.find('123').foo).to eq('bar')
100
+ end
101
+ end
102
+ end
103
+
104
+ context 'when hash key is handled as integer' do
105
+ class IntegerHandledHash < Dynamini::Base
106
+ set_hash_key :id, :integer
107
+ end
108
+
109
+ context 'when finding a record by integer when hash key was string' do
110
+ it 'should the item' do
111
+ IntegerHandledHash.create!(id: '123', foo: 'bar')
112
+ expect(IntegerHandledHash.find(123).foo).to eq('bar')
113
+ end
114
+ end
115
+
116
+ context 'when finding a record by string when hash key was integer' do
117
+ it 'should find the item' do
118
+ IntegerHandledHash.create!(id: 123, foo: 'bar')
119
+ expect(IntegerHandledHash.find('123').foo).to eq('bar')
120
+ end
121
+ end
122
+ end
60
123
  end
61
124
 
62
125
  describe '.find_or_nil' do
@@ -81,7 +81,7 @@ describe Dynamini::TestClient do
81
81
  expect(test_client.get_item(table_name: table_name, key: {test_client.hash_key_attr => "abc"}).item[:test_attr]).to eq('test')
82
82
  end
83
83
 
84
- it 'should returns nil if the item does not exist' do
84
+ it 'should return nil if the item does not exist' do
85
85
  expect(test_client.get_item(table_name: table_name, key: {test_client.hash_key_attr => "abc"}).item).to eq(nil)
86
86
  end
87
87
 
@@ -116,6 +116,23 @@ describe Dynamini::TestClient do
116
116
  expect(test_client.get_item(table_name: table_name, key: {test_client.range_key_attr => 'def'}).item).to eq(nil)
117
117
  end
118
118
  end
119
+
120
+ context 'hash key is not handled' do
121
+ let(:test_client) { Dynamini::TestClient.new(:hash_key_name) }
122
+ context 'getting a record by integer when hash key is string' do
123
+ it 'should not find the item' do
124
+ test_client.update_item(table_name: table_name, key: {test_client.hash_key_attr => '123'}, attribute_updates: {test_attr: {value: 'test', action: 'PUT'}})
125
+ expect(test_client.get_item(table_name: table_name, key: {test_client.range_key_attr => 123}).item).to eq(nil)
126
+ end
127
+ end
128
+
129
+ context 'getting a record by string when hash key is integer' do
130
+ it 'should not find the item' do
131
+ test_client.update_item(table_name: table_name, key: {test_client.hash_key_attr => 123}, attribute_updates: {test_attr: {value: 'test', action: 'PUT'}})
132
+ expect(test_client.get_item(table_name: table_name, key: {test_client.range_key_attr => '123'}).item).to eq(nil)
133
+ end
134
+ end
135
+ end
119
136
  end
120
137
 
121
138
  describe '#query' do
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: 2.6.4
4
+ version: 2.6.5
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: 2016-09-28 00:00:00.000000000 Z
18
+ date: 2016-10-04 00:00:00.000000000 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: activemodel
@@ -185,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
185
  version: '0'
186
186
  requirements: []
187
187
  rubyforge_project:
188
- rubygems_version: 2.4.6
188
+ rubygems_version: 2.5.1
189
189
  signing_key:
190
190
  specification_version: 4
191
191
  summary: DynamoDB interface