dynamoid 0.6.1 → 0.7.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 (92) hide show
  1. data/.travis.yml +4 -0
  2. data/Gemfile +3 -2
  3. data/Gemfile.lock +40 -45
  4. data/README.markdown +55 -25
  5. data/Rakefile +31 -0
  6. data/VERSION +1 -1
  7. data/doc/Dynamoid.html +58 -42
  8. data/doc/Dynamoid/Adapter.html +666 -179
  9. data/doc/Dynamoid/Adapter/AwsSdk.html +752 -236
  10. data/doc/Dynamoid/Associations.html +28 -21
  11. data/doc/Dynamoid/Associations/Association.html +102 -49
  12. data/doc/Dynamoid/Associations/BelongsTo.html +28 -25
  13. data/doc/Dynamoid/Associations/ClassMethods.html +95 -52
  14. data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +28 -25
  15. data/doc/Dynamoid/Associations/HasMany.html +28 -25
  16. data/doc/Dynamoid/Associations/HasOne.html +28 -25
  17. data/doc/Dynamoid/Associations/ManyAssociation.html +138 -94
  18. data/doc/Dynamoid/Associations/SingleAssociation.html +67 -38
  19. data/doc/Dynamoid/Components.html +60 -22
  20. data/doc/Dynamoid/Config.html +61 -44
  21. data/doc/Dynamoid/Config/Options.html +90 -61
  22. data/doc/Dynamoid/Criteria.html +28 -21
  23. data/doc/Dynamoid/Criteria/Chain.html +508 -100
  24. data/doc/Dynamoid/Criteria/ClassMethods.html +26 -19
  25. data/doc/Dynamoid/Dirty.html +424 -0
  26. data/doc/Dynamoid/Dirty/ClassMethods.html +174 -0
  27. data/doc/Dynamoid/Document.html +451 -84
  28. data/doc/Dynamoid/Document/ClassMethods.html +281 -102
  29. data/doc/Dynamoid/Errors.html +29 -22
  30. data/doc/Dynamoid/Errors/ConditionalCheckFailedException.html +141 -0
  31. data/doc/Dynamoid/Errors/DocumentNotValid.html +36 -25
  32. data/doc/Dynamoid/Errors/Error.html +27 -20
  33. data/doc/Dynamoid/Errors/InvalidField.html +27 -19
  34. data/doc/Dynamoid/Errors/InvalidQuery.html +131 -0
  35. data/doc/Dynamoid/Errors/MissingRangeKey.html +27 -19
  36. data/doc/Dynamoid/Fields.html +94 -77
  37. data/doc/Dynamoid/Fields/ClassMethods.html +166 -37
  38. data/doc/Dynamoid/Finders.html +28 -21
  39. data/doc/Dynamoid/Finders/ClassMethods.html +505 -78
  40. data/doc/Dynamoid/IdentityMap.html +492 -0
  41. data/doc/Dynamoid/IdentityMap/ClassMethods.html +534 -0
  42. data/doc/Dynamoid/Indexes.html +41 -28
  43. data/doc/Dynamoid/Indexes/ClassMethods.html +45 -29
  44. data/doc/Dynamoid/Indexes/Index.html +100 -62
  45. data/doc/Dynamoid/Middleware.html +115 -0
  46. data/doc/Dynamoid/Middleware/IdentityMap.html +264 -0
  47. data/doc/Dynamoid/Persistence.html +326 -85
  48. data/doc/Dynamoid/Persistence/ClassMethods.html +275 -109
  49. data/doc/Dynamoid/Validations.html +47 -31
  50. data/doc/_index.html +116 -71
  51. data/doc/class_list.html +13 -7
  52. data/doc/css/full_list.css +4 -2
  53. data/doc/css/style.css +60 -44
  54. data/doc/file.LICENSE.html +26 -19
  55. data/doc/file.README.html +152 -48
  56. data/doc/file_list.html +14 -8
  57. data/doc/frames.html +20 -5
  58. data/doc/index.html +152 -48
  59. data/doc/js/app.js +52 -43
  60. data/doc/js/full_list.js +14 -9
  61. data/doc/js/jquery.js +4 -16
  62. data/doc/method_list.html +446 -540
  63. data/doc/top-level-namespace.html +27 -20
  64. data/{Dynamoid.gemspec → dynamoid.gemspec} +21 -8
  65. data/lib/dynamoid/adapter.rb +11 -10
  66. data/lib/dynamoid/adapter/aws_sdk.rb +40 -19
  67. data/lib/dynamoid/components.rb +2 -1
  68. data/lib/dynamoid/criteria/chain.rb +29 -11
  69. data/lib/dynamoid/dirty.rb +6 -0
  70. data/lib/dynamoid/document.rb +34 -19
  71. data/lib/dynamoid/fields.rb +36 -30
  72. data/lib/dynamoid/finders.rb +7 -5
  73. data/lib/dynamoid/persistence.rb +37 -10
  74. data/spec/app/models/address.rb +2 -0
  75. data/spec/app/models/camel_case.rb +10 -0
  76. data/spec/app/models/car.rb +6 -0
  77. data/spec/app/models/nuclear_submarine.rb +5 -0
  78. data/spec/app/models/subscription.rb +2 -2
  79. data/spec/app/models/vehicle.rb +7 -0
  80. data/spec/dynamoid/adapter/aws_sdk_spec.rb +20 -11
  81. data/spec/dynamoid/adapter_spec.rb +67 -82
  82. data/spec/dynamoid/associations/association_spec.rb +30 -30
  83. data/spec/dynamoid/criteria/chain_spec.rb +56 -9
  84. data/spec/dynamoid/criteria_spec.rb +3 -0
  85. data/spec/dynamoid/dirty_spec.rb +8 -0
  86. data/spec/dynamoid/document_spec.rb +109 -47
  87. data/spec/dynamoid/fields_spec.rb +32 -3
  88. data/spec/dynamoid/finders_spec.rb +12 -0
  89. data/spec/dynamoid/persistence_spec.rb +73 -8
  90. data/spec/spec_helper.rb +1 -0
  91. data/spec/support/with_partitioning.rb +15 -0
  92. metadata +22 -9
@@ -6,19 +6,21 @@
6
6
  <title>
7
7
  Top Level Namespace
8
8
 
9
- &mdash; Documentation by YARD 0.7.5
9
+ &mdash; Documentation by YARD 0.8.6.1
10
10
 
11
11
  </title>
12
12
 
13
- <link rel="stylesheet" href="css/style.css" type="text/css" media="screen" charset="utf-8" />
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
14
14
 
15
- <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
16
16
 
17
17
  <script type="text/javascript" charset="utf-8">
18
+ hasFrames = window.top.frames.main ? true : false;
18
19
  relpath = '';
19
- if (relpath != '') relpath += '/';
20
+ framesUrl = "frames.html#!" + escape(window.location.href);
20
21
  </script>
21
22
 
23
+
22
24
  <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
23
25
 
24
26
  <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
@@ -26,36 +28,41 @@
26
28
 
27
29
  </head>
28
30
  <body>
29
- <script type="text/javascript" charset="utf-8">
30
- if (window.top.frames.main) document.body.className = 'frames';
31
- </script>
32
-
33
31
  <div id="header">
34
32
  <div id="menu">
35
33
 
36
- <a href="_index.html">Index</a> &raquo;
34
+ <a href="_index.html">Index</a> &raquo;
37
35
 
38
36
 
39
37
  <span class="title">Top Level Namespace</span>
40
38
 
41
-
39
+
42
40
  <div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
43
41
  </div>
44
42
 
45
43
  <div id="search">
46
44
 
47
- <a id="class_list_link" href="#">Class List</a>
45
+ <a class="full_list_link" id="class_list_link"
46
+ href="class_list.html">
47
+ Class List
48
+ </a>
48
49
 
49
- <a id="method_list_link" href="#">Method List</a>
50
+ <a class="full_list_link" id="method_list_link"
51
+ href="method_list.html">
52
+ Method List
53
+ </a>
50
54
 
51
- <a id="file_list_link" href="#">File List</a>
55
+ <a class="full_list_link" id="file_list_link"
56
+ href="file_list.html">
57
+ File List
58
+ </a>
52
59
 
53
60
  </div>
54
61
  <div class="clear"></div>
55
62
  </div>
56
-
63
+
57
64
  <iframe id="search_frame"></iframe>
58
-
65
+
59
66
  <div id="content"><h1>Top Level Namespace
60
67
 
61
68
 
@@ -76,11 +83,11 @@
76
83
 
77
84
  <h2>Defined Under Namespace</h2>
78
85
  <p class="children">
79
-
86
+
80
87
 
81
88
  <strong class="modules">Modules:</strong> <span class='object_link'><a href="Dynamoid.html" title="Dynamoid (module)">Dynamoid</a></span>
82
89
 
83
-
90
+
84
91
 
85
92
 
86
93
  </p>
@@ -94,11 +101,11 @@
94
101
 
95
102
 
96
103
  </div>
97
-
104
+
98
105
  <div id="footer">
99
- Generated on Thu Apr 26 01:26:26 2012 by
106
+ Generated on Thu Jun 27 21:59:09 2013 by
100
107
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
101
- 0.7.5 (ruby-1.9.3).
108
+ 0.8.6.1 (ruby-1.9.3).
102
109
  </div>
103
110
 
104
111
  </body>
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "dynamoid"
8
- s.version = "0.6.1"
8
+ s.version = "0.7.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Josh Symonds"]
12
- s.date = "2013-01-09"
12
+ s.date = "2013-06-28"
13
13
  s.description = "Dynamoid is an ORM for Amazon's DynamoDB that supports offline development, associations, querying, and everything else you'd expect from an ActiveRecord-style replacement."
14
14
  s.email = "josh@joshsymonds.com"
15
15
  s.extra_rdoc_files = [
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.files = [
20
20
  ".document",
21
21
  ".rspec",
22
- "Dynamoid.gemspec",
22
+ ".travis.yml",
23
23
  "Gemfile",
24
24
  "Gemfile.lock",
25
25
  "LICENSE.txt",
@@ -46,20 +46,28 @@ Gem::Specification.new do |s|
46
46
  "doc/Dynamoid/Criteria.html",
47
47
  "doc/Dynamoid/Criteria/Chain.html",
48
48
  "doc/Dynamoid/Criteria/ClassMethods.html",
49
+ "doc/Dynamoid/Dirty.html",
50
+ "doc/Dynamoid/Dirty/ClassMethods.html",
49
51
  "doc/Dynamoid/Document.html",
50
52
  "doc/Dynamoid/Document/ClassMethods.html",
51
53
  "doc/Dynamoid/Errors.html",
54
+ "doc/Dynamoid/Errors/ConditionalCheckFailedException.html",
52
55
  "doc/Dynamoid/Errors/DocumentNotValid.html",
53
56
  "doc/Dynamoid/Errors/Error.html",
54
57
  "doc/Dynamoid/Errors/InvalidField.html",
58
+ "doc/Dynamoid/Errors/InvalidQuery.html",
55
59
  "doc/Dynamoid/Errors/MissingRangeKey.html",
56
60
  "doc/Dynamoid/Fields.html",
57
61
  "doc/Dynamoid/Fields/ClassMethods.html",
58
62
  "doc/Dynamoid/Finders.html",
59
63
  "doc/Dynamoid/Finders/ClassMethods.html",
64
+ "doc/Dynamoid/IdentityMap.html",
65
+ "doc/Dynamoid/IdentityMap/ClassMethods.html",
60
66
  "doc/Dynamoid/Indexes.html",
61
67
  "doc/Dynamoid/Indexes/ClassMethods.html",
62
68
  "doc/Dynamoid/Indexes/Index.html",
69
+ "doc/Dynamoid/Middleware.html",
70
+ "doc/Dynamoid/Middleware/IdentityMap.html",
63
71
  "doc/Dynamoid/Persistence.html",
64
72
  "doc/Dynamoid/Persistence/ClassMethods.html",
65
73
  "doc/Dynamoid/Validations.html",
@@ -78,6 +86,7 @@ Gem::Specification.new do |s|
78
86
  "doc/js/jquery.js",
79
87
  "doc/method_list.html",
80
88
  "doc/top-level-namespace.html",
89
+ "dynamoid.gemspec",
81
90
  "lib/dynamoid.rb",
82
91
  "lib/dynamoid/adapter.rb",
83
92
  "lib/dynamoid/adapter/aws_sdk.rb",
@@ -107,12 +116,15 @@ Gem::Specification.new do |s|
107
116
  "lib/dynamoid/validations.rb",
108
117
  "spec/app/models/address.rb",
109
118
  "spec/app/models/camel_case.rb",
119
+ "spec/app/models/car.rb",
110
120
  "spec/app/models/magazine.rb",
111
121
  "spec/app/models/message.rb",
122
+ "spec/app/models/nuclear_submarine.rb",
112
123
  "spec/app/models/sponsor.rb",
113
124
  "spec/app/models/subscription.rb",
114
125
  "spec/app/models/tweet.rb",
115
126
  "spec/app/models/user.rb",
127
+ "spec/app/models/vehicle.rb",
116
128
  "spec/dynamoid/adapter/aws_sdk_spec.rb",
117
129
  "spec/dynamoid/adapter_spec.rb",
118
130
  "spec/dynamoid/associations/association_spec.rb",
@@ -134,12 +146,13 @@ Gem::Specification.new do |s|
134
146
  "spec/dynamoid/persistence_spec.rb",
135
147
  "spec/dynamoid/validations_spec.rb",
136
148
  "spec/dynamoid_spec.rb",
137
- "spec/spec_helper.rb"
149
+ "spec/spec_helper.rb",
150
+ "spec/support/with_partitioning.rb"
138
151
  ]
139
152
  s.homepage = "http://github.com/Veraticus/Dynamoid"
140
153
  s.licenses = ["MIT"]
141
154
  s.require_paths = ["lib"]
142
- s.rubygems_version = "1.8.23"
155
+ s.rubygems_version = "1.8.25"
143
156
  s.summary = "Dynamoid is an ORM for Amazon's DynamoDB"
144
157
 
145
158
  if s.respond_to? :specification_version then
@@ -157,7 +170,7 @@ Gem::Specification.new do |s|
157
170
  s.add_development_dependency(%q<redcarpet>, ["= 1.17.2"])
158
171
  s.add_development_dependency(%q<github-markup>, [">= 0"])
159
172
  s.add_development_dependency(%q<pry>, [">= 0"])
160
- s.add_development_dependency(%q<fake_dynamo>, [">= 0"])
173
+ s.add_development_dependency(%q<fake_dynamo>, ["~> 0.1.3"])
161
174
  s.add_development_dependency(%q<mocha>, ["= 0.10.0"])
162
175
  else
163
176
  s.add_dependency(%q<activemodel>, [">= 0"])
@@ -171,7 +184,7 @@ Gem::Specification.new do |s|
171
184
  s.add_dependency(%q<redcarpet>, ["= 1.17.2"])
172
185
  s.add_dependency(%q<github-markup>, [">= 0"])
173
186
  s.add_dependency(%q<pry>, [">= 0"])
174
- s.add_dependency(%q<fake_dynamo>, [">= 0"])
187
+ s.add_dependency(%q<fake_dynamo>, ["~> 0.1.3"])
175
188
  s.add_dependency(%q<mocha>, ["= 0.10.0"])
176
189
  end
177
190
  else
@@ -186,7 +199,7 @@ Gem::Specification.new do |s|
186
199
  s.add_dependency(%q<redcarpet>, ["= 1.17.2"])
187
200
  s.add_dependency(%q<github-markup>, [">= 0"])
188
201
  s.add_dependency(%q<pry>, [">= 0"])
189
- s.add_dependency(%q<fake_dynamo>, [">= 0"])
202
+ s.add_dependency(%q<fake_dynamo>, ["~> 0.1.3"])
190
203
  s.add_dependency(%q<mocha>, ["= 0.10.0"])
191
204
  end
192
205
  end
@@ -65,25 +65,28 @@ module Dynamoid
65
65
  #
66
66
  # @param [String] table the name of the table to write the object to
67
67
  # @param [Array] ids to fetch, can also be a string of just one id
68
- # @param [Number] range_key the range key of the record
68
+ # @param [Hash] options: Passed to the underlying query. The :range_key option is required whenever the table has a range key,
69
+ # unless multiple ids are passed in and Dynamoid::Config.partitioning? is turned off.
69
70
  #
70
71
  # @since 0.2.0
71
72
  def read(table, ids, options = {})
72
- range_key = options[:range_key]
73
+ range_key = options.delete(:range_key)
74
+
73
75
  if ids.respond_to?(:each)
74
76
  ids = ids.collect{|id| range_key ? [id, range_key] : id}
75
77
  if Dynamoid::Config.partitioning?
76
- results = batch_get_item(table => id_with_partitions(ids))
78
+ results = batch_get_item({table => id_with_partitions(ids)}, options)
77
79
  {table => result_for_partition(results[table],table)}
78
80
  else
79
- batch_get_item(table => ids)
81
+ batch_get_item({table => ids}, options)
80
82
  end
81
83
  else
82
84
  if Dynamoid::Config.partitioning?
83
85
  ids = range_key ? [[ids, range_key]] : ids
84
- results = batch_get_item(table => id_with_partitions(ids))
86
+ results = batch_get_item({table => id_with_partitions(ids)}, options)
85
87
  result_for_partition(results[table],table).first
86
88
  else
89
+ options[:range_key] = range_key if range_key
87
90
  get_item(table, ids, options)
88
91
  end
89
92
  end
@@ -185,7 +188,7 @@ module Dynamoid
185
188
  range_key_name = table.range_key.name.to_sym
186
189
 
187
190
  final_hash = {}
188
-
191
+
189
192
  results.each do |record|
190
193
  test_record = final_hash[record[range_key_name]]
191
194
 
@@ -254,11 +257,9 @@ module Dynamoid
254
257
  modified_options[:hash_value] = id
255
258
 
256
259
  query_result = Dynamoid::Adapter::AwsSdk.query(table_name, modified_options)
257
- query_result = [query_result] if !query_result.is_a?(Array)
258
-
259
- results = results + query_result unless query_result.nil?
260
+ results += query_result.inject([]){|array, result| array += [result]} if query_result.any?
260
261
  end
261
-
262
+
262
263
  result_for_partition results, table_name
263
264
  end
264
265
  end
@@ -53,20 +53,21 @@ module Dynamoid
53
53
  # Get many items at once from DynamoDB. More efficient than getting each item individually.
54
54
  #
55
55
  # @example Retrieve IDs 1 and 2 from the table testtable
56
- # Dynamoid::Adapter::AwsSdk.batch_get_item('table1' => ['1', '2'])
56
+ # Dynamoid::Adapter::AwsSdk.batch_get_item({'table1' => ['1', '2']}, :consistent_read => true)
57
57
  #
58
- # @param [Hash] options the hash of tables and IDs to retrieve
58
+ # @param [Hash] table_ids the hash of tables and IDs to retrieve
59
+ # @param [Hash] options to be passed to underlying BatchGet call
59
60
  #
60
61
  # @return [Hash] a hash where keys are the table names and the values are the retrieved items
61
62
  #
62
63
  # @since 0.2.0
63
- def batch_get_item(options)
64
+ def batch_get_item(table_ids, options = {})
64
65
  hash = Hash.new{|h, k| h[k] = []}
65
- return hash if options.all?{|k, v| v.empty?}
66
- options.each do |t, ids|
66
+ return hash if table_ids.all?{|k, v| v.empty?}
67
+ table_ids.each do |t, ids|
67
68
  Array(ids).in_groups_of(100, false) do |group|
68
69
  batch = AWS::DynamoDB::BatchGet.new(:config => @@connection.config)
69
- batch.table(t, :all, Array(group)) unless group.nil? || group.empty?
70
+ batch.table(t, :all, Array(group), options) unless group.nil? || group.empty?
70
71
  batch.each do |table_name, attributes|
71
72
  hash[table_name] << attributes.symbolize_keys!
72
73
  end
@@ -196,6 +197,8 @@ module Dynamoid
196
197
  object.delete_if{|k, v| v.nil? || (v.respond_to?(:empty?) && v.empty?)},
197
198
  options || {}
198
199
  )
200
+ rescue AWS::DynamoDB::Errors::ConditionalCheckFailedException => e
201
+ raise Dynamoid::Errors::ConditionalCheckFailedException
199
202
  end
200
203
 
201
204
  # Query the DynamoDB table. This employs DynamoDB's indexes so is generally faster than scanning, but is
@@ -211,19 +214,25 @@ module Dynamoid
211
214
  # @option opts [Number] :range_gte find range keys greater than or equal to this
212
215
  # @option opts [Number] :range_lte find range keys less than or equal to this
213
216
  #
214
- # @return [Array] an array of all matching items
217
+ # @return [Enumerator] an iterator of all matching items
215
218
  #
216
219
  # @since 0.2.0
217
220
  def query(table_name, opts = {})
218
221
  table = get_table(table_name)
219
222
 
220
- consistent_opts = { :consistent_read => opts[:consistent_read] || false }
221
- if table.composite_key?
222
- results = []
223
- table.items.query(opts).each {|data| results << data.attributes.to_h(consistent_opts).symbolize_keys!}
224
- results
225
- else
226
- get_item(table_name, opts[:hash_value])
223
+ Enumerator.new do |yielder|
224
+ consistent_opts = { :consistent_read => opts[:consistent_read] || false }
225
+ if table.composite_key?
226
+ table.items.query(opts).each do |data|
227
+ if opts.has_key? :select
228
+ yielder.yield data.attributes.symbolize_keys!
229
+ else
230
+ yielder.yield data.attributes.to_h(consistent_opts).symbolize_keys!
231
+ end
232
+ end
233
+ else
234
+ yielder.yield get_item(table_name, opts[:hash_value])
235
+ end
227
236
  end
228
237
  end
229
238
 
@@ -233,16 +242,16 @@ module Dynamoid
233
242
  # @param [String] table_name the name of the table
234
243
  # @param [Hash] scan_hash a hash of attributes: matching records will be returned by the scan
235
244
  #
236
- # @return [Array] an array of all matching items
245
+ # @return [Enumerator] an iterator of all matching items
237
246
  #
238
247
  # @since 0.2.0
239
248
  def scan(table_name, scan_hash, select_opts)
240
249
  table = get_table(table_name)
241
- results = []
242
- table.items.where(scan_hash).select(select_opts) do |data|
243
- results << data.attributes.symbolize_keys!
250
+ Enumerator.new do |yielder|
251
+ table.items.where(scan_hash).select(select_opts).each do |data|
252
+ yielder.yield data.attributes.symbolize_keys!
253
+ end
244
254
  end
245
- results
246
255
  end
247
256
 
248
257
  # @todo Add an UpdateItem method.
@@ -261,6 +270,18 @@ module Dynamoid
261
270
  def table_cache
262
271
  @table_cache ||= {}
263
272
  end
273
+
274
+ # Number of items from a table
275
+ #
276
+ # @param [String] table_name the name of the table
277
+ #
278
+ # @return [Integer] the number of items from a table
279
+ #
280
+ # @since 0.6.1
281
+ def count(table_name)
282
+ table = get_table(table_name)
283
+ table.items.count
284
+ end
264
285
  end
265
286
  end
266
287
  end
@@ -10,10 +10,11 @@ module Dynamoid
10
10
  extend ActiveModel::Translation
11
11
  extend ActiveModel::Callbacks
12
12
 
13
- define_model_callbacks :create, :save, :destroy, :initialize
13
+ define_model_callbacks :create, :save, :destroy, :initialize, :update
14
14
 
15
15
  before_create :set_created_at
16
16
  before_save :set_updated_at
17
+ after_initialize :set_type
17
18
  end
18
19
 
19
20
  include ActiveModel::AttributeMethods
@@ -31,7 +31,7 @@ module Dynamoid #:nodoc:
31
31
  #
32
32
  # @since 0.2.0
33
33
  def where(args)
34
- args.each {|k, v| query[k] = v}
34
+ args.each {|k, v| query[k.to_sym] = v}
35
35
  self
36
36
  end
37
37
 
@@ -43,7 +43,8 @@ module Dynamoid #:nodoc:
43
43
  # Returns all the records matching the criteria.
44
44
  #
45
45
  # @since 0.2.0
46
- def all
46
+ def all(opts = {})
47
+ batch opts[:batch_size] if opts.has_key? :batch_size
47
48
  records
48
49
  end
49
50
 
@@ -116,6 +117,12 @@ module Dynamoid #:nodoc:
116
117
  records
117
118
  end
118
119
 
120
+ def batch(batch_size)
121
+ raise 'Cannot batch calls when using partitioning' if Dynamoid::Config.partitioning?
122
+ @batch_size = batch_size
123
+ self
124
+ end
125
+
119
126
  def start(start)
120
127
  @start = start
121
128
  self
@@ -141,28 +148,29 @@ module Dynamoid #:nodoc:
141
148
 
142
149
  # The actual records referenced by the association.
143
150
  #
144
- # @return [Array] an array of the found records.
151
+ # @return [Enumerator] an iterator of the found records.
145
152
  #
146
153
  # @since 0.2.0
147
154
  def records
148
- if range?
155
+ results = if range?
149
156
  records_with_range
150
157
  elsif index
151
158
  records_with_index
152
159
  else
153
160
  records_without_index
154
161
  end
162
+ @batch_size ? results : Array(results)
155
163
  end
156
164
 
157
165
  # If the query matches an index on the associated class, then this method will retrieve results from the index table.
158
166
  #
159
- # @return [Array] an array of the found records.
167
+ # @return [Enumerator] an iterator of the found records.
160
168
  #
161
169
  # @since 0.2.0
162
170
  def records_with_index
163
171
  ids = ids_from_index
164
172
  if ids.nil? || ids.empty?
165
- []
173
+ Enumerator.new []
166
174
  else
167
175
  ids = ids.to_a
168
176
 
@@ -171,7 +179,7 @@ module Dynamoid #:nodoc:
171
179
  end
172
180
 
173
181
  ids = ids.take(@limit) if @limit
174
- Array(source.find(ids, consistent_opts))
182
+ source.find(ids, consistent_opts)
175
183
  end
176
184
  end
177
185
 
@@ -190,12 +198,16 @@ module Dynamoid #:nodoc:
190
198
  end
191
199
 
192
200
  def records_with_range
193
- Dynamoid::Adapter.query(source.table_name, range_query).collect {|hash| source.from_database(hash) }
201
+ Enumerator.new do |yielder|
202
+ Dynamoid::Adapter.query(source.table_name, range_query).each do |hash|
203
+ yielder.yield source.from_database(hash)
204
+ end
205
+ end
194
206
  end
195
207
 
196
208
  # If the query does not match an index, we'll manually scan the associated table to find results.
197
209
  #
198
- # @return [Array] an array of the found records.
210
+ # @return [Enumerator] an iterator of the found records.
199
211
  #
200
212
  # @since 0.2.0
201
213
  def records_without_index
@@ -208,7 +220,11 @@ module Dynamoid #:nodoc:
208
220
  raise Dynamoid::Errors::InvalidQuery, 'Consistent read is not supported by SCAN operation'
209
221
  end
210
222
 
211
- Dynamoid::Adapter.scan(source.table_name, query, scan_opts).collect {|hash| source.from_database(hash) }
223
+ Enumerator.new do |yielder|
224
+ Dynamoid::Adapter.scan(source.table_name, query, scan_opts).each do |hash|
225
+ yielder.yield source.from_database(hash)
226
+ end
227
+ end
212
228
  end
213
229
 
214
230
  # Format the provided query so that it can be used to query results from DynamoDB.
@@ -271,8 +287,9 @@ module Dynamoid #:nodoc:
271
287
  query.keys.collect{|k| k.to_s.split('.').first}
272
288
  end
273
289
 
290
+ # Use range query only when [hash_key] or [hash_key, range_key] is specified in query keys.
274
291
  def range?
275
- return false unless source.range_key
292
+ return false unless query_keys.include?(source.hash_key.to_s) or query_keys.include?(source.range_key.to_s)
276
293
  query_keys == [source.hash_key.to_s] || (query_keys.to_set == [source.hash_key.to_s, source.range_key.to_s].to_set)
277
294
  end
278
295
 
@@ -298,6 +315,7 @@ module Dynamoid #:nodoc:
298
315
  opts = {}
299
316
  opts[:limit] = @limit if @limit
300
317
  opts[:next_token] = start_key if @start
318
+ opts[:batch_size] = @batch_size if @batch_size
301
319
  opts
302
320
  end
303
321
  end