dynamini 1.10.1 → 1.10.2

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: 7ac958908500fd7c64b8c6476a6bac8e20c09966
4
- data.tar.gz: 48552250242ac4617aae6f21151a90fb2baa5382
3
+ metadata.gz: 8248aff788be3cda0502be12ccc3768cdf4fc3d4
4
+ data.tar.gz: 860898330266f91bce5a52d1a4193edce7f64e07
5
5
  SHA512:
6
- metadata.gz: ac7bd1db86987a5555a33d4958988635e20c005fd9d04e8e8480838b4b90ce6b6fdea4212321b6b83b467be2c970f8db305a9697d5f59d5b2e47eda890a3d141
7
- data.tar.gz: 50a9a0a883421c0fc8903eba5f377c71cc4757556acf4af7e3d7e03b10d346b67c2a59962b30e2de22f7cbe072f43107cdeb2665184a87c29a65ec7ca6f66573
6
+ metadata.gz: 9dc5d37aefc854902b172a271a2b80b5ab22310f507ad2f5c234a60bb81d00b5a2f0a69bdd2ef8fe6c426830fe06d9f985f67d51db62b83a98d4eb8d6a956bee
7
+ data.tar.gz: 9efb1fd623f05c5eba81660ea04e46873d222634b5aca361b69205e75eccb1ad2c1fef2d53cf44555514eb5eae68aa559aec1ddebdc2a03dd53a49219a6c86ad
data/Gemfile.lock CHANGED
@@ -1,17 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dynamini (1.10.1)
4
+ dynamini (1.10.2)
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.4)
12
- activesupport (= 4.2.4)
11
+ activemodel (4.2.5)
12
+ activesupport (= 4.2.5)
13
13
  builder (~> 3.1)
14
- activesupport (4.2.4)
14
+ activesupport (4.2.5)
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.2)
59
+ minitest (5.8.3)
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 = '1.10.1'
3
+ s.version = '1.10.2'
4
4
  s.date = '2015-01-07'
5
5
  s.summary = 'DynamoDB interface'
6
6
  s.description = 'Lightweight DynamoDB interface gem designed as
data/lib/dynamini/base.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  require_relative 'batch_operations'
2
+ require_relative 'querying'
2
3
 
3
4
  module Dynamini
4
5
  # Core db interface class.
5
6
  class Base
6
7
  include ActiveModel::Validations
7
8
  extend Dynamini::BatchOperations
9
+ extend Dynamini::Querying
8
10
 
9
11
  attr_reader :attributes
10
12
 
@@ -91,45 +93,6 @@ module Dynamini
91
93
  model = new(attributes, true)
92
94
  model if model.save!(options)
93
95
  end
94
-
95
- def find(hash_value, range_value = nil)
96
- fail 'Range key cannot be blank.' if range_key && range_value.nil?
97
- response = client.get_item(table_name: table_name, key: create_key_hash(hash_value, range_value))
98
- raise 'Item not found.' unless response.item
99
- new(response.item.symbolize_keys, false)
100
- end
101
-
102
- def exists?(hash_value, range_value = nil)
103
- fail 'Range key cannot be blank.' if range_key && range_value.nil?
104
-
105
- r = client.get_item(table_name: table_name, key: create_key_hash(hash_value, range_value))
106
- r.item.present?
107
- end
108
-
109
- def find_or_new(hash_value, range_value = nil)
110
- fail 'Key cannot be blank.' if (hash_value.nil? || hash_value == '')
111
- fail 'Range key cannot be blank.' if range_key && range_value.nil?
112
-
113
- r = client.get_item(table_name: table_name, key: create_key_hash(hash_value, range_value))
114
- if r.item
115
- new(r.item.symbolize_keys, false)
116
- else
117
- range_key ? new(hash_key => hash_value, range_key => range_value) : new(hash_key => hash_value)
118
- end
119
- end
120
-
121
- def query(args = {})
122
- fail ArgumentError, 'You must provide a :hash_key.' unless args[:hash_key]
123
- fail TypeError, 'Your range key must be handled as an integer, float, date, or time.' unless self.range_is_numeric?
124
-
125
- response = self.dynamo_query(args)
126
- objects = []
127
- response.items.each do |item|
128
- objects << new(item.symbolize_keys, false)
129
- end
130
- objects
131
- end
132
-
133
96
  end
134
97
 
135
98
  #### Instance Methods
@@ -273,37 +236,6 @@ module Dynamini
273
236
  )
274
237
  end
275
238
 
276
- def self.dynamo_query(args)
277
- expression_attribute_values = self.build_expression_attribute_values(args)
278
- key_condition_expression = self.build_key_condition_expression(args)
279
-
280
- client.query(
281
- table_name: table_name,
282
- key_condition_expression: key_condition_expression,
283
- expression_attribute_values: expression_attribute_values
284
- )
285
- end
286
-
287
- def self.build_expression_attribute_values(args)
288
- expression_values = {}
289
- expression_values[':h'] = args[:hash_key]
290
- expression_values[':s'] = args[:start] if args[:start]
291
- expression_values[':e'] = args[:end] if args[:end]
292
- expression_values
293
- end
294
-
295
- def self.build_key_condition_expression(args)
296
- expression = "#{hash_key} = :h"
297
- if args[:start] && args[:end]
298
- expression += " AND #{range_key} BETWEEN :s AND :e"
299
- elsif args[:start]
300
- expression += " AND #{range_key} >= :s"
301
- elsif args[:end]
302
- expression += " AND #{range_key} <= :e"
303
- end
304
- expression
305
- end
306
-
307
239
  def key
308
240
  key_hash = { self.class.hash_key => @attributes[self.class.hash_key] }
309
241
  key_hash[self.class.range_key] = @attributes[self.class.range_key] if self.class.range_key
@@ -316,30 +248,6 @@ module Dynamini
316
248
  key_hash
317
249
  end
318
250
 
319
- def self.build_range_expression(start_value, end_value)
320
- operator = (
321
- if start_value && end_value
322
- 'BETWEEN'
323
- elsif start_value
324
- 'GE'
325
- elsif end_value
326
- 'LE'
327
- end
328
- )
329
- attribute_value_list = []
330
-
331
- if handle = handles[range_key.to_sym]
332
- attribute_value_list << attribute_callback(SETTER_PROCS, handle, start_value) if start_value
333
- attribute_value_list << attribute_callback(SETTER_PROCS, handle, end_value) if end_value
334
- else
335
- attribute_value_list << start_value if start_value
336
- attribute_value_list << end_value if end_value
337
- end
338
-
339
- {attribute_value_list: attribute_value_list, comparison_operator: operator}
340
- end
341
-
342
-
343
251
  def attribute_updates
344
252
  changes.reduce({}) do |updates, (key, value)|
345
253
  current_value = value[1]
@@ -0,0 +1,101 @@
1
+ module Dynamini
2
+ module Querying
3
+
4
+ def find(hash_value, range_value = nil)
5
+ fail 'Range key cannot be blank.' if range_key && range_value.nil?
6
+ response = client.get_item(table_name: table_name, key: create_key_hash(hash_value, range_value))
7
+ raise 'Item not found.' unless response.item
8
+ new(response.item.symbolize_keys, false)
9
+ end
10
+
11
+ def exists?(hash_value, range_value = nil)
12
+ fail 'Range key cannot be blank.' if range_key && range_value.nil?
13
+
14
+ r = client.get_item(table_name: table_name, key: create_key_hash(hash_value, range_value))
15
+ r.item.present?
16
+ end
17
+
18
+ def find_or_new(hash_value, range_value = nil)
19
+ fail 'Key cannot be blank.' if (hash_value.nil? || hash_value == '')
20
+ fail 'Range key cannot be blank.' if range_key && range_value.nil?
21
+
22
+ r = client.get_item(table_name: table_name, key: create_key_hash(hash_value, range_value))
23
+ if r.item
24
+ new(r.item.symbolize_keys, false)
25
+ else
26
+ range_key ? new(hash_key => hash_value, range_key => range_value) : new(hash_key => hash_value)
27
+ end
28
+ end
29
+
30
+ def query(args = {})
31
+ fail ArgumentError, 'You must provide a :hash_key.' unless args[:hash_key]
32
+ fail TypeError, 'Your range key must be handled as an integer, float, date, or time.' unless self.range_is_numeric?
33
+
34
+ response = dynamo_query(args)
35
+ objects = []
36
+ response.items.each do |item|
37
+ objects << new(item.symbolize_keys, false)
38
+ end
39
+ objects
40
+ end
41
+
42
+ private
43
+
44
+ def dynamo_query(args)
45
+ expression_attribute_values = build_expression_attribute_values(args)
46
+ key_condition_expression = build_key_condition_expression(args)
47
+
48
+ client.query(
49
+ table_name: table_name,
50
+ key_condition_expression: key_condition_expression,
51
+ expression_attribute_values: expression_attribute_values
52
+ )
53
+ end
54
+
55
+ def build_expression_attribute_values(args)
56
+ expression_values = {}
57
+ expression_values[':h'] = args[:hash_key]
58
+ expression_values[':s'] = args[:start] if args[:start]
59
+ expression_values[':e'] = args[:end] if args[:end]
60
+ expression_values
61
+ end
62
+
63
+ def build_key_condition_expression(args)
64
+ expression = "#{hash_key} = :h"
65
+ if args[:start] && args[:end]
66
+ expression += " AND #{range_key} BETWEEN :s AND :e"
67
+ elsif args[:start]
68
+ expression += " AND #{range_key} >= :s"
69
+ elsif args[:end]
70
+ expression += " AND #{range_key} <= :e"
71
+ end
72
+ expression
73
+ end
74
+
75
+ #FIXME unused method
76
+ def build_range_expression(start_value, end_value)
77
+ operator = (
78
+ if start_value && end_value
79
+ 'BETWEEN'
80
+ elsif start_value
81
+ 'GE'
82
+ elsif end_value
83
+ 'LE'
84
+ end
85
+ )
86
+ attribute_value_list = []
87
+
88
+ if handle = handles[range_key.to_sym]
89
+ attribute_value_list << attribute_callback(SETTER_PROCS, handle, start_value) if start_value
90
+ attribute_value_list << attribute_callback(SETTER_PROCS, handle, end_value) if end_value
91
+ else
92
+ attribute_value_list << start_value if start_value
93
+ attribute_value_list << end_value if end_value
94
+ end
95
+
96
+ {attribute_value_list: attribute_value_list, comparison_operator: operator}
97
+ end
98
+
99
+
100
+ end
101
+ end
@@ -65,11 +65,11 @@ module Dynamini
65
65
  def batch_get_item(args = {})
66
66
  responses = {}
67
67
 
68
- args[:request_items].each do |k, v|
69
- responses[k] = []
70
- v[:keys].each do |key_hash|
71
- item = @data[k][key_hash.values.first]
72
- responses[k] << item unless item.nil?
68
+ args[:request_items].each do |table_name, get_request|
69
+ responses[table_name] = []
70
+ get_request[:keys].each do |key_hash|
71
+ item = get_table(table_name)[key_hash.values.first]
72
+ responses[table_name] << item unless item.nil?
73
73
  end
74
74
  end
75
75
 
@@ -78,18 +78,17 @@ module Dynamini
78
78
 
79
79
  #FIXME Add range key support
80
80
  def batch_write_item(request_options)
81
- request_options[:request_items].each do |k, v|
82
- @data[k] ||= {}
83
- v.each do |request_hash|
81
+ request_options[:request_items].each do |table_name, put_requests|
82
+ put_requests.each do |request_hash|
84
83
  item = request_hash[:put_request][:item]
85
84
  key = item[hash_key_attr.to_s]
86
- @data[k][key] = item
85
+ get_table(table_name)[key] = item
87
86
  end
88
87
  end
89
88
  end
90
89
 
91
90
  def delete_item(args = {})
92
- @data[args[:table_name]].delete(args[:key][hash_key_attr])
91
+ get_table(args[:table_name]).delete(args[:key][hash_key_attr])
93
92
  end
94
93
 
95
94
  def query(args = {})
@@ -119,7 +118,7 @@ module Dynamini
119
118
  start_val = nil
120
119
  end_val = nil
121
120
  end
122
- parent = @data[args[:table_name]][hash_key]
121
+ parent = get_table(args[:table_name])[hash_key]
123
122
  return OpenStruct.new(items:[]) unless parent
124
123
 
125
124
  selected = parent.values
@@ -143,10 +142,11 @@ module Dynamini
143
142
 
144
143
  if args[:attribute_updates]
145
144
  args[:attribute_updates].each do |k, v|
145
+ table = get_table(args[:table_name])
146
146
 
147
- if v[:action] == 'ADD' && @data[args[:table_name]][hash_key_value]
147
+ if v[:action] == 'ADD' && table[hash_key_value]
148
148
  # if record has been saved
149
- data = @data[args[:table_name]][hash_key_value]
149
+ data = table[hash_key_value]
150
150
  data = (data[range_key_value] ||= {}) if range_key_value
151
151
 
152
152
  attribute_hash[k] = (v[:value] + data[k].to_f)
@@ -119,91 +119,6 @@ describe Dynamini::Base do
119
119
  end
120
120
  end
121
121
 
122
- describe '.find' do
123
-
124
- it 'should return a model with the retrieved attributes' do
125
- found = Dynamini::Base.find('abcd1234')
126
- expect(found.price).to eq(9.99)
127
- expect(found.name).to eq('Widget')
128
- expect(found.hash_key).to eq('009')
129
- end
130
-
131
- context 'when the object does not exist' do
132
- it 'should raise an error' do
133
- expect { Dynamini::Base.find('f') }.to raise_error 'Item not found.'
134
- end
135
-
136
- end
137
-
138
- context 'when retrieving a subclass' do
139
- class Foo < Dynamini::Base
140
- self.in_memory = true
141
- end
142
-
143
- it 'should return the object as an instance of the subclass' do
144
- Foo.create(id: '1')
145
- expect(Foo.find('1')).to be_a Foo
146
- end
147
- end
148
- end
149
-
150
- describe '.query' do
151
- before do
152
- 4.times do |i|
153
- TestClassWithRange.create(foo: 'foo', bar: i + 1)
154
- end
155
- end
156
- context 'start value provided' do
157
- it 'should return records with a range key greater than or equal to the start value' do
158
- records = TestClassWithRange.query(hash_key: 'foo', start: 2)
159
- expect(records.length).to eq 3
160
- expect(records.first.bar).to eq 2
161
- expect(records.last.bar).to eq 4
162
- end
163
- end
164
- context 'end value provided' do
165
- it 'should return records with a range key less than or equal to the start value' do
166
- records = TestClassWithRange.query(hash_key: 'foo', end: 2)
167
- expect(records.length).to eq 2
168
- expect(records.first.bar).to eq 1
169
- expect(records.last.bar).to eq 2
170
- end
171
- end
172
- context 'start and end values provided' do
173
- it 'should return records between the two values inclusive' do
174
- records = TestClassWithRange.query(hash_key: 'foo', start: 1, end: 3)
175
- expect(records.length).to eq 3
176
- expect(records.first.bar).to eq 1
177
- expect(records.last.bar).to eq 3
178
- end
179
- end
180
- context 'neither value provided' do
181
- it 'should return all records belonging to that hash key' do
182
- records = TestClassWithRange.query(hash_key: 'foo')
183
- expect(records.length).to eq 4
184
- expect(records.first.bar).to eq 1
185
- expect(records.last.bar).to eq 4
186
- end
187
- end
188
-
189
- context 'a non-numeric range field' do
190
- it 'should raise an error' do
191
- class TestClassWithStringRange < Dynamini::Base
192
- self.in_memory = true
193
- set_hash_key :group
194
- set_range_key :user_name
195
- end
196
- expect { TestClassWithStringRange.query(hash_key: 'registered', start: 'a') }.to raise_error TypeError
197
- end
198
- end
199
-
200
- context 'hash key does not exist' do
201
- it 'should return an empty array' do
202
- expect(TestClassWithRange.query(hash_key: 'non-existent key')).to eq([])
203
- end
204
- end
205
- end
206
-
207
122
  describe '.increment!' do
208
123
  context 'when incrementing a nil value' do
209
124
  it 'should save' do
@@ -277,36 +192,6 @@ describe Dynamini::Base do
277
192
  end
278
193
  end
279
194
 
280
- describe '.find_or_new' do
281
- context 'when a record with the given key exists' do
282
- it 'should return that record' do
283
- existing_record = Dynamini::Base.find_or_new(model.id)
284
- expect(existing_record.new_record?).to eq(false)
285
- expect(existing_record.id).to eq(model.id)
286
- end
287
-
288
- it 'should return the record for table with range key' do
289
- existing_record = TestClassWithRange.create!(foo: 1, bar: 123)
290
- expect(TestClassWithRange.find_or_new(existing_record.foo, existing_record.bar).new_record?).to eq(false)
291
- expect(existing_record.foo).to eq(1)
292
- expect(existing_record.bar).to eq(123)
293
- end
294
-
295
- end
296
- context 'when the key cannot be found' do
297
- it 'should initialize a new object with that key' do
298
- expect(Dynamini::Base.find_or_new('foo').new_record?).to be_truthy
299
- end
300
-
301
- it 'should initialize a new object with hash key and range key' do
302
- new_record = TestClassWithRange.find_or_new(1, 6)
303
- expect(new_record.new_record?).to be_truthy
304
- expect(new_record.foo).to eq(1)
305
- expect(new_record.bar).to eq(6)
306
- end
307
- end
308
- end
309
-
310
195
  describe '#==' do
311
196
  let(:model_a) { Dynamini::Base.new(model_attributes).tap {
312
197
  |model| model.send(:clear_changes)
@@ -672,40 +557,6 @@ describe Dynamini::Base do
672
557
  end
673
558
  end
674
559
 
675
- describe '.exists?' do
676
-
677
- context 'with hash key' do
678
- context 'the item exists' do
679
- it 'should return true' do
680
- expect(Dynamini::Base.exists?(model_attributes[:id])).to be_truthy
681
- end
682
- end
683
-
684
- context 'the item does not exist' do
685
- it 'should return false' do
686
- expect(Dynamini::Base.exists?('nonexistent id')).to eq(false)
687
- end
688
- end
689
- end
690
-
691
- context 'with hash key and range key' do
692
-
693
- it 'should return true if item exists' do
694
- TestClassWithRange.create!(foo: 'abc', bar: 123)
695
-
696
- expect(TestClassWithRange.exists?('abc', 123)).to eq(true)
697
- end
698
-
699
- it 'should return false if the item does not exist' do
700
- TestClassWithRange.create!(foo: 'abc', bar: 123)
701
-
702
- expect(TestClassWithRange.exists?('abc', 'nonexistent range key')).to eq(false)
703
- end
704
-
705
- end
706
- end
707
-
708
-
709
560
  describe '#new_record?' do
710
561
  it 'should return true for a new record' do
711
562
  expect(Dynamini::Base.new).to be_truthy
@@ -0,0 +1,178 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dynamini::Querying do
4
+
5
+ let(:model_attributes) {
6
+ {
7
+ name: 'Widget',
8
+ price: 9.99,
9
+ id: 'abcd1234',
10
+ hash_key: '009'
11
+ }
12
+ }
13
+
14
+ subject(:model) { Dynamini::Base.new(model_attributes) }
15
+
16
+ class TestClassWithRange < Dynamini::Base
17
+ set_hash_key :foo
18
+ set_range_key :bar
19
+ self.in_memory = true
20
+ handle :bar, :integer
21
+ end
22
+
23
+ describe '.find' do
24
+
25
+ before do
26
+ model.save
27
+ end
28
+
29
+ it 'should return a model with the retrieved attributes' do
30
+ found = Dynamini::Base.find('abcd1234')
31
+ expect(found.price).to eq(9.99)
32
+ expect(found.name).to eq('Widget')
33
+ expect(found.hash_key).to eq('009')
34
+ end
35
+
36
+ context 'when the object does not exist' do
37
+ it 'should raise an error' do
38
+ expect { Dynamini::Base.find('f') }.to raise_error 'Item not found.'
39
+ end
40
+
41
+ end
42
+
43
+ context 'when retrieving a subclass' do
44
+ class Foo < Dynamini::Base
45
+ self.in_memory = true
46
+ end
47
+
48
+ it 'should return the object as an instance of the subclass' do
49
+ Foo.create(id: '1')
50
+ expect(Foo.find('1')).to be_a Foo
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '.query' do
56
+ before do
57
+ 4.times do |i|
58
+ TestClassWithRange.create(foo: 'foo', bar: i + 1)
59
+ end
60
+ end
61
+ context 'start value provided' do
62
+ it 'should return records with a range key greater than or equal to the start value' do
63
+ records = TestClassWithRange.query(hash_key: 'foo', start: 2)
64
+ expect(records.length).to eq 3
65
+ expect(records.first.bar).to eq 2
66
+ expect(records.last.bar).to eq 4
67
+ end
68
+ end
69
+ context 'end value provided' do
70
+ it 'should return records with a range key less than or equal to the start value' do
71
+ records = TestClassWithRange.query(hash_key: 'foo', end: 2)
72
+ expect(records.length).to eq 2
73
+ expect(records.first.bar).to eq 1
74
+ expect(records.last.bar).to eq 2
75
+ end
76
+ end
77
+ context 'start and end values provided' do
78
+ it 'should return records between the two values inclusive' do
79
+ records = TestClassWithRange.query(hash_key: 'foo', start: 1, end: 3)
80
+ expect(records.length).to eq 3
81
+ expect(records.first.bar).to eq 1
82
+ expect(records.last.bar).to eq 3
83
+ end
84
+ end
85
+ context 'neither value provided' do
86
+ it 'should return all records belonging to that hash key' do
87
+ records = TestClassWithRange.query(hash_key: 'foo')
88
+ expect(records.length).to eq 4
89
+ expect(records.first.bar).to eq 1
90
+ expect(records.last.bar).to eq 4
91
+ end
92
+ end
93
+
94
+ context 'a non-numeric range field' do
95
+ it 'should raise an error' do
96
+ class TestClassWithStringRange < Dynamini::Base
97
+ self.in_memory = true
98
+ set_hash_key :group
99
+ set_range_key :user_name
100
+ end
101
+ expect { TestClassWithStringRange.query(hash_key: 'registered', start: 'a') }.to raise_error TypeError
102
+ end
103
+ end
104
+
105
+ context 'hash key does not exist' do
106
+ it 'should return an empty array' do
107
+ expect(TestClassWithRange.query(hash_key: 'non-existent key')).to eq([])
108
+ end
109
+ end
110
+ end
111
+
112
+ describe '.exists?' do
113
+ context 'with hash key' do
114
+ context 'the item exists' do
115
+ before do
116
+ model.save
117
+ end
118
+ it 'should return true' do
119
+ expect(Dynamini::Base.exists?(model_attributes[:id])).to be_truthy
120
+ end
121
+ end
122
+
123
+ context 'the item does not exist' do
124
+ it 'should return false' do
125
+ expect(Dynamini::Base.exists?('nonexistent id')).to eq(false)
126
+ end
127
+ end
128
+ end
129
+
130
+ context 'with hash key and range key' do
131
+
132
+ it 'should return true if item exists' do
133
+ TestClassWithRange.create!(foo: 'abc', bar: 123)
134
+
135
+ expect(TestClassWithRange.exists?('abc', 123)).to eq(true)
136
+ end
137
+
138
+ it 'should return false if the item does not exist' do
139
+ TestClassWithRange.create!(foo: 'abc', bar: 123)
140
+
141
+ expect(TestClassWithRange.exists?('abc', 'nonexistent range key')).to eq(false)
142
+ end
143
+ end
144
+ end
145
+
146
+ describe '.find_or_new' do
147
+ context 'when a record with the given key exists' do
148
+ before do
149
+ model.save
150
+ end
151
+ it 'should return that record' do
152
+ existing_record = Dynamini::Base.find_or_new(model.id)
153
+ expect(existing_record.new_record?).to eq(false)
154
+ expect(existing_record.id).to eq(model.id)
155
+ end
156
+
157
+ it 'should return the record for table with range key' do
158
+ existing_record = TestClassWithRange.create!(foo: 1, bar: 123)
159
+ expect(TestClassWithRange.find_or_new(existing_record.foo, existing_record.bar).new_record?).to eq(false)
160
+ expect(existing_record.foo).to eq(1)
161
+ expect(existing_record.bar).to eq(123)
162
+ end
163
+
164
+ end
165
+ context 'when the key cannot be found' do
166
+ it 'should initialize a new object with that key' do
167
+ expect(Dynamini::Base.find_or_new('foo').new_record?).to be_truthy
168
+ end
169
+
170
+ it 'should initialize a new object with hash key and range key' do
171
+ new_record = TestClassWithRange.find_or_new(1, 6)
172
+ expect(new_record.new_record?).to be_truthy
173
+ expect(new_record.foo).to eq(1)
174
+ expect(new_record.bar).to eq(6)
175
+ end
176
+ end
177
+ end
178
+ 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.10.1
4
+ version: 1.10.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greg Ward
@@ -21,104 +21,104 @@ dependencies:
21
21
  name: activemodel
22
22
  requirement: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3'
27
- - - "<"
27
+ - - <
28
28
  - !ruby/object:Gem::Version
29
29
  version: '5.0'
30
30
  type: :runtime
31
31
  prerelease: false
32
32
  version_requirements: !ruby/object:Gem::Requirement
33
33
  requirements:
34
- - - ">="
34
+ - - '>='
35
35
  - !ruby/object:Gem::Version
36
36
  version: '3'
37
- - - "<"
37
+ - - <
38
38
  - !ruby/object:Gem::Version
39
39
  version: '5.0'
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: aws-sdk
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
- - - "~>"
44
+ - - ~>
45
45
  - !ruby/object:Gem::Version
46
46
  version: '2'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
- - - "~>"
51
+ - - ~>
52
52
  - !ruby/object:Gem::Version
53
53
  version: '2'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: rspec
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
- - - "~>"
58
+ - - ~>
59
59
  - !ruby/object:Gem::Version
60
60
  version: '3'
61
61
  type: :development
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
- - - "~>"
65
+ - - ~>
66
66
  - !ruby/object:Gem::Version
67
67
  version: '3'
68
68
  - !ruby/object:Gem::Dependency
69
69
  name: pry
70
70
  requirement: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - "~>"
72
+ - - ~>
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
75
  type: :development
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
- - - "~>"
79
+ - - ~>
80
80
  - !ruby/object:Gem::Version
81
81
  version: '0'
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: fuubar
84
84
  requirement: !ruby/object:Gem::Requirement
85
85
  requirements:
86
- - - "~>"
86
+ - - ~>
87
87
  - !ruby/object:Gem::Version
88
88
  version: '2'
89
89
  type: :development
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
- - - "~>"
93
+ - - ~>
94
94
  - !ruby/object:Gem::Version
95
95
  version: '2'
96
96
  - !ruby/object:Gem::Dependency
97
97
  name: guard-rspec
98
98
  requirement: !ruby/object:Gem::Requirement
99
99
  requirements:
100
- - - ">="
100
+ - - '>='
101
101
  - !ruby/object:Gem::Version
102
102
  version: '0'
103
103
  type: :development
104
104
  prerelease: false
105
105
  version_requirements: !ruby/object:Gem::Requirement
106
106
  requirements:
107
- - - ">="
107
+ - - '>='
108
108
  - !ruby/object:Gem::Version
109
109
  version: '0'
110
110
  - !ruby/object:Gem::Dependency
111
111
  name: guard-shell
112
112
  requirement: !ruby/object:Gem::Requirement
113
113
  requirements:
114
- - - ">="
114
+ - - '>='
115
115
  - !ruby/object:Gem::Version
116
116
  version: '0'
117
117
  type: :development
118
118
  prerelease: false
119
119
  version_requirements: !ruby/object:Gem::Requirement
120
120
  requirements:
121
- - - ">="
121
+ - - '>='
122
122
  - !ruby/object:Gem::Version
123
123
  version: '0'
124
124
  description: |-
@@ -130,9 +130,9 @@ executables: []
130
130
  extensions: []
131
131
  extra_rdoc_files: []
132
132
  files:
133
- - ".gitignore"
134
- - ".rspec"
135
- - ".travis.yml"
133
+ - .gitignore
134
+ - .rspec
135
+ - .travis.yml
136
136
  - Gemfile
137
137
  - Gemfile.lock
138
138
  - Guardfile
@@ -145,9 +145,11 @@ files:
145
145
  - lib/dynamini/base.rb
146
146
  - lib/dynamini/batch_operations.rb
147
147
  - lib/dynamini/configuration.rb
148
+ - lib/dynamini/querying.rb
148
149
  - lib/dynamini/test_client.rb
149
150
  - spec/dynamini/base_spec.rb
150
151
  - spec/dynamini/batch_operations_spec.rb
152
+ - spec/dynamini/querying_spec.rb
151
153
  - spec/dynamini/test_client_spec.rb
152
154
  - spec/spec_helper.rb
153
155
  homepage: https://github.com/47colborne/dynamini
@@ -160,22 +162,23 @@ require_paths:
160
162
  - lib
161
163
  required_ruby_version: !ruby/object:Gem::Requirement
162
164
  requirements:
163
- - - ">="
165
+ - - '>='
164
166
  - !ruby/object:Gem::Version
165
167
  version: '0'
166
168
  required_rubygems_version: !ruby/object:Gem::Requirement
167
169
  requirements:
168
- - - ">="
170
+ - - '>='
169
171
  - !ruby/object:Gem::Version
170
172
  version: '0'
171
173
  requirements: []
172
174
  rubyforge_project:
173
- rubygems_version: 2.4.6
175
+ rubygems_version: 2.2.2
174
176
  signing_key:
175
177
  specification_version: 4
176
178
  summary: DynamoDB interface
177
179
  test_files:
178
180
  - spec/dynamini/base_spec.rb
179
181
  - spec/dynamini/batch_operations_spec.rb
182
+ - spec/dynamini/querying_spec.rb
180
183
  - spec/dynamini/test_client_spec.rb
181
184
  - spec/spec_helper.rb