dynamoid 0.7.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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