dynamoid 0.7.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +2 -24
- data/README.markdown +89 -73
- data/Rakefile +10 -36
- data/dynamoid.gemspec +56 -191
- data/lib/dynamoid.rb +6 -4
- data/lib/dynamoid/adapter.rb +64 -150
- data/lib/dynamoid/adapter_plugin/aws_sdk_v2.rb +579 -0
- data/lib/dynamoid/components.rb +0 -1
- data/lib/dynamoid/config.rb +2 -5
- data/lib/dynamoid/criteria.rb +1 -1
- data/lib/dynamoid/criteria/chain.rb +27 -140
- data/lib/dynamoid/document.rb +2 -2
- data/lib/dynamoid/errors.rb +30 -9
- data/lib/dynamoid/fields.rb +15 -3
- data/lib/dynamoid/finders.rb +7 -6
- data/lib/dynamoid/identity_map.rb +1 -5
- data/lib/dynamoid/persistence.rb +108 -93
- metadata +56 -229
- data/.document +0 -5
- data/.rspec +0 -1
- data/.travis.yml +0 -7
- data/Gemfile.lock +0 -81
- data/Gemfile_activemodel4 +0 -24
- data/Gemfile_activemodel4.lock +0 -88
- data/VERSION +0 -1
- data/doc/.nojekyll +0 -0
- data/doc/Dynamoid.html +0 -328
- data/doc/Dynamoid/Adapter.html +0 -1872
- data/doc/Dynamoid/Adapter/AwsSdk.html +0 -2101
- data/doc/Dynamoid/Adapter/Local.html +0 -1574
- data/doc/Dynamoid/Associations.html +0 -138
- data/doc/Dynamoid/Associations/Association.html +0 -847
- data/doc/Dynamoid/Associations/BelongsTo.html +0 -161
- data/doc/Dynamoid/Associations/ClassMethods.html +0 -766
- data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +0 -167
- data/doc/Dynamoid/Associations/HasMany.html +0 -167
- data/doc/Dynamoid/Associations/HasOne.html +0 -161
- data/doc/Dynamoid/Associations/ManyAssociation.html +0 -1684
- data/doc/Dynamoid/Associations/SingleAssociation.html +0 -627
- data/doc/Dynamoid/Components.html +0 -242
- data/doc/Dynamoid/Config.html +0 -412
- data/doc/Dynamoid/Config/Options.html +0 -638
- data/doc/Dynamoid/Criteria.html +0 -138
- data/doc/Dynamoid/Criteria/Chain.html +0 -1471
- data/doc/Dynamoid/Criteria/ClassMethods.html +0 -105
- data/doc/Dynamoid/Dirty.html +0 -424
- data/doc/Dynamoid/Dirty/ClassMethods.html +0 -174
- data/doc/Dynamoid/Document.html +0 -1033
- data/doc/Dynamoid/Document/ClassMethods.html +0 -1116
- data/doc/Dynamoid/Errors.html +0 -125
- data/doc/Dynamoid/Errors/ConditionalCheckFailedException.html +0 -141
- data/doc/Dynamoid/Errors/DocumentNotValid.html +0 -221
- data/doc/Dynamoid/Errors/Error.html +0 -137
- data/doc/Dynamoid/Errors/InvalidField.html +0 -141
- data/doc/Dynamoid/Errors/InvalidQuery.html +0 -131
- data/doc/Dynamoid/Errors/MissingRangeKey.html +0 -141
- data/doc/Dynamoid/Fields.html +0 -686
- data/doc/Dynamoid/Fields/ClassMethods.html +0 -438
- data/doc/Dynamoid/Finders.html +0 -135
- data/doc/Dynamoid/Finders/ClassMethods.html +0 -943
- data/doc/Dynamoid/IdentityMap.html +0 -492
- data/doc/Dynamoid/IdentityMap/ClassMethods.html +0 -534
- data/doc/Dynamoid/Indexes.html +0 -321
- data/doc/Dynamoid/Indexes/ClassMethods.html +0 -369
- data/doc/Dynamoid/Indexes/Index.html +0 -1142
- data/doc/Dynamoid/Middleware.html +0 -115
- data/doc/Dynamoid/Middleware/IdentityMap.html +0 -264
- data/doc/Dynamoid/Persistence.html +0 -892
- data/doc/Dynamoid/Persistence/ClassMethods.html +0 -836
- data/doc/Dynamoid/Validations.html +0 -415
- data/doc/_index.html +0 -506
- data/doc/class_list.html +0 -53
- data/doc/css/common.css +0 -1
- data/doc/css/full_list.css +0 -57
- data/doc/css/style.css +0 -338
- data/doc/file.LICENSE.html +0 -73
- data/doc/file.README.html +0 -416
- data/doc/file_list.html +0 -58
- data/doc/frames.html +0 -28
- data/doc/index.html +0 -416
- data/doc/js/app.js +0 -214
- data/doc/js/full_list.js +0 -178
- data/doc/js/jquery.js +0 -4
- data/doc/method_list.html +0 -1144
- data/doc/top-level-namespace.html +0 -112
- data/lib/dynamoid/adapter/aws_sdk.rb +0 -287
- data/lib/dynamoid/indexes.rb +0 -69
- data/lib/dynamoid/indexes/index.rb +0 -103
- data/spec/app/models/address.rb +0 -13
- data/spec/app/models/camel_case.rb +0 -34
- data/spec/app/models/car.rb +0 -6
- data/spec/app/models/magazine.rb +0 -11
- data/spec/app/models/message.rb +0 -9
- data/spec/app/models/nuclear_submarine.rb +0 -5
- data/spec/app/models/sponsor.rb +0 -8
- data/spec/app/models/subscription.rb +0 -12
- data/spec/app/models/tweet.rb +0 -12
- data/spec/app/models/user.rb +0 -26
- data/spec/app/models/vehicle.rb +0 -7
- data/spec/dynamoid/adapter/aws_sdk_spec.rb +0 -376
- data/spec/dynamoid/adapter_spec.rb +0 -155
- data/spec/dynamoid/associations/association_spec.rb +0 -194
- data/spec/dynamoid/associations/belongs_to_spec.rb +0 -71
- data/spec/dynamoid/associations/has_and_belongs_to_many_spec.rb +0 -47
- data/spec/dynamoid/associations/has_many_spec.rb +0 -42
- data/spec/dynamoid/associations/has_one_spec.rb +0 -45
- data/spec/dynamoid/associations_spec.rb +0 -16
- data/spec/dynamoid/config_spec.rb +0 -27
- data/spec/dynamoid/criteria/chain_spec.rb +0 -210
- data/spec/dynamoid/criteria_spec.rb +0 -75
- data/spec/dynamoid/dirty_spec.rb +0 -57
- data/spec/dynamoid/document_spec.rb +0 -180
- data/spec/dynamoid/fields_spec.rb +0 -156
- data/spec/dynamoid/finders_spec.rb +0 -147
- data/spec/dynamoid/identity_map_spec.rb +0 -45
- data/spec/dynamoid/indexes/index_spec.rb +0 -104
- data/spec/dynamoid/indexes_spec.rb +0 -25
- data/spec/dynamoid/persistence_spec.rb +0 -301
- data/spec/dynamoid/validations_spec.rb +0 -36
- data/spec/dynamoid_spec.rb +0 -9
- data/spec/spec_helper.rb +0 -55
- data/spec/support/with_partitioning.rb +0 -15
@@ -1,103 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
module Dynamoid #:nodoc:
|
3
|
-
module Indexes
|
4
|
-
|
5
|
-
# The class contains all the information an index contains, including its keys and which attributes it covers.
|
6
|
-
class Index
|
7
|
-
attr_accessor :source, :name, :hash_keys, :range_keys
|
8
|
-
alias_method :range_key?, :range_keys
|
9
|
-
|
10
|
-
# Create a new index. Pass either :range => true or :range => :column_name to create a ranged index on that column.
|
11
|
-
#
|
12
|
-
# @param [Class] source the source class for the index
|
13
|
-
# @param [Symbol] name the name of the index
|
14
|
-
#
|
15
|
-
# @since 0.2.0
|
16
|
-
def initialize(source, name, options = {})
|
17
|
-
@source = source
|
18
|
-
|
19
|
-
if options.delete(:range)
|
20
|
-
@range_keys = sort(name)
|
21
|
-
elsif options[:range_key]
|
22
|
-
@range_keys = sort(options[:range_key])
|
23
|
-
end
|
24
|
-
@hash_keys = sort(name)
|
25
|
-
@name = sort([hash_keys, range_keys])
|
26
|
-
|
27
|
-
raise Dynamoid::Errors::InvalidField, 'A key specified for an index is not a field' unless keys.all?{|n| source.attributes.include?(n)}
|
28
|
-
end
|
29
|
-
|
30
|
-
# Sort objects into alphabetical strings, used for composing index names correctly (since we always assume they're alphabetical).
|
31
|
-
#
|
32
|
-
# @example find all users by first and last name
|
33
|
-
# sort([:gamma, :alpha, :beta, :omega]) # => [:alpha, :beta, :gamma, :omega]
|
34
|
-
#
|
35
|
-
# @since 0.2.0
|
36
|
-
def sort(objs)
|
37
|
-
Array(objs).flatten.compact.uniq.collect(&:to_s).sort.collect(&:to_sym)
|
38
|
-
end
|
39
|
-
|
40
|
-
# Return the array of keys this index uses for its table.
|
41
|
-
#
|
42
|
-
# @since 0.2.0
|
43
|
-
def keys
|
44
|
-
[Array(hash_keys) + Array(range_keys)].flatten.uniq
|
45
|
-
end
|
46
|
-
|
47
|
-
# Return the table name for this index.
|
48
|
-
#
|
49
|
-
# @since 0.2.0
|
50
|
-
def table_name
|
51
|
-
"#{Dynamoid::Config.namespace}_index_" + source.table_name.sub("#{Dynamoid::Config.namespace}_", '').singularize + "_#{name.collect(&:to_s).collect(&:pluralize).join('_and_')}"
|
52
|
-
end
|
53
|
-
|
54
|
-
# Given either an object or a list of attributes, generate a hash key and a range key for the index. Optionally pass in
|
55
|
-
# true to changed_attributes for a list of all the object's dirty attributes in convenient index form (for deleting stale
|
56
|
-
# information from the indexes).
|
57
|
-
#
|
58
|
-
# @param [Object] attrs either an object that responds to :attributes, or a hash of attributes
|
59
|
-
#
|
60
|
-
# @return [Hash] a hash with the keys :hash_value and :range_value
|
61
|
-
#
|
62
|
-
# @since 0.2.0
|
63
|
-
def values(attrs, changed_attributes = false)
|
64
|
-
if changed_attributes
|
65
|
-
hash = {}
|
66
|
-
attrs.changes.each {|k, v| hash[k.to_sym] = (v.first || v.last)}
|
67
|
-
attrs = hash
|
68
|
-
end
|
69
|
-
attrs = attrs.send(:attributes) if attrs.respond_to?(:attributes)
|
70
|
-
{}.tap do |hash|
|
71
|
-
hash[:hash_value] = hash_keys.collect{|key| attrs[key]}.join('.')
|
72
|
-
hash[:range_value] = range_keys.inject(0.0) {|sum, key| sum + attrs[key].to_f} if self.range_key?
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# Save an object to this index, merging it with existing ids if there's already something present at this index location.
|
77
|
-
# First, though, delete this object from its old indexes (so the object isn't listed in an erroneous index).
|
78
|
-
#
|
79
|
-
# @since 0.2.0
|
80
|
-
def save(obj)
|
81
|
-
self.delete(obj, true)
|
82
|
-
values = values(obj)
|
83
|
-
return true if values[:hash_value].blank? || (!values[:range_value].nil? && values[:range_value].blank?)
|
84
|
-
existing = Dynamoid::Adapter.read(self.table_name, values[:hash_value], { :range_key => values[:range_value] })
|
85
|
-
ids = ((existing and existing[:ids]) or Set.new)
|
86
|
-
Dynamoid::Adapter.write(self.table_name, {:id => values[:hash_value], :ids => ids.merge([obj.id]), :range => values[:range_value]})
|
87
|
-
end
|
88
|
-
|
89
|
-
# Delete an object from this index, preserving existing ids if there are any, and failing gracefully if for some reason the
|
90
|
-
# index doesn't already have this object in it.
|
91
|
-
#
|
92
|
-
# @since 0.2.0
|
93
|
-
def delete(obj, changed_attributes = false)
|
94
|
-
values = values(obj, changed_attributes)
|
95
|
-
return true if values[:hash_value].blank? || (!values[:range_value].nil? && values[:range_value].blank?)
|
96
|
-
existing = Dynamoid::Adapter.read(self.table_name, values[:hash_value], { :range_key => values[:range_value]})
|
97
|
-
return true unless existing && existing[:ids] && existing[:ids].include?(obj.id)
|
98
|
-
Dynamoid::Adapter.write(self.table_name, {:id => values[:hash_value], :ids => (existing[:ids] - Set[obj.id]), :range => values[:range_value]})
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
data/spec/app/models/address.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
class CamelCase
|
2
|
-
include Dynamoid::Document
|
3
|
-
|
4
|
-
field :color
|
5
|
-
|
6
|
-
belongs_to :magazine
|
7
|
-
has_many :users
|
8
|
-
has_one :sponsor
|
9
|
-
has_and_belongs_to_many :subscriptions
|
10
|
-
|
11
|
-
before_create :doing_before_create
|
12
|
-
after_create :doing_after_create
|
13
|
-
before_update :doing_before_update
|
14
|
-
after_update :doing_after_update
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def doing_before_create
|
19
|
-
true
|
20
|
-
end
|
21
|
-
|
22
|
-
def doing_after_create
|
23
|
-
true
|
24
|
-
end
|
25
|
-
|
26
|
-
def doing_before_update
|
27
|
-
true
|
28
|
-
end
|
29
|
-
|
30
|
-
def doing_after_update
|
31
|
-
true
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
data/spec/app/models/car.rb
DELETED
data/spec/app/models/magazine.rb
DELETED
data/spec/app/models/message.rb
DELETED
data/spec/app/models/sponsor.rb
DELETED
data/spec/app/models/tweet.rb
DELETED
data/spec/app/models/user.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
class User
|
2
|
-
include Dynamoid::Document
|
3
|
-
|
4
|
-
field :name
|
5
|
-
field :email
|
6
|
-
field :password
|
7
|
-
field :last_logged_in_at, :datetime
|
8
|
-
|
9
|
-
index :name
|
10
|
-
index :email
|
11
|
-
index [:name, :email]
|
12
|
-
index :name, :range_key => :created_at
|
13
|
-
index :name, :range_key => :last_logged_in_at
|
14
|
-
index :created_at, :range => true
|
15
|
-
|
16
|
-
has_and_belongs_to_many :subscriptions
|
17
|
-
|
18
|
-
has_many :books, :class_name => 'Magazine', :inverse_of => :owner
|
19
|
-
has_one :monthly, :class_name => 'Subscription', :inverse_of => :customer
|
20
|
-
|
21
|
-
has_and_belongs_to_many :followers, :class_name => 'User', :inverse_of => :following
|
22
|
-
has_and_belongs_to_many :following, :class_name => 'User', :inverse_of => :followers
|
23
|
-
|
24
|
-
belongs_to :camel_case
|
25
|
-
|
26
|
-
end
|
data/spec/app/models/vehicle.rb
DELETED
@@ -1,376 +0,0 @@
|
|
1
|
-
require 'dynamoid/adapter/aws_sdk'
|
2
|
-
require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
|
3
|
-
|
4
|
-
describe Dynamoid::Adapter::AwsSdk do
|
5
|
-
before(:each) do
|
6
|
-
pending "You must have an active DynamoDB connection" unless ENV['ACCESS_KEY'] && ENV['SECRET_KEY']
|
7
|
-
end
|
8
|
-
|
9
|
-
#
|
10
|
-
# These let() definitions create tables "dynamoid_tests_TestTable<N>" and return the
|
11
|
-
# name of the table. An after(:each) handler drops any tables created this way after each test
|
12
|
-
#
|
13
|
-
# Name => Constructor args
|
14
|
-
{
|
15
|
-
1 => [:id],
|
16
|
-
2 => [:id],
|
17
|
-
3 => [:id, {:range_key => {:range => :number}}],
|
18
|
-
4 => [:id, {:range_key => {:range => :number}}]
|
19
|
-
}.each do |n, args|
|
20
|
-
name = "dynamoid_tests_TestTable#{n}"
|
21
|
-
let(:"test_table#{n}") do
|
22
|
-
Dynamoid::Adapter.create_table(name, *args)
|
23
|
-
@created_tables << name
|
24
|
-
name
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
before(:each) { @created_tables = [] }
|
29
|
-
after(:each) do
|
30
|
-
@created_tables.each do |t|
|
31
|
-
Dynamoid::Adapter.delete_table(t)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
#
|
36
|
-
# Returns a random key parition if partitioning is on, or an empty string if
|
37
|
-
# it is off, useful for shared examples where partitioning may or may not be on
|
38
|
-
#
|
39
|
-
def key_partition
|
40
|
-
Dynamoid::Config.partitioning? ? ".#{Random.rand(Dynamoid::Config.partition_size)}" : ''
|
41
|
-
end
|
42
|
-
|
43
|
-
#
|
44
|
-
# Tests adapter against ranged tables
|
45
|
-
#
|
46
|
-
shared_examples 'range queries' do
|
47
|
-
before do
|
48
|
-
Dynamoid::Adapter.put_item(test_table3, {:id => "1#{key_partition}", :range => 1.0})
|
49
|
-
Dynamoid::Adapter.put_item(test_table3, {:id => "1#{key_partition}", :range => 3.0})
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'performs query on a table with a range and selects items in a range' do
|
53
|
-
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_value => 0.0..3.0).to_a.should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'performs query on a table with a range and selects items in a range with :select option' do
|
57
|
-
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_value => 0.0..3.0, :select => :all).to_a.should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'performs query on a table with a range and selects items greater than' do
|
61
|
-
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_greater_than => 1.0).to_a.should =~ [{:id => '1', :range => BigDecimal.new(3)}]
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'performs query on a table with a range and selects items less than' do
|
65
|
-
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_less_than => 2.0).to_a.should =~ [{:id => '1', :range => BigDecimal.new(1)}]
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'performs query on a table with a range and selects items gte' do
|
69
|
-
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_gte => 1.0).to_a.should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'performs query on a table with a range and selects items lte' do
|
73
|
-
Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_lte => 3.0).to_a.should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
#
|
78
|
-
# Tests scan_index_forwards flag behavior on range queries
|
79
|
-
#
|
80
|
-
shared_examples 'correct ordering' do
|
81
|
-
before(:each) do
|
82
|
-
pending "Order is not preserved on paritioned tables" if(Dynamoid::Config.partitioning?)
|
83
|
-
Dynamoid::Adapter.put_item(test_table4, {:id => "1#{key_partition}", :order => 1, :range => 1.0})
|
84
|
-
Dynamoid::Adapter.put_item(test_table4, {:id => "1#{key_partition}", :order => 2, :range => 2.0})
|
85
|
-
Dynamoid::Adapter.put_item(test_table4, {:id => "1#{key_partition}", :order => 3, :range => 3.0})
|
86
|
-
Dynamoid::Adapter.put_item(test_table4, {:id => "1#{key_partition}", :order => 4, :range => 4.0})
|
87
|
-
Dynamoid::Adapter.put_item(test_table4, {:id => "1#{key_partition}", :order => 5, :range => 5.0})
|
88
|
-
Dynamoid::Adapter.put_item(test_table4, {:id => "1#{key_partition}", :order => 6, :range => 6.0})
|
89
|
-
end
|
90
|
-
|
91
|
-
it 'performs query on a table with a range and selects items less than that is in the correct order, scan_index_forward true' do
|
92
|
-
query = Dynamoid::Adapter.query(test_table4, :hash_value => '1', :range_greater_than => 0, :scan_index_forward => true).to_a
|
93
|
-
query[0].should == {:id => '1', :order => 1, :range => BigDecimal.new(1)}
|
94
|
-
query[1].should == {:id => '1', :order => 2, :range => BigDecimal.new(2)}
|
95
|
-
query[2].should == {:id => '1', :order => 3, :range => BigDecimal.new(3)}
|
96
|
-
query[3].should == {:id => '1', :order => 4, :range => BigDecimal.new(4)}
|
97
|
-
query[4].should == {:id => '1', :order => 5, :range => BigDecimal.new(5)}
|
98
|
-
query[5].should == {:id => '1', :order => 6, :range => BigDecimal.new(6)}
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'performs query on a table with a range and selects items less than that is in the correct order, scan_index_forward false' do
|
102
|
-
query = Dynamoid::Adapter.query(test_table4, :hash_value => '1', :range_greater_than => 0, :scan_index_forward => false).to_a
|
103
|
-
query[5].should == {:id => '1', :order => 1, :range => BigDecimal.new(1)}
|
104
|
-
query[4].should == {:id => '1', :order => 2, :range => BigDecimal.new(2)}
|
105
|
-
query[3].should == {:id => '1', :order => 3, :range => BigDecimal.new(3)}
|
106
|
-
query[2].should == {:id => '1', :order => 4, :range => BigDecimal.new(4)}
|
107
|
-
query[1].should == {:id => '1', :order => 5, :range => BigDecimal.new(5)}
|
108
|
-
query[0].should == {:id => '1', :order => 6, :range => BigDecimal.new(6)}
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
|
113
|
-
context 'without a preexisting table' do
|
114
|
-
# CreateTable and DeleteTable
|
115
|
-
it 'performs CreateTable and DeleteTable' do
|
116
|
-
table = Dynamoid::Adapter.create_table('CreateTable', :id, :range_key => { :created_at => :number })
|
117
|
-
|
118
|
-
Dynamoid::Adapter.connection.tables.collect{|t| t.name}.should include 'CreateTable'
|
119
|
-
|
120
|
-
Dynamoid::Adapter.delete_table('CreateTable')
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
|
125
|
-
context 'with a preexisting table without paritioning' do
|
126
|
-
# GetItem, PutItem and DeleteItem
|
127
|
-
it "performs GetItem for an item that does not exist" do
|
128
|
-
Dynamoid::Adapter.get_item(test_table1, '1').should be_nil
|
129
|
-
end
|
130
|
-
|
131
|
-
it "performs GetItem for an item that does exist" do
|
132
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
133
|
-
|
134
|
-
Dynamoid::Adapter.get_item(test_table1, '1').should == {:name => 'Josh', :id => '1'}
|
135
|
-
|
136
|
-
Dynamoid::Adapter.delete_item(test_table1, '1')
|
137
|
-
|
138
|
-
Dynamoid::Adapter.get_item(test_table1, '1').should be_nil
|
139
|
-
end
|
140
|
-
|
141
|
-
it 'performs GetItem for an item that does exist with a range key' do
|
142
|
-
Dynamoid::Adapter.put_item(test_table3, {:id => '1', :name => 'Josh', :range => 2.0})
|
143
|
-
|
144
|
-
Dynamoid::Adapter.get_item(test_table3, '1', :range_key => 2.0).should == {:name => 'Josh', :id => '1', :range => 2.0}
|
145
|
-
|
146
|
-
Dynamoid::Adapter.delete_item(test_table3, '1', :range_key => 2.0)
|
147
|
-
|
148
|
-
Dynamoid::Adapter.get_item(test_table3, '1', :range_key => 2.0).should be_nil
|
149
|
-
end
|
150
|
-
|
151
|
-
it 'performs DeleteItem for an item that does not exist' do
|
152
|
-
Dynamoid::Adapter.delete_item(test_table1, '1')
|
153
|
-
|
154
|
-
Dynamoid::Adapter.get_item(test_table1, '1').should be_nil
|
155
|
-
end
|
156
|
-
|
157
|
-
it 'performs PutItem for an item that does not exist' do
|
158
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
159
|
-
|
160
|
-
Dynamoid::Adapter.get_item(test_table1, '1').should == {:id => '1', :name => 'Josh'}
|
161
|
-
end
|
162
|
-
|
163
|
-
# BatchGetItem
|
164
|
-
it 'passes options to underlying BatchGet call' do
|
165
|
-
AWS::DynamoDB::BatchGet.any_instance.expects(:table).with(test_table1, :all, ['1', '2'], :consistent_read => true)
|
166
|
-
described_class.batch_get_item({test_table1 => ['1', '2']}, :consistent_read => true)
|
167
|
-
end
|
168
|
-
|
169
|
-
it "performs BatchGetItem with singular keys" do
|
170
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
171
|
-
Dynamoid::Adapter.put_item(test_table2, {:id => '1', :name => 'Justin'})
|
172
|
-
|
173
|
-
results = Dynamoid::Adapter.batch_get_item(test_table1 => '1', test_table2 => '1')
|
174
|
-
results.size.should == 2
|
175
|
-
results[test_table1].should include({:name => 'Josh', :id => '1'})
|
176
|
-
results[test_table2].should include({:name => 'Justin', :id => '1'})
|
177
|
-
end
|
178
|
-
|
179
|
-
it "performs BatchGetItem with multiple keys" do
|
180
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
181
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '2', :name => 'Justin'})
|
182
|
-
|
183
|
-
results = Dynamoid::Adapter.batch_get_item(test_table1 => ['1', '2'])
|
184
|
-
results.size.should == 1
|
185
|
-
results[test_table1].should include({:name => 'Josh', :id => '1'})
|
186
|
-
results[test_table1].should include({:name => 'Justin', :id => '2'})
|
187
|
-
end
|
188
|
-
|
189
|
-
it 'performs BatchGetItem with one ranged key' do
|
190
|
-
Dynamoid::Adapter.put_item(test_table3, {:id => '1', :name => 'Josh', :range => 1.0})
|
191
|
-
Dynamoid::Adapter.put_item(test_table3, {:id => '2', :name => 'Justin', :range => 2.0})
|
192
|
-
|
193
|
-
results = Dynamoid::Adapter.batch_get_item(test_table3 => [['1', 1.0]])
|
194
|
-
results.size.should == 1
|
195
|
-
results[test_table3].should include({:name => 'Josh', :id => '1', :range => 1.0})
|
196
|
-
end
|
197
|
-
|
198
|
-
it 'performs BatchGetItem with multiple ranged keys' do
|
199
|
-
Dynamoid::Adapter.put_item(test_table3, {:id => '1', :name => 'Josh', :range => 1.0})
|
200
|
-
Dynamoid::Adapter.put_item(test_table3, {:id => '2', :name => 'Justin', :range => 2.0})
|
201
|
-
|
202
|
-
results = Dynamoid::Adapter.batch_get_item(test_table3 => [['1', 1.0],['2', 2.0]])
|
203
|
-
results.size.should == 1
|
204
|
-
results[test_table3].should include({:name => 'Josh', :id => '1', :range => 1.0})
|
205
|
-
results[test_table3].should include({:name => 'Justin', :id => '2', :range => 2.0})
|
206
|
-
end
|
207
|
-
|
208
|
-
# BatchDeleteItem
|
209
|
-
it "performs BatchDeleteItem with singular keys" do
|
210
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
211
|
-
Dynamoid::Adapter.put_item(test_table2, {:id => '1', :name => 'Justin'})
|
212
|
-
|
213
|
-
Dynamoid::Adapter.batch_delete_item(test_table1 => ['1'], test_table2 => ['1'])
|
214
|
-
|
215
|
-
results = Dynamoid::Adapter.batch_get_item(test_table1 => '1', test_table2 => '1')
|
216
|
-
results.size.should == 0
|
217
|
-
|
218
|
-
results[test_table1].should_not include({:name => 'Josh', :id => '1'})
|
219
|
-
results[test_table2].should_not include({:name => 'Justin', :id => '1'})
|
220
|
-
end
|
221
|
-
|
222
|
-
it "performs BatchDeleteItem with multiple keys" do
|
223
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
224
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '2', :name => 'Justin'})
|
225
|
-
|
226
|
-
Dynamoid::Adapter.batch_delete_item(test_table1 => ['1', '2'])
|
227
|
-
|
228
|
-
results = Dynamoid::Adapter.batch_get_item(test_table1 => ['1', '2'])
|
229
|
-
results.size.should == 0
|
230
|
-
|
231
|
-
results[test_table1].should_not include({:name => 'Josh', :id => '1'})
|
232
|
-
results[test_table1].should_not include({:name => 'Justin', :id => '2'})
|
233
|
-
end
|
234
|
-
|
235
|
-
it 'performs BatchDeleteItem with one ranged key' do
|
236
|
-
Dynamoid::Adapter.put_item(test_table3, {:id => '1', :name => 'Josh', :range => 1.0})
|
237
|
-
Dynamoid::Adapter.put_item(test_table3, {:id => '2', :name => 'Justin', :range => 2.0})
|
238
|
-
|
239
|
-
Dynamoid::Adapter.batch_delete_item(test_table3 => [['1', 1.0]])
|
240
|
-
results = Dynamoid::Adapter.batch_get_item(test_table3 => [['1', 1.0]])
|
241
|
-
results.size.should == 0
|
242
|
-
|
243
|
-
results[test_table3].should_not include({:name => 'Josh', :id => '1', :range => 1.0})
|
244
|
-
end
|
245
|
-
|
246
|
-
it 'performs BatchDeleteItem with multiple ranged keys' do
|
247
|
-
Dynamoid::Adapter.put_item(test_table3, {:id => '1', :name => 'Josh', :range => 1.0})
|
248
|
-
Dynamoid::Adapter.put_item(test_table3, {:id => '2', :name => 'Justin', :range => 2.0})
|
249
|
-
|
250
|
-
Dynamoid::Adapter.batch_delete_item(test_table3 => [['1', 1.0],['2', 2.0]])
|
251
|
-
results = Dynamoid::Adapter.batch_get_item(test_table3 => [['1', 1.0],['2', 2.0]])
|
252
|
-
results.size.should == 0
|
253
|
-
|
254
|
-
results[test_table3].should_not include({:name => 'Josh', :id => '1', :range => 1.0})
|
255
|
-
results[test_table3].should_not include({:name => 'Justin', :id => '2', :range => 2.0})
|
256
|
-
end
|
257
|
-
|
258
|
-
# ListTables
|
259
|
-
it 'performs ListTables' do
|
260
|
-
#Force creation of the tables
|
261
|
-
test_table1; test_table2; test_table3; test_table4
|
262
|
-
|
263
|
-
Dynamoid::Adapter.list_tables.should include test_table1
|
264
|
-
Dynamoid::Adapter.list_tables.should include test_table2
|
265
|
-
end
|
266
|
-
|
267
|
-
# Query
|
268
|
-
it 'performs query on a table and returns items' do
|
269
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
270
|
-
|
271
|
-
Dynamoid::Adapter.query(test_table1, :hash_value => '1').first.should == { :id=> '1', :name=>"Josh" }
|
272
|
-
end
|
273
|
-
|
274
|
-
it 'performs query on a table and returns items if there are multiple items' do
|
275
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
276
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '2', :name => 'Justin'})
|
277
|
-
|
278
|
-
Dynamoid::Adapter.query(test_table1, :hash_value => '1').first.should == { :id=> '1', :name=>"Josh" }
|
279
|
-
end
|
280
|
-
|
281
|
-
it_behaves_like 'range queries'
|
282
|
-
|
283
|
-
# Scan
|
284
|
-
it 'performs scan on a table and returns items' do
|
285
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
286
|
-
|
287
|
-
Dynamoid::Adapter.scan(test_table1, :name => 'Josh').to_a.should == [{ :id=> '1', :name=>"Josh" }]
|
288
|
-
end
|
289
|
-
|
290
|
-
it 'performs scan on a table and returns items if there are multiple items but only one match' do
|
291
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
292
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '2', :name => 'Justin'})
|
293
|
-
|
294
|
-
Dynamoid::Adapter.scan(test_table1, :name => 'Josh').to_a.should == [{ :id=> '1', :name=>"Josh" }]
|
295
|
-
end
|
296
|
-
|
297
|
-
it 'performs scan on a table and returns multiple items if there are multiple matches' do
|
298
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
299
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '2', :name => 'Josh'})
|
300
|
-
|
301
|
-
Dynamoid::Adapter.scan(test_table1, :name => 'Josh').should include({:name=>"Josh", :id=>"2"}, {:name=>"Josh", :id=>"1"})
|
302
|
-
end
|
303
|
-
|
304
|
-
it 'performs scan on a table and returns all items if no criteria are specified' do
|
305
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
|
306
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '2', :name => 'Josh'})
|
307
|
-
|
308
|
-
Dynamoid::Adapter.scan(test_table1, {}).should include({:name=>"Josh", :id=>"2"}, {:name=>"Josh", :id=>"1"})
|
309
|
-
end
|
310
|
-
|
311
|
-
it_behaves_like 'correct ordering'
|
312
|
-
end
|
313
|
-
|
314
|
-
context 'with a preexisting table with paritioning' do
|
315
|
-
before(:all) do
|
316
|
-
@previous_value = Dynamoid::Config.partitioning
|
317
|
-
Dynamoid::Config.partitioning = true
|
318
|
-
end
|
319
|
-
|
320
|
-
after(:all) do
|
321
|
-
Dynamoid::Config.partitioning = @previous_value
|
322
|
-
end
|
323
|
-
|
324
|
-
# Query
|
325
|
-
it 'performs query on a table and returns items' do
|
326
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1.1', :name => 'Josh'})
|
327
|
-
|
328
|
-
Dynamoid::Adapter.query(test_table1, :hash_value => '1').first.should == { :id=> '1', :name=>"Josh" }
|
329
|
-
end
|
330
|
-
|
331
|
-
it 'performs query on a table and returns items if there are multiple items' do
|
332
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1.1', :name => 'Josh'})
|
333
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '2.1', :name => 'Justin'})
|
334
|
-
|
335
|
-
Dynamoid::Adapter.query(test_table1, :hash_value => '1').first.should == { :id=> '1', :name=>"Josh" }
|
336
|
-
end
|
337
|
-
|
338
|
-
it_behaves_like 'range queries'
|
339
|
-
|
340
|
-
# Scan
|
341
|
-
it 'performs scan on a table and returns items' do
|
342
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1.1', :name => 'Josh'})
|
343
|
-
|
344
|
-
Dynamoid::Adapter.scan(test_table1, :name => 'Josh').should == [{ :id=> '1', :name=>"Josh" }]
|
345
|
-
end
|
346
|
-
|
347
|
-
it 'performs scan on a table and returns items if there are multiple items but only one match' do
|
348
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1.1', :name => 'Josh'})
|
349
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '2.1', :name => 'Justin'})
|
350
|
-
|
351
|
-
Dynamoid::Adapter.scan(test_table1, :name => 'Josh').should == [{ :id=> '1', :name=>"Josh" }]
|
352
|
-
end
|
353
|
-
|
354
|
-
it 'performs scan on a table and returns multiple items if there are multiple matches' do
|
355
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1.1', :name => 'Josh'})
|
356
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '2.1', :name => 'Josh'})
|
357
|
-
|
358
|
-
Dynamoid::Adapter.scan(test_table1, :name => 'Josh').should include({:name=>"Josh", :id=>"2"}, {:name=>"Josh", :id=>"1"})
|
359
|
-
end
|
360
|
-
|
361
|
-
it 'performs scan on a table and returns all items if no criteria are specified' do
|
362
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '1.1', :name => 'Josh'})
|
363
|
-
Dynamoid::Adapter.put_item(test_table1, {:id => '2.1', :name => 'Josh'})
|
364
|
-
|
365
|
-
Dynamoid::Adapter.scan(test_table1, {}).should include({:name=>"Josh", :id=>"2"}, {:name=>"Josh", :id=>"1"})
|
366
|
-
end
|
367
|
-
|
368
|
-
it_behaves_like 'correct ordering'
|
369
|
-
end
|
370
|
-
|
371
|
-
# DescribeTable
|
372
|
-
|
373
|
-
# UpdateItem
|
374
|
-
|
375
|
-
# UpdateTable
|
376
|
-
end
|