adept_dynamoid 0.5.0.8 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/adept_dynamoid.gemspec +195 -0
- data/lib/dynamoid/adapter.rb +111 -23
- data/lib/dynamoid/adapter/aws_sdk.rb +23 -3
- data/lib/dynamoid/criteria/chain.rb +65 -1
- data/lib/dynamoid/fields.rb +2 -0
- data/spec/dynamoid/adapter/aws_sdk_spec.rb +135 -1
- data/spec/dynamoid/adapter_spec.rb +54 -1
- data/spec/dynamoid/criteria/chain_spec.rb +24 -0
- metadata +6 -3
data/Rakefile
CHANGED
@@ -14,11 +14,11 @@ require 'rake'
|
|
14
14
|
require 'jeweler'
|
15
15
|
Jeweler::Tasks.new do |gem|
|
16
16
|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
-
gem.name = "
|
17
|
+
gem.name = "dynamoid"
|
18
18
|
gem.homepage = "http://github.com/Veraticus/Dynamoid"
|
19
19
|
gem.license = "MIT"
|
20
20
|
gem.summary = "Dynamoid is an ORM for Amazon's DynamoDB"
|
21
|
-
gem.description = "Dynamoid is an ORM for Amazon's DynamoDB that supports offline development, associations, querying, and everything else you'd expect from an ActiveRecord-style replacement.
|
21
|
+
gem.description = "Dynamoid is an ORM for Amazon's DynamoDB that supports offline development, associations, querying, and everything else you'd expect from an ActiveRecord-style replacement."
|
22
22
|
gem.email = "josh@joshsymonds.com"
|
23
23
|
gem.authors = ["Josh Symonds"]
|
24
24
|
# dependencies defined in Gemfile
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.0.0
|
@@ -0,0 +1,195 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "adept_dynamoid"
|
8
|
+
s.version = "0.6.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Josh Symonds"]
|
12
|
+
s.date = "2012-12-05"
|
13
|
+
s.description = "Dynamoid is an ORM for Amazon's DynamoDB that supports offline development, associations, querying, and everything else you'd expect from an ActiveRecord-style replacement. Make sure you add require 'dynamoid' to before your configure script with adept_dynamoid"
|
14
|
+
s.email = "josh@joshsymonds.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.markdown"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".project",
|
22
|
+
".rspec",
|
23
|
+
"Dynamoid.gemspec",
|
24
|
+
"Gemfile",
|
25
|
+
"Gemfile.lock",
|
26
|
+
"LICENSE.txt",
|
27
|
+
"README.markdown",
|
28
|
+
"Rakefile",
|
29
|
+
"VERSION",
|
30
|
+
"adept_dynamoid.gemspec",
|
31
|
+
"doc/.nojekyll",
|
32
|
+
"doc/Dynamoid.html",
|
33
|
+
"doc/Dynamoid/Adapter.html",
|
34
|
+
"doc/Dynamoid/Adapter/AwsSdk.html",
|
35
|
+
"doc/Dynamoid/Adapter/Local.html",
|
36
|
+
"doc/Dynamoid/Associations.html",
|
37
|
+
"doc/Dynamoid/Associations/Association.html",
|
38
|
+
"doc/Dynamoid/Associations/BelongsTo.html",
|
39
|
+
"doc/Dynamoid/Associations/ClassMethods.html",
|
40
|
+
"doc/Dynamoid/Associations/HasAndBelongsToMany.html",
|
41
|
+
"doc/Dynamoid/Associations/HasMany.html",
|
42
|
+
"doc/Dynamoid/Associations/HasOne.html",
|
43
|
+
"doc/Dynamoid/Associations/ManyAssociation.html",
|
44
|
+
"doc/Dynamoid/Associations/SingleAssociation.html",
|
45
|
+
"doc/Dynamoid/Components.html",
|
46
|
+
"doc/Dynamoid/Config.html",
|
47
|
+
"doc/Dynamoid/Config/Options.html",
|
48
|
+
"doc/Dynamoid/Criteria.html",
|
49
|
+
"doc/Dynamoid/Criteria/Chain.html",
|
50
|
+
"doc/Dynamoid/Criteria/ClassMethods.html",
|
51
|
+
"doc/Dynamoid/Document.html",
|
52
|
+
"doc/Dynamoid/Document/ClassMethods.html",
|
53
|
+
"doc/Dynamoid/Errors.html",
|
54
|
+
"doc/Dynamoid/Errors/DocumentNotValid.html",
|
55
|
+
"doc/Dynamoid/Errors/Error.html",
|
56
|
+
"doc/Dynamoid/Errors/InvalidField.html",
|
57
|
+
"doc/Dynamoid/Errors/MissingRangeKey.html",
|
58
|
+
"doc/Dynamoid/Fields.html",
|
59
|
+
"doc/Dynamoid/Fields/ClassMethods.html",
|
60
|
+
"doc/Dynamoid/Finders.html",
|
61
|
+
"doc/Dynamoid/Finders/ClassMethods.html",
|
62
|
+
"doc/Dynamoid/Indexes.html",
|
63
|
+
"doc/Dynamoid/Indexes/ClassMethods.html",
|
64
|
+
"doc/Dynamoid/Indexes/Index.html",
|
65
|
+
"doc/Dynamoid/Persistence.html",
|
66
|
+
"doc/Dynamoid/Persistence/ClassMethods.html",
|
67
|
+
"doc/Dynamoid/Validations.html",
|
68
|
+
"doc/_index.html",
|
69
|
+
"doc/class_list.html",
|
70
|
+
"doc/css/common.css",
|
71
|
+
"doc/css/full_list.css",
|
72
|
+
"doc/css/style.css",
|
73
|
+
"doc/file.LICENSE.html",
|
74
|
+
"doc/file.README.html",
|
75
|
+
"doc/file_list.html",
|
76
|
+
"doc/frames.html",
|
77
|
+
"doc/index.html",
|
78
|
+
"doc/js/app.js",
|
79
|
+
"doc/js/full_list.js",
|
80
|
+
"doc/js/jquery.js",
|
81
|
+
"doc/method_list.html",
|
82
|
+
"doc/top-level-namespace.html",
|
83
|
+
"lib/dynamoid.rb",
|
84
|
+
"lib/dynamoid/adapter.rb",
|
85
|
+
"lib/dynamoid/adapter/aws_sdk.rb",
|
86
|
+
"lib/dynamoid/associations.rb",
|
87
|
+
"lib/dynamoid/associations/association.rb",
|
88
|
+
"lib/dynamoid/associations/belongs_to.rb",
|
89
|
+
"lib/dynamoid/associations/has_and_belongs_to_many.rb",
|
90
|
+
"lib/dynamoid/associations/has_many.rb",
|
91
|
+
"lib/dynamoid/associations/has_one.rb",
|
92
|
+
"lib/dynamoid/associations/many_association.rb",
|
93
|
+
"lib/dynamoid/associations/single_association.rb",
|
94
|
+
"lib/dynamoid/components.rb",
|
95
|
+
"lib/dynamoid/config.rb",
|
96
|
+
"lib/dynamoid/config/options.rb",
|
97
|
+
"lib/dynamoid/criteria.rb",
|
98
|
+
"lib/dynamoid/criteria/chain.rb",
|
99
|
+
"lib/dynamoid/dirty.rb",
|
100
|
+
"lib/dynamoid/document.rb",
|
101
|
+
"lib/dynamoid/errors.rb",
|
102
|
+
"lib/dynamoid/fields.rb",
|
103
|
+
"lib/dynamoid/finders.rb",
|
104
|
+
"lib/dynamoid/identity_map.rb",
|
105
|
+
"lib/dynamoid/indexes.rb",
|
106
|
+
"lib/dynamoid/indexes/index.rb",
|
107
|
+
"lib/dynamoid/middleware/identity_map.rb",
|
108
|
+
"lib/dynamoid/persistence.rb",
|
109
|
+
"lib/dynamoid/validations.rb",
|
110
|
+
"spec/app/models/address.rb",
|
111
|
+
"spec/app/models/camel_case.rb",
|
112
|
+
"spec/app/models/magazine.rb",
|
113
|
+
"spec/app/models/message.rb",
|
114
|
+
"spec/app/models/sponsor.rb",
|
115
|
+
"spec/app/models/subscription.rb",
|
116
|
+
"spec/app/models/tweet.rb",
|
117
|
+
"spec/app/models/user.rb",
|
118
|
+
"spec/dynamoid/adapter/aws_sdk_spec.rb",
|
119
|
+
"spec/dynamoid/adapter_spec.rb",
|
120
|
+
"spec/dynamoid/associations/association_spec.rb",
|
121
|
+
"spec/dynamoid/associations/belongs_to_spec.rb",
|
122
|
+
"spec/dynamoid/associations/has_and_belongs_to_many_spec.rb",
|
123
|
+
"spec/dynamoid/associations/has_many_spec.rb",
|
124
|
+
"spec/dynamoid/associations/has_one_spec.rb",
|
125
|
+
"spec/dynamoid/associations_spec.rb",
|
126
|
+
"spec/dynamoid/config_spec.rb",
|
127
|
+
"spec/dynamoid/criteria/chain_spec.rb",
|
128
|
+
"spec/dynamoid/criteria_spec.rb",
|
129
|
+
"spec/dynamoid/dirty_spec.rb",
|
130
|
+
"spec/dynamoid/document_spec.rb",
|
131
|
+
"spec/dynamoid/fields_spec.rb",
|
132
|
+
"spec/dynamoid/finders_spec.rb",
|
133
|
+
"spec/dynamoid/identity_map_spec.rb",
|
134
|
+
"spec/dynamoid/indexes/index_spec.rb",
|
135
|
+
"spec/dynamoid/indexes_spec.rb",
|
136
|
+
"spec/dynamoid/persistence_spec.rb",
|
137
|
+
"spec/dynamoid/validations_spec.rb",
|
138
|
+
"spec/dynamoid_spec.rb",
|
139
|
+
"spec/spec_helper.rb"
|
140
|
+
]
|
141
|
+
s.homepage = "http://github.com/Veraticus/Dynamoid"
|
142
|
+
s.licenses = ["MIT"]
|
143
|
+
s.require_paths = ["lib"]
|
144
|
+
s.rubygems_version = "1.8.24"
|
145
|
+
s.summary = "Dynamoid is an ORM for Amazon's DynamoDB"
|
146
|
+
|
147
|
+
if s.respond_to? :specification_version then
|
148
|
+
s.specification_version = 3
|
149
|
+
|
150
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
151
|
+
s.add_runtime_dependency(%q<activemodel>, [">= 0"])
|
152
|
+
s.add_runtime_dependency(%q<tzinfo>, [">= 0"])
|
153
|
+
s.add_runtime_dependency(%q<aws-sdk>, [">= 0"])
|
154
|
+
s.add_development_dependency(%q<rake>, [">= 0"])
|
155
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
156
|
+
s.add_development_dependency(%q<bundler>, [">= 0"])
|
157
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
158
|
+
s.add_development_dependency(%q<yard>, [">= 0"])
|
159
|
+
s.add_development_dependency(%q<redcarpet>, ["= 1.17.2"])
|
160
|
+
s.add_development_dependency(%q<github-markup>, [">= 0"])
|
161
|
+
s.add_development_dependency(%q<pry>, [">= 0"])
|
162
|
+
s.add_development_dependency(%q<fake_dynamo>, [">= 0"])
|
163
|
+
s.add_development_dependency(%q<mocha>, ["= 0.10.0"])
|
164
|
+
else
|
165
|
+
s.add_dependency(%q<activemodel>, [">= 0"])
|
166
|
+
s.add_dependency(%q<tzinfo>, [">= 0"])
|
167
|
+
s.add_dependency(%q<aws-sdk>, [">= 0"])
|
168
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
169
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
170
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
171
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
172
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
173
|
+
s.add_dependency(%q<redcarpet>, ["= 1.17.2"])
|
174
|
+
s.add_dependency(%q<github-markup>, [">= 0"])
|
175
|
+
s.add_dependency(%q<pry>, [">= 0"])
|
176
|
+
s.add_dependency(%q<fake_dynamo>, [">= 0"])
|
177
|
+
s.add_dependency(%q<mocha>, ["= 0.10.0"])
|
178
|
+
end
|
179
|
+
else
|
180
|
+
s.add_dependency(%q<activemodel>, [">= 0"])
|
181
|
+
s.add_dependency(%q<tzinfo>, [">= 0"])
|
182
|
+
s.add_dependency(%q<aws-sdk>, [">= 0"])
|
183
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
184
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
185
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
186
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
187
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
188
|
+
s.add_dependency(%q<redcarpet>, ["= 1.17.2"])
|
189
|
+
s.add_dependency(%q<github-markup>, [">= 0"])
|
190
|
+
s.add_dependency(%q<pry>, [">= 0"])
|
191
|
+
s.add_dependency(%q<fake_dynamo>, [">= 0"])
|
192
|
+
s.add_dependency(%q<mocha>, ["= 0.10.0"])
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
data/lib/dynamoid/adapter.rb
CHANGED
@@ -73,7 +73,7 @@ module Dynamoid
|
|
73
73
|
ids = ids.collect{|id| range_key ? [id, range_key] : id}
|
74
74
|
if Dynamoid::Config.partitioning?
|
75
75
|
results = batch_get_item(table => id_with_partitions(ids))
|
76
|
-
{table => result_for_partition(results[table])}
|
76
|
+
{table => result_for_partition(results[table],table)}
|
77
77
|
else
|
78
78
|
batch_get_item(table => ids)
|
79
79
|
end
|
@@ -81,7 +81,7 @@ module Dynamoid
|
|
81
81
|
if Dynamoid::Config.partitioning?
|
82
82
|
ids = range_key ? [[ids, range_key]] : ids
|
83
83
|
results = batch_get_item(table => id_with_partitions(ids))
|
84
|
-
result_for_partition(results[table]).first
|
84
|
+
result_for_partition(results[table],table).first
|
85
85
|
else
|
86
86
|
get_item(table, ids, options)
|
87
87
|
end
|
@@ -91,15 +91,31 @@ module Dynamoid
|
|
91
91
|
# Delete an item from a table. If partitioning is turned on, deletes all partitioned keys as well.
|
92
92
|
#
|
93
93
|
# @param [String] table the name of the table to write the object to
|
94
|
-
# @param [
|
95
|
-
# @param [
|
94
|
+
# @param [Array] ids to delete, can also be a string of just one id
|
95
|
+
# @param [Array] range_key of the record to delete, can also be a string of just one range_key
|
96
96
|
#
|
97
|
-
|
98
|
-
|
99
|
-
if
|
100
|
-
|
97
|
+
def delete(table, ids, options = {})
|
98
|
+
range_key = options[:range_key] #array of range keys that matches the ids passed in
|
99
|
+
if ids.respond_to?(:each)
|
100
|
+
if range_key.respond_to?(:each)
|
101
|
+
#turn ids into array of arrays each element being hash_key, range_key
|
102
|
+
ids = ids.each_with_index.map{|id,i| [id,range_key[i]]}
|
103
|
+
else
|
104
|
+
ids = range_key ? [[ids, range_key]] : ids
|
105
|
+
end
|
106
|
+
|
107
|
+
if Dynamoid::Config.partitioning?
|
108
|
+
batch_delete_item(table => id_with_partitions(ids))
|
109
|
+
else
|
110
|
+
batch_delete_item(table => ids)
|
111
|
+
end
|
101
112
|
else
|
102
|
-
|
113
|
+
if Dynamoid::Config.partitioning?
|
114
|
+
ids = range_key ? [[ids, range_key]] : ids
|
115
|
+
batch_delete_item(table => id_with_partitions(ids))
|
116
|
+
else
|
117
|
+
delete_item(table, ids, options)
|
118
|
+
end
|
103
119
|
end
|
104
120
|
end
|
105
121
|
|
@@ -112,7 +128,7 @@ module Dynamoid
|
|
112
128
|
def scan(table, query, opts = {})
|
113
129
|
if Dynamoid::Config.partitioning?
|
114
130
|
results = benchmark('Scan', table, query) {adapter.scan(table, query, opts)}
|
115
|
-
result_for_partition(results)
|
131
|
+
result_for_partition(results,table)
|
116
132
|
else
|
117
133
|
benchmark('Scan', table, query) {adapter.scan(table, query, opts)}
|
118
134
|
end
|
@@ -141,27 +157,59 @@ module Dynamoid
|
|
141
157
|
def id_with_partitions(ids)
|
142
158
|
Array(ids).collect {|id| (0...Dynamoid::Config.partition_size).collect{|n| id.is_a?(Array) ? ["#{id.first}.#{n}", id.last] : "#{id}.#{n}"}}.flatten(1)
|
143
159
|
end
|
160
|
+
|
161
|
+
#Get original id (hash_key) and partiton number from a hash_key
|
162
|
+
#
|
163
|
+
# @param [String] id the id or hash_key of a record, ex. xxxxx.13
|
164
|
+
#
|
165
|
+
# @return [String,String] original_id and the partition number, ex original_id = xxxxx partition = 13
|
166
|
+
def get_original_id_and_partition id
|
167
|
+
partition = id.split('.').last
|
168
|
+
id = id.split(".#{partition}").first
|
169
|
+
|
170
|
+
return id, partition
|
171
|
+
end
|
144
172
|
|
145
|
-
# Takes an array of results that are partitioned, find the most recently updated
|
173
|
+
# Takes an array of query results that are partitioned, find the most recently updated ones that share an id and range_key, and return only the most recently updated. Compares each result by
|
146
174
|
# their id and updated_at attributes; if the updated_at is the greatest, then it must be the correct result.
|
147
175
|
#
|
148
176
|
# @param [Array] returned partitioned results from a query
|
177
|
+
# @param [String] table_name the name of the table
|
149
178
|
#
|
150
179
|
# @since 0.2.0
|
151
|
-
def result_for_partition(results)
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
180
|
+
def result_for_partition(results, table_name)
|
181
|
+
table = Dynamoid::Adapter::AwsSdk.get_table(table_name)
|
182
|
+
|
183
|
+
if table.range_key
|
184
|
+
range_key_name = table.range_key.name.to_sym
|
185
|
+
|
186
|
+
final_hash = {}
|
187
|
+
|
188
|
+
results.each do |record|
|
189
|
+
test_record = final_hash[record[range_key_name]]
|
158
190
|
|
159
|
-
if
|
160
|
-
|
161
|
-
|
191
|
+
if test_record.nil? || ((record[range_key_name] == test_record[range_key_name]) && (record[:updated_at] > test_record[:updated_at]))
|
192
|
+
#get ride of our partition and put it in the array with the range key
|
193
|
+
record[:id], partition = get_original_id_and_partition record[:id]
|
194
|
+
final_hash[record[range_key_name]] = record
|
162
195
|
end
|
163
196
|
end
|
164
|
-
|
197
|
+
|
198
|
+
return final_hash.values
|
199
|
+
else
|
200
|
+
{}.tap do |hash|
|
201
|
+
Array(results).each do |result|
|
202
|
+
next if result.nil?
|
203
|
+
#Need to find the value of id with out the . and partition number
|
204
|
+
id, partition = get_original_id_and_partition result[:id]
|
205
|
+
|
206
|
+
if !hash[id] || (result[:updated_at] > hash[id][:updated_at])
|
207
|
+
result[:id] = id
|
208
|
+
hash[id] = result
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end.values
|
212
|
+
end
|
165
213
|
end
|
166
214
|
|
167
215
|
# Delegate all methods that aren't defind here to the underlying adapter.
|
@@ -171,7 +219,47 @@ module Dynamoid
|
|
171
219
|
return benchmark(method, *args) {adapter.send(method, *args, &block)} if @adapter.respond_to?(method)
|
172
220
|
super
|
173
221
|
end
|
222
|
+
|
223
|
+
# Query the DynamoDB table. This employs DynamoDB's indexes so is generally faster than scanning, but is
|
224
|
+
# only really useful for range queries, since it can only find by one hash key at once. Only provide
|
225
|
+
# one range key to the hash. If paritioning is on, will run a query for every parition and join the results
|
226
|
+
#
|
227
|
+
# @param [String] table_name the name of the table
|
228
|
+
# @param [Hash] opts the options to query the table with
|
229
|
+
# @option opts [String] :hash_value the value of the hash key to find
|
230
|
+
# @option opts [Range] :range_value find the range key within this range
|
231
|
+
# @option opts [Number] :range_greater_than find range keys greater than this
|
232
|
+
# @option opts [Number] :range_less_than find range keys less than this
|
233
|
+
# @option opts [Number] :range_gte find range keys greater than or equal to this
|
234
|
+
# @option opts [Number] :range_lte find range keys less than or equal to this
|
235
|
+
#
|
236
|
+
# @return [Array] an array of all matching items
|
237
|
+
#
|
238
|
+
def query(table_name, opts = {})
|
239
|
+
|
240
|
+
unless Dynamoid::Config.partitioning?
|
241
|
+
#no paritioning? just pass to the standard query method
|
242
|
+
Dynamoid::Adapter::AwsSdk.query(table_name, opts)
|
243
|
+
else
|
244
|
+
#get all the hash_values that could be possible
|
245
|
+
ids = id_with_partitions(opts[:hash_value])
|
174
246
|
|
175
|
-
|
247
|
+
#lets not overwrite with the original options
|
248
|
+
modified_options = opts.clone
|
249
|
+
results = []
|
250
|
+
|
251
|
+
#loop and query on each of the partition ids
|
252
|
+
ids.each do |id|
|
253
|
+
modified_options[:hash_value] = id
|
254
|
+
|
255
|
+
query_result = Dynamoid::Adapter::AwsSdk.query(table_name, modified_options)
|
256
|
+
query_result = [query_result] if !query_result.is_a?(Array)
|
176
257
|
|
258
|
+
results = results + query_result unless query_result.nil?
|
259
|
+
end
|
260
|
+
|
261
|
+
result_for_partition results, table_name
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
177
265
|
end
|
@@ -54,6 +54,29 @@ module Dynamoid
|
|
54
54
|
end
|
55
55
|
hash
|
56
56
|
end
|
57
|
+
|
58
|
+
# Delete many items at once from DynamoDB. More efficient than delete each item individually.
|
59
|
+
#
|
60
|
+
# @example Delete IDs 1 and 2 from the table testtable
|
61
|
+
# Dynamoid::Adapter::AwsSdk.batch_delete_item('table1' => ['1', '2'])
|
62
|
+
#or
|
63
|
+
# Dynamoid::Adapter::AwsSdk.batch_delete_item('table1' => [['hk1', 'rk2'], ['hk1', 'rk2']]]))
|
64
|
+
#
|
65
|
+
# @param [Hash] options the hash of tables and IDs to delete
|
66
|
+
#
|
67
|
+
# @return nil
|
68
|
+
#
|
69
|
+
def batch_delete_item(options)
|
70
|
+
return nil if options.all?{|k, v| v.empty?}
|
71
|
+
options.each do |t, ids|
|
72
|
+
Array(ids).in_groups_of(25, false) do |group|
|
73
|
+
batch = AWS::DynamoDB::BatchWrite.new(:config => @@connection.config)
|
74
|
+
batch.delete(t,group)
|
75
|
+
batch.process!
|
76
|
+
end
|
77
|
+
end
|
78
|
+
nil
|
79
|
+
end
|
57
80
|
|
58
81
|
# Create a table on DynamoDB. This usually takes a long time to complete.
|
59
82
|
#
|
@@ -111,9 +134,6 @@ module Dynamoid
|
|
111
134
|
# @return [Hash] a hash representing the raw item in DynamoDB
|
112
135
|
#
|
113
136
|
# @since 0.2.0
|
114
|
-
|
115
|
-
|
116
|
-
|
117
137
|
def get_item(table_name, key, options = {})
|
118
138
|
range_key = options.delete(:range_key)
|
119
139
|
table = get_table(table_name)
|
@@ -46,6 +46,63 @@ module Dynamoid #:nodoc:
|
|
46
46
|
def all
|
47
47
|
records
|
48
48
|
end
|
49
|
+
|
50
|
+
# Destroys all the records matching the criteria.
|
51
|
+
#
|
52
|
+
def destroy_all
|
53
|
+
ids = []
|
54
|
+
|
55
|
+
if range?
|
56
|
+
ranges = []
|
57
|
+
Dynamoid::Adapter.query(source.table_name, range_query).collect do |hash|
|
58
|
+
ids << hash[source.hash_key.to_sym]
|
59
|
+
ranges << hash[source.range_key.to_sym]
|
60
|
+
end
|
61
|
+
|
62
|
+
Dynamoid::Adapter.delete(source.table_name, ids,{:range_key => ranges})
|
63
|
+
elsif index
|
64
|
+
#TODO: test this throughly and find a way to delete all index table records for one source record
|
65
|
+
if index.range_key?
|
66
|
+
results = Dynamoid::Adapter.query(index.table_name, index_query.merge(consistent_opts))
|
67
|
+
else
|
68
|
+
results = Dynamoid::Adapter.read(index.table_name, index_query[:hash_value], consistent_opts)
|
69
|
+
end
|
70
|
+
|
71
|
+
results.collect do |hash|
|
72
|
+
ids << hash[source.hash_key.to_sym]
|
73
|
+
index_ranges << hash[source.range_key.to_sym]
|
74
|
+
end
|
75
|
+
|
76
|
+
unless ids.nil? || ids.empty?
|
77
|
+
ids = ids.to_a
|
78
|
+
|
79
|
+
if @start
|
80
|
+
ids = ids.drop_while { |id| id != @start.hash_key }.drop(1)
|
81
|
+
index_ranges = index_ranges.drop_while { |range| range != @start.hash_key }.drop(1) unless index_ranges.nil?
|
82
|
+
end
|
83
|
+
|
84
|
+
if @limit
|
85
|
+
ids = ids.take(@limit)
|
86
|
+
index_ranges = index_ranges.take(@limit)
|
87
|
+
end
|
88
|
+
|
89
|
+
Dynamoid::Adapter.delete(source.table_name, ids)
|
90
|
+
|
91
|
+
if index.range_key?
|
92
|
+
Dynamoid::Adapter.delete(index.table_name, ids,{:range_key => index_ranges})
|
93
|
+
else
|
94
|
+
Dynamoid::Adapter.delete(index.table_name, ids)
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
else
|
99
|
+
Dynamoid::Adapter.scan(source.table_name, query, scan_opts).collect do |hash|
|
100
|
+
ids << hash[source.hash_key.to_sym]
|
101
|
+
end
|
102
|
+
|
103
|
+
Dynamoid::Adapter.delete(source.table_name, ids)
|
104
|
+
end
|
105
|
+
end
|
49
106
|
|
50
107
|
# Returns the first record matching the criteria.
|
51
108
|
#
|
@@ -151,7 +208,7 @@ module Dynamoid #:nodoc:
|
|
151
208
|
raise Dynamoid::Errors::InvalidQuery, 'Consistent read is not supported by SCAN operation'
|
152
209
|
end
|
153
210
|
|
154
|
-
Dynamoid::Adapter.scan(source.table_name, query,
|
211
|
+
Dynamoid::Adapter.scan(source.table_name, query, scan_opts).collect {|hash| source.from_database(hash) }
|
155
212
|
end
|
156
213
|
|
157
214
|
# Format the provided query so that it can be used to query results from DynamoDB.
|
@@ -236,6 +293,13 @@ module Dynamoid #:nodoc:
|
|
236
293
|
opts[:scan_index_forward] = @scan_index_forward
|
237
294
|
opts
|
238
295
|
end
|
296
|
+
|
297
|
+
def scan_opts
|
298
|
+
opts = {}
|
299
|
+
opts[:limit] = @limit if @limit
|
300
|
+
opts[:next_token] = start_key if @start
|
301
|
+
opts
|
302
|
+
end
|
239
303
|
end
|
240
304
|
|
241
305
|
end
|
data/lib/dynamoid/fields.rb
CHANGED
@@ -16,7 +16,7 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
context 'with a preexisting table' do
|
19
|
+
context 'with a preexisting table without paritioning' do
|
20
20
|
before(:all) do
|
21
21
|
Dynamoid::Adapter.create_table('dynamoid_tests_TestTable1', :id) unless Dynamoid::Adapter.list_tables.include?('dynamoid_tests_TestTable1')
|
22
22
|
Dynamoid::Adapter.create_table('dynamoid_tests_TestTable2', :id) unless Dynamoid::Adapter.list_tables.include?('dynamoid_tests_TestTable2')
|
@@ -99,6 +99,56 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
99
99
|
results['dynamoid_tests_TestTable3'].should include({:name => 'Josh', :id => '1', :range => 1.0})
|
100
100
|
results['dynamoid_tests_TestTable3'].should include({:name => 'Justin', :id => '2', :range => 2.0})
|
101
101
|
end
|
102
|
+
|
103
|
+
# BatchDeleteItem
|
104
|
+
it "performs BatchDeleteItem with singular keys" do
|
105
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '1', :name => 'Josh'})
|
106
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable2', {:id => '1', :name => 'Justin'})
|
107
|
+
|
108
|
+
Dynamoid::Adapter.batch_delete_item('dynamoid_tests_TestTable1' => ['1'], 'dynamoid_tests_TestTable2' => ['1'])
|
109
|
+
|
110
|
+
results = Dynamoid::Adapter.batch_get_item('dynamoid_tests_TestTable1' => '1', 'dynamoid_tests_TestTable2' => '1')
|
111
|
+
results.size.should == 0
|
112
|
+
|
113
|
+
results['dynamoid_tests_TestTable1'].should_not include({:name => 'Josh', :id => '1'})
|
114
|
+
results['dynamoid_tests_TestTable2'].should_not include({:name => 'Justin', :id => '1'})
|
115
|
+
end
|
116
|
+
|
117
|
+
it "performs BatchDeleteItem with multiple keys" do
|
118
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '1', :name => 'Josh'})
|
119
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '2', :name => 'Justin'})
|
120
|
+
|
121
|
+
Dynamoid::Adapter.batch_delete_item('dynamoid_tests_TestTable1' => ['1', '2'])
|
122
|
+
|
123
|
+
results = Dynamoid::Adapter.batch_get_item('dynamoid_tests_TestTable1' => ['1', '2'])
|
124
|
+
results.size.should == 0
|
125
|
+
|
126
|
+
results['dynamoid_tests_TestTable1'].should_not include({:name => 'Josh', :id => '1'})
|
127
|
+
results['dynamoid_tests_TestTable1'].should_not include({:name => 'Justin', :id => '2'})
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'performs BatchDeleteItem with one ranged key' do
|
131
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '1', :name => 'Josh', :range => 1.0})
|
132
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '2', :name => 'Justin', :range => 2.0})
|
133
|
+
|
134
|
+
Dynamoid::Adapter.batch_delete_item('dynamoid_tests_TestTable3' => [['1', 1.0]])
|
135
|
+
results = Dynamoid::Adapter.batch_get_item('dynamoid_tests_TestTable3' => [['1', 1.0]])
|
136
|
+
results.size.should == 0
|
137
|
+
|
138
|
+
results['dynamoid_tests_TestTable3'].should_not include({:name => 'Josh', :id => '1', :range => 1.0})
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'performs BatchDeleteItem with multiple ranged keys' do
|
142
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '1', :name => 'Josh', :range => 1.0})
|
143
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '2', :name => 'Justin', :range => 2.0})
|
144
|
+
|
145
|
+
Dynamoid::Adapter.batch_delete_item('dynamoid_tests_TestTable3' => [['1', 1.0],['2', 2.0]])
|
146
|
+
results = Dynamoid::Adapter.batch_get_item('dynamoid_tests_TestTable3' => [['1', 1.0],['2', 2.0]])
|
147
|
+
results.size.should == 0
|
148
|
+
|
149
|
+
results['dynamoid_tests_TestTable3'].should_not include({:name => 'Josh', :id => '1', :range => 1.0})
|
150
|
+
results['dynamoid_tests_TestTable3'].should_not include({:name => 'Justin', :id => '2', :range => 2.0})
|
151
|
+
end
|
102
152
|
|
103
153
|
# ListTables
|
104
154
|
it 'performs ListTables' do
|
@@ -175,6 +225,90 @@ describe Dynamoid::Adapter::AwsSdk do
|
|
175
225
|
Dynamoid::Adapter.scan('dynamoid_tests_TestTable1', {}).should include({:name=>"Josh", :id=>"2"}, {:name=>"Josh", :id=>"1"})
|
176
226
|
end
|
177
227
|
end
|
228
|
+
|
229
|
+
context 'with a preexisting table with paritioning' do
|
230
|
+
before(:all) do
|
231
|
+
@previous_value = Dynamoid::Config.partitioning
|
232
|
+
Dynamoid::Config.partitioning = true
|
233
|
+
|
234
|
+
Dynamoid::Adapter.create_table('dynamoid_tests_TestTable1', :id) unless Dynamoid::Adapter.list_tables.include?('dynamoid_tests_TestTable1')
|
235
|
+
Dynamoid::Adapter.create_table('dynamoid_tests_TestTable2', :id) unless Dynamoid::Adapter.list_tables.include?('dynamoid_tests_TestTable2')
|
236
|
+
Dynamoid::Adapter.create_table('dynamoid_tests_TestTable3', :id, :range_key => { :range => :number }) unless Dynamoid::Adapter.list_tables.include?('dynamoid_tests_TestTable3')
|
237
|
+
end
|
238
|
+
|
239
|
+
after(:all) do
|
240
|
+
Dynamoid::Config.partitioning = @previous_value
|
241
|
+
end
|
242
|
+
|
243
|
+
# Query
|
244
|
+
it 'performs query on a table and returns items' do
|
245
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '1.1', :name => 'Josh'})
|
246
|
+
|
247
|
+
Dynamoid::Adapter.query('dynamoid_tests_TestTable1', :hash_value => '1').first.should == { :id=> '1', :name=>"Josh" }
|
248
|
+
end
|
249
|
+
|
250
|
+
it 'performs query on a table and returns items if there are multiple items' do
|
251
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '1.1', :name => 'Josh'})
|
252
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '2.1', :name => 'Justin'})
|
253
|
+
|
254
|
+
Dynamoid::Adapter.query('dynamoid_tests_TestTable1', :hash_value => '1').first.should == { :id=> '1', :name=>"Josh" }
|
255
|
+
end
|
256
|
+
|
257
|
+
context 'range queries' do
|
258
|
+
before do
|
259
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '1.1', :range => 1.0})
|
260
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable3', {:id => '1.1', :range => 3.0})
|
261
|
+
end
|
262
|
+
|
263
|
+
it 'performs query on a table with a range and selects items in a range' do
|
264
|
+
Dynamoid::Adapter.query('dynamoid_tests_TestTable3', :hash_value => '1', :range_value => 0.0..3.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'performs query on a table with a range and selects items greater than' do
|
268
|
+
Dynamoid::Adapter.query('dynamoid_tests_TestTable3', :hash_value => '1', :range_greater_than => 1.0).should =~ [{:id => '1', :range => BigDecimal.new(3)}]
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'performs query on a table with a range and selects items less than' do
|
272
|
+
Dynamoid::Adapter.query('dynamoid_tests_TestTable3', :hash_value => '1', :range_less_than => 2.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}]
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'performs query on a table with a range and selects items gte' do
|
276
|
+
Dynamoid::Adapter.query('dynamoid_tests_TestTable3', :hash_value => '1', :range_gte => 1.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'performs query on a table with a range and selects items lte' do
|
280
|
+
Dynamoid::Adapter.query('dynamoid_tests_TestTable3', :hash_value => '1', :range_lte => 3.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
# Scan
|
285
|
+
it 'performs scan on a table and returns items' do
|
286
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '1.1', :name => 'Josh'})
|
287
|
+
|
288
|
+
Dynamoid::Adapter.scan('dynamoid_tests_TestTable1', :name => 'Josh').should == [{ :id=> '1', :name=>"Josh" }]
|
289
|
+
end
|
290
|
+
|
291
|
+
it 'performs scan on a table and returns items if there are multiple items but only one match' do
|
292
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '1.1', :name => 'Josh'})
|
293
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '2.1', :name => 'Justin'})
|
294
|
+
|
295
|
+
Dynamoid::Adapter.scan('dynamoid_tests_TestTable1', :name => 'Josh').should == [{ :id=> '1', :name=>"Josh" }]
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'performs scan on a table and returns multiple items if there are multiple matches' do
|
299
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '1.1', :name => 'Josh'})
|
300
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '2.1', :name => 'Josh'})
|
301
|
+
|
302
|
+
Dynamoid::Adapter.scan('dynamoid_tests_TestTable1', :name => 'Josh').should include({:name=>"Josh", :id=>"2"}, {:name=>"Josh", :id=>"1"})
|
303
|
+
end
|
304
|
+
|
305
|
+
it 'performs scan on a table and returns all items if no criteria are specified' do
|
306
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '1.1', :name => 'Josh'})
|
307
|
+
Dynamoid::Adapter.put_item('dynamoid_tests_TestTable1', {:id => '2.1', :name => 'Josh'})
|
308
|
+
|
309
|
+
Dynamoid::Adapter.scan('dynamoid_tests_TestTable1', {}).should include({:name=>"Josh", :id=>"2"}, {:name=>"Josh", :id=>"1"})
|
310
|
+
end
|
311
|
+
end
|
178
312
|
|
179
313
|
# DescribeTable
|
180
314
|
|
@@ -42,6 +42,18 @@ describe "Dynamoid::Adapter" do
|
|
42
42
|
Dynamoid::Adapter.read('dynamoid_tests_TestTable', ['1', '2'])
|
43
43
|
end
|
44
44
|
|
45
|
+
it 'delete through the adapter for one ID' do
|
46
|
+
Dynamoid::Adapter.expects(:delete_item).with('dynamoid_tests_TestTable', '123', {}).returns(nil)
|
47
|
+
|
48
|
+
Dynamoid::Adapter.delete('dynamoid_tests_TestTable', '123')
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'deletes through the adapter for many IDs' do
|
52
|
+
Dynamoid::Adapter.expects(:batch_delete_item).with({'dynamoid_tests_TestTable' => ['1', '2']}).returns(nil)
|
53
|
+
|
54
|
+
Dynamoid::Adapter.delete('dynamoid_tests_TestTable', ['1', '2'])
|
55
|
+
end
|
56
|
+
|
45
57
|
it 'reads through the adapter for one ID and a range key' do
|
46
58
|
Dynamoid::Adapter.expects(:get_item).with('dynamoid_tests_TestTable', '123', :range_key => 2.0).returns(true)
|
47
59
|
|
@@ -53,6 +65,18 @@ describe "Dynamoid::Adapter" do
|
|
53
65
|
|
54
66
|
Dynamoid::Adapter.read('dynamoid_tests_TestTable', ['1', '2'], :range_key => 2.0)
|
55
67
|
end
|
68
|
+
|
69
|
+
it 'deletes through the adapter for one ID and a range key' do
|
70
|
+
Dynamoid::Adapter.expects(:delete_item).with('dynamoid_tests_TestTable', '123', :range_key => 2.0).returns(nil)
|
71
|
+
|
72
|
+
Dynamoid::Adapter.delete('dynamoid_tests_TestTable', '123', :range_key => 2.0)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'deletes through the adapter for many IDs and a range key' do
|
76
|
+
Dynamoid::Adapter.expects(:batch_delete_item).with({'dynamoid_tests_TestTable' => [['1', 2.0], ['2', 2.0]]}).returns(nil)
|
77
|
+
|
78
|
+
Dynamoid::Adapter.delete('dynamoid_tests_TestTable', ['1', '2'], :range_key => [2.0,2.0])
|
79
|
+
end
|
56
80
|
end
|
57
81
|
|
58
82
|
context 'with partitioning' do
|
@@ -109,9 +133,38 @@ describe "Dynamoid::Adapter" do
|
|
109
133
|
@time = DateTime.now
|
110
134
|
@array =[{:id => '1.0', :updated_at => @time - 6.hours}, {:id => '1.1', :updated_at => @time - 3.hours}, {:id => '1.2', :updated_at => @time - 1.hour}, {:id => '1.3', :updated_at => @time - 6.hours}, {:id => '2.0', :updated_at => @time}]
|
111
135
|
|
112
|
-
Dynamoid::Adapter.result_for_partition(@array).should =~ [{:id => '1', :updated_at => @time - 1.hour}, {:id => '2', :updated_at => @time}]
|
136
|
+
Dynamoid::Adapter.result_for_partition(@array,"dynamoid_tests_TestTable").should =~ [{:id => '1', :updated_at => @time - 1.hour}, {:id => '2', :updated_at => @time}]
|
113
137
|
end
|
114
138
|
|
139
|
+
it 'returns a valid original id and partition number' do
|
140
|
+
@id = "12345.387327.-sdf3"
|
141
|
+
@partition_number = "4"
|
142
|
+
Dynamoid::Adapter.get_original_id_and_partition("#{@id}.#{@partition_number}").should == [@id, @partition_number]
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'delete through the adapter for one ID' do
|
146
|
+
Dynamoid::Adapter.expects(:batch_delete_item).with('dynamoid_tests_TestTable' => (0...Dynamoid::Config.partition_size).collect{|n| "123.#{n}"}).returns(nil)
|
147
|
+
|
148
|
+
Dynamoid::Adapter.delete('dynamoid_tests_TestTable', '123')
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'deletes through the adapter for many IDs' do
|
152
|
+
Dynamoid::Adapter.expects(:batch_delete_item).with('dynamoid_tests_TestTable' => (0...Dynamoid::Config.partition_size).collect{|n| "1.#{n}"} + (0...Dynamoid::Config.partition_size).collect{|n| "2.#{n}"}).returns(nil)
|
153
|
+
|
154
|
+
Dynamoid::Adapter.delete('dynamoid_tests_TestTable', ['1', '2'])
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'deletes through the adapter for one ID and a range key' do
|
158
|
+
Dynamoid::Adapter.expects(:batch_delete_item).with('dynamoid_tests_TestTable' => (0...Dynamoid::Config.partition_size).collect{|n| ["123.#{n}", 2.0]}).returns(nil)
|
159
|
+
|
160
|
+
Dynamoid::Adapter.delete('dynamoid_tests_TestTable', '123', :range_key => 2.0)
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'deletes through the adapter for many IDs and a range key' do
|
164
|
+
Dynamoid::Adapter.expects(:batch_delete_item).with('dynamoid_tests_TestTable' => (0...Dynamoid::Config.partition_size).collect{|n| ["1.#{n}", 2.0]} + (0...Dynamoid::Config.partition_size).collect{|n| ["2.#{n}", 2.0]}).returns(nil)
|
165
|
+
|
166
|
+
Dynamoid::Adapter.delete('dynamoid_tests_TestTable', ['1', '2'], :range_key => [2.0,2.0])
|
167
|
+
end
|
115
168
|
end
|
116
169
|
|
117
170
|
end
|
@@ -136,5 +136,29 @@ describe "Dynamoid::Associations::Chain" do
|
|
136
136
|
@chain.send(:records_with_range).should == [@tweet3]
|
137
137
|
end
|
138
138
|
end
|
139
|
+
|
140
|
+
context 'destroy alls' do
|
141
|
+
before do
|
142
|
+
@tweet1 = Tweet.create(:tweet_id => "x", :group => "one")
|
143
|
+
@tweet2 = Tweet.create(:tweet_id => "x", :group => "two")
|
144
|
+
@tweet3 = Tweet.create(:tweet_id => "xx", :group => "two")
|
145
|
+
@chain = Dynamoid::Criteria::Chain.new(Tweet)
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'destroys tweet with a range simple range query' do
|
149
|
+
@chain.query = { :tweet_id => "x" }
|
150
|
+
@chain.all.size.should == 2
|
151
|
+
@chain.destroy_all
|
152
|
+
@chain.consistent.all.size.should == 0
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'deletes one specific tweet with range' do
|
156
|
+
@chain = Dynamoid::Criteria::Chain.new(Tweet)
|
157
|
+
@chain.query = { :tweet_id => "xx", :group => "two" }
|
158
|
+
@chain.all.size.should == 1
|
159
|
+
@chain.destroy_all
|
160
|
+
@chain.consistent.all.size.should == 0
|
161
|
+
end
|
162
|
+
end
|
139
163
|
|
140
164
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: adept_dynamoid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
@@ -240,6 +240,7 @@ files:
|
|
240
240
|
- README.markdown
|
241
241
|
- Rakefile
|
242
242
|
- VERSION
|
243
|
+
- adept_dynamoid.gemspec
|
243
244
|
- doc/.nojekyll
|
244
245
|
- doc/Dynamoid.html
|
245
246
|
- doc/Dynamoid/Adapter.html
|
@@ -362,6 +363,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
362
363
|
- - ! '>='
|
363
364
|
- !ruby/object:Gem::Version
|
364
365
|
version: '0'
|
366
|
+
segments:
|
367
|
+
- 0
|
368
|
+
hash: 108672444036973826
|
365
369
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
366
370
|
none: false
|
367
371
|
requirements:
|
@@ -375,4 +379,3 @@ signing_key:
|
|
375
379
|
specification_version: 3
|
376
380
|
summary: Dynamoid is an ORM for Amazon's DynamoDB
|
377
381
|
test_files: []
|
378
|
-
has_rdoc:
|