dynamoid 0.7.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -24
  3. data/README.markdown +89 -73
  4. data/Rakefile +10 -36
  5. data/dynamoid.gemspec +56 -191
  6. data/lib/dynamoid.rb +6 -4
  7. data/lib/dynamoid/adapter.rb +64 -150
  8. data/lib/dynamoid/adapter_plugin/aws_sdk_v2.rb +579 -0
  9. data/lib/dynamoid/components.rb +0 -1
  10. data/lib/dynamoid/config.rb +2 -5
  11. data/lib/dynamoid/criteria.rb +1 -1
  12. data/lib/dynamoid/criteria/chain.rb +27 -140
  13. data/lib/dynamoid/document.rb +2 -2
  14. data/lib/dynamoid/errors.rb +30 -9
  15. data/lib/dynamoid/fields.rb +15 -3
  16. data/lib/dynamoid/finders.rb +7 -6
  17. data/lib/dynamoid/identity_map.rb +1 -5
  18. data/lib/dynamoid/persistence.rb +108 -93
  19. metadata +56 -229
  20. data/.document +0 -5
  21. data/.rspec +0 -1
  22. data/.travis.yml +0 -7
  23. data/Gemfile.lock +0 -81
  24. data/Gemfile_activemodel4 +0 -24
  25. data/Gemfile_activemodel4.lock +0 -88
  26. data/VERSION +0 -1
  27. data/doc/.nojekyll +0 -0
  28. data/doc/Dynamoid.html +0 -328
  29. data/doc/Dynamoid/Adapter.html +0 -1872
  30. data/doc/Dynamoid/Adapter/AwsSdk.html +0 -2101
  31. data/doc/Dynamoid/Adapter/Local.html +0 -1574
  32. data/doc/Dynamoid/Associations.html +0 -138
  33. data/doc/Dynamoid/Associations/Association.html +0 -847
  34. data/doc/Dynamoid/Associations/BelongsTo.html +0 -161
  35. data/doc/Dynamoid/Associations/ClassMethods.html +0 -766
  36. data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +0 -167
  37. data/doc/Dynamoid/Associations/HasMany.html +0 -167
  38. data/doc/Dynamoid/Associations/HasOne.html +0 -161
  39. data/doc/Dynamoid/Associations/ManyAssociation.html +0 -1684
  40. data/doc/Dynamoid/Associations/SingleAssociation.html +0 -627
  41. data/doc/Dynamoid/Components.html +0 -242
  42. data/doc/Dynamoid/Config.html +0 -412
  43. data/doc/Dynamoid/Config/Options.html +0 -638
  44. data/doc/Dynamoid/Criteria.html +0 -138
  45. data/doc/Dynamoid/Criteria/Chain.html +0 -1471
  46. data/doc/Dynamoid/Criteria/ClassMethods.html +0 -105
  47. data/doc/Dynamoid/Dirty.html +0 -424
  48. data/doc/Dynamoid/Dirty/ClassMethods.html +0 -174
  49. data/doc/Dynamoid/Document.html +0 -1033
  50. data/doc/Dynamoid/Document/ClassMethods.html +0 -1116
  51. data/doc/Dynamoid/Errors.html +0 -125
  52. data/doc/Dynamoid/Errors/ConditionalCheckFailedException.html +0 -141
  53. data/doc/Dynamoid/Errors/DocumentNotValid.html +0 -221
  54. data/doc/Dynamoid/Errors/Error.html +0 -137
  55. data/doc/Dynamoid/Errors/InvalidField.html +0 -141
  56. data/doc/Dynamoid/Errors/InvalidQuery.html +0 -131
  57. data/doc/Dynamoid/Errors/MissingRangeKey.html +0 -141
  58. data/doc/Dynamoid/Fields.html +0 -686
  59. data/doc/Dynamoid/Fields/ClassMethods.html +0 -438
  60. data/doc/Dynamoid/Finders.html +0 -135
  61. data/doc/Dynamoid/Finders/ClassMethods.html +0 -943
  62. data/doc/Dynamoid/IdentityMap.html +0 -492
  63. data/doc/Dynamoid/IdentityMap/ClassMethods.html +0 -534
  64. data/doc/Dynamoid/Indexes.html +0 -321
  65. data/doc/Dynamoid/Indexes/ClassMethods.html +0 -369
  66. data/doc/Dynamoid/Indexes/Index.html +0 -1142
  67. data/doc/Dynamoid/Middleware.html +0 -115
  68. data/doc/Dynamoid/Middleware/IdentityMap.html +0 -264
  69. data/doc/Dynamoid/Persistence.html +0 -892
  70. data/doc/Dynamoid/Persistence/ClassMethods.html +0 -836
  71. data/doc/Dynamoid/Validations.html +0 -415
  72. data/doc/_index.html +0 -506
  73. data/doc/class_list.html +0 -53
  74. data/doc/css/common.css +0 -1
  75. data/doc/css/full_list.css +0 -57
  76. data/doc/css/style.css +0 -338
  77. data/doc/file.LICENSE.html +0 -73
  78. data/doc/file.README.html +0 -416
  79. data/doc/file_list.html +0 -58
  80. data/doc/frames.html +0 -28
  81. data/doc/index.html +0 -416
  82. data/doc/js/app.js +0 -214
  83. data/doc/js/full_list.js +0 -178
  84. data/doc/js/jquery.js +0 -4
  85. data/doc/method_list.html +0 -1144
  86. data/doc/top-level-namespace.html +0 -112
  87. data/lib/dynamoid/adapter/aws_sdk.rb +0 -287
  88. data/lib/dynamoid/indexes.rb +0 -69
  89. data/lib/dynamoid/indexes/index.rb +0 -103
  90. data/spec/app/models/address.rb +0 -13
  91. data/spec/app/models/camel_case.rb +0 -34
  92. data/spec/app/models/car.rb +0 -6
  93. data/spec/app/models/magazine.rb +0 -11
  94. data/spec/app/models/message.rb +0 -9
  95. data/spec/app/models/nuclear_submarine.rb +0 -5
  96. data/spec/app/models/sponsor.rb +0 -8
  97. data/spec/app/models/subscription.rb +0 -12
  98. data/spec/app/models/tweet.rb +0 -12
  99. data/spec/app/models/user.rb +0 -26
  100. data/spec/app/models/vehicle.rb +0 -7
  101. data/spec/dynamoid/adapter/aws_sdk_spec.rb +0 -376
  102. data/spec/dynamoid/adapter_spec.rb +0 -155
  103. data/spec/dynamoid/associations/association_spec.rb +0 -194
  104. data/spec/dynamoid/associations/belongs_to_spec.rb +0 -71
  105. data/spec/dynamoid/associations/has_and_belongs_to_many_spec.rb +0 -47
  106. data/spec/dynamoid/associations/has_many_spec.rb +0 -42
  107. data/spec/dynamoid/associations/has_one_spec.rb +0 -45
  108. data/spec/dynamoid/associations_spec.rb +0 -16
  109. data/spec/dynamoid/config_spec.rb +0 -27
  110. data/spec/dynamoid/criteria/chain_spec.rb +0 -210
  111. data/spec/dynamoid/criteria_spec.rb +0 -75
  112. data/spec/dynamoid/dirty_spec.rb +0 -57
  113. data/spec/dynamoid/document_spec.rb +0 -180
  114. data/spec/dynamoid/fields_spec.rb +0 -156
  115. data/spec/dynamoid/finders_spec.rb +0 -147
  116. data/spec/dynamoid/identity_map_spec.rb +0 -45
  117. data/spec/dynamoid/indexes/index_spec.rb +0 -104
  118. data/spec/dynamoid/indexes_spec.rb +0 -25
  119. data/spec/dynamoid/persistence_spec.rb +0 -301
  120. data/spec/dynamoid/validations_spec.rb +0 -36
  121. data/spec/dynamoid_spec.rb +0 -9
  122. data/spec/spec_helper.rb +0 -55
  123. 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
@@ -1,13 +0,0 @@
1
- class Address
2
- include Dynamoid::Document
3
-
4
- field :city
5
- field :options, :serialized
6
- field :deliverable, :boolean
7
-
8
- field :lock_version, :integer #Provides Optimistic Locking
9
-
10
- def zip_code=(zip_code)
11
- self.city = "Chicago"
12
- end
13
- end
@@ -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
@@ -1,6 +0,0 @@
1
- require_relative 'vehicle'
2
-
3
- class Car < Vehicle
4
-
5
- field :power_locks, :boolean
6
- end
@@ -1,11 +0,0 @@
1
- class Magazine
2
- include Dynamoid::Document
3
-
4
- field :title
5
-
6
- has_many :subscriptions
7
- has_many :camel_cases
8
- has_one :sponsor
9
-
10
- belongs_to :owner, :class_name => 'User', :inverse_of => :books
11
- end
@@ -1,9 +0,0 @@
1
- class Message
2
- include Dynamoid::Document
3
-
4
- table name: :messages, key: :message_id, read_capacity: 200, write_capacity: 200
5
-
6
- range :time, :datetime
7
-
8
- field :text
9
- end
@@ -1,5 +0,0 @@
1
- require_relative 'vehicle'
2
- class NuclearSubmarine < Vehicle
3
-
4
- field :torpedoes, :integer
5
- end
@@ -1,8 +0,0 @@
1
- class Sponsor
2
- include Dynamoid::Document
3
-
4
- belongs_to :magazine
5
- has_many :subscriptions
6
-
7
- belongs_to :camel_case
8
- end
@@ -1,12 +0,0 @@
1
- class Subscription
2
- include Dynamoid::Document
3
-
4
- field :length, :integer
5
-
6
- belongs_to :magazine
7
- has_and_belongs_to_many :users
8
-
9
- belongs_to :customer, :class_name => 'User', :inverse_of => :monthly
10
-
11
- has_and_belongs_to_many :camel_cases
12
- end
@@ -1,12 +0,0 @@
1
- class Tweet
2
- include Dynamoid::Document
3
-
4
- table name: :twitters, key: :tweet_id, read_capacity: 200, write_capacity: 200
5
-
6
- range :group, :string
7
-
8
- field :msg
9
- field :count, :integer
10
- field :tags, :set
11
- field :user_name
12
- end
@@ -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
@@ -1,7 +0,0 @@
1
- class Vehicle
2
- include Dynamoid::Document
3
-
4
- field :type
5
-
6
- field :description
7
- end
@@ -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