aws-sdk 1.0.1 → 1.0.2

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.
@@ -19,7 +19,9 @@ require 'aws/indifferent_hash'
19
19
 
20
20
  require 'aws/record/naming'
21
21
  require 'aws/record/attribute_macros'
22
+ require 'aws/record/scopes'
22
23
  require 'aws/record/finder_methods'
24
+ require 'aws/record/optimistic_locking'
23
25
  require 'aws/record/validations'
24
26
  require 'aws/record/dirty_tracking'
25
27
  require 'aws/record/conversion'
@@ -288,6 +290,9 @@ module AWS
288
290
  extend Validations
289
291
  extend AttributeMacros
290
292
  extend FinderMethods
293
+ extend OptimisticLocking
294
+ extend Scopes
295
+
291
296
  include Conversion
292
297
  include DirtyTracking
293
298
 
@@ -410,6 +415,41 @@ module AWS
410
415
  persisted? ? !!@_deleted : false
411
416
  end
412
417
 
418
+ class << self
419
+
420
+ # @return [Hash<String,Attribute>] Returns a hash of all of the
421
+ # configured attributes for this class.
422
+ def attributes
423
+ @attributes ||= {}
424
+ end
425
+
426
+ # Allows you to override the default domain name for this record.
427
+ # The defualt domain name is the class name.
428
+ # @param [String] The domain name that should be used for this class.
429
+ def set_domain_name name
430
+ @_domain_name = name
431
+ end
432
+
433
+ # @return [String] Returns the full prefixed domain name for this class.
434
+ def domain_name
435
+ @_domain_name ||= self.to_s
436
+ "#{Record.domain_prefix}#{@_domain_name}"
437
+ end
438
+
439
+ # Creates the SimpleDB domain that is configured for this class.
440
+ def create_domain
441
+ AWS::SimpleDB.new.domains.create(domain_name)
442
+ end
443
+
444
+ # @return [AWS::SimpleDB::Domain] Returns a reference to the domain
445
+ # this class will save data to.
446
+ # @private
447
+ def sdb_domain
448
+ AWS::SimpleDB.new.domains[domain_name]
449
+ end
450
+
451
+ end
452
+
413
453
  # If you define a custom setter, you use #[]= to set the value
414
454
  # on the record.
415
455
  #
@@ -16,6 +16,7 @@ require 'aws/record/scope'
16
16
 
17
17
  module AWS
18
18
  module Record
19
+
19
20
  module FinderMethods
20
21
 
21
22
  # @param [String] id The id of the record to load.
@@ -83,8 +84,22 @@ module AWS
83
84
  _new_scope.find(*args)
84
85
  end
85
86
 
86
- # Equivalent to +find(:all)+
87
- def all(options = {})
87
+ # Returns an enumerable scope object represents all records.
88
+ #
89
+ # Book.all.each do |book|
90
+ # # ...
91
+ # end
92
+ #
93
+ # This method is equivalent to +find(:all)+, and therefore you can also
94
+ # pass aditional options. See {#find} for more information on what
95
+ # options you can pass.
96
+ #
97
+ # Book.all(:where => { :author' => 'me' }).each do |my_book|
98
+ # # ...
99
+ # end
100
+ #
101
+ # @return [Scope] Returns an enumerable scope object.
102
+ def all options = {}
88
103
  find(:all, options)
89
104
  end
90
105
 
@@ -188,75 +203,6 @@ module AWS
188
203
  _new_scope.limit(limit)
189
204
  end
190
205
 
191
- # @private
192
- def _new_scope
193
- Scope.new(self)
194
- end
195
- private :_new_scope
196
-
197
- # A configuration method to override the default domain name.
198
- # @param [String] The domain name that should be used for this class.
199
- def set_domain_name name
200
- @_domain_name = name
201
- end
202
-
203
- # @return [String] Returns the full prefixed domain name for this class.
204
- #
205
- def domain_name
206
- @_domain_name ||= self.to_s
207
- "#{Record.domain_prefix}#{@_domain_name}"
208
- end
209
-
210
- # @return [AWS::SimpleDB::Domain] A reference to the domain
211
- # this class will save data to.
212
- def sdb_domain
213
- AWS::SimpleDB.new.domains[domain_name]
214
- end
215
-
216
- # Creates the SimpleDB domain that is configured for this class.
217
- def create_domain
218
- AWS::SimpleDB.new.domains.create(domain_name)
219
- end
220
-
221
- # @return [Hash] A hash of Attribute objects that represent the
222
- # "columns" objects in this domain use.
223
- def attributes
224
- @attributes ||= {}
225
- end
226
-
227
- # @param [Symbol] name The name of the scope. Scope names should be
228
- # method-safe and should not conflict with any of the class
229
- # methods of {Record::Base} or {Record::Scope}.
230
- #
231
- # Adding a scope using built-in scope modifiers:
232
- #
233
- # scope :top_10, order(:rating, :desc).limit(10)
234
- #
235
- def scope name, scope = nil, &block
236
-
237
- raise ArgumentError, "only a scope or block may be passed, not both" if
238
- scope and block_given?
239
-
240
- if scope
241
- method_definition = lambda { scope }
242
- else
243
- method_definition = block
244
- end
245
-
246
- extend(Module.new { define_method(name, &method_definition) })
247
-
248
- end
249
-
250
- def optimistic_locking attribute_name = :version_id
251
- attribute = integer_attr(attribute_name)
252
- @optimistic_locking_attr = attribute
253
- end
254
-
255
- # @private
256
- def optimistic_locking_attr
257
- @optimistic_locking_attr
258
- end
259
-
260
206
  end
261
207
  end
262
208
  end
@@ -0,0 +1,34 @@
1
+ # Copyright 2011 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+ require 'aws/simple_db'
15
+ require 'aws/record/scope'
16
+
17
+ module AWS
18
+ module Record
19
+
20
+ module OptimisticLocking
21
+
22
+ def optimistic_locking attribute_name = :version_id
23
+ attribute = integer_attr(attribute_name)
24
+ @optimistic_locking_attr = attribute
25
+ end
26
+
27
+ # @private
28
+ def optimistic_locking_attr
29
+ @optimistic_locking_attr
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -13,17 +13,82 @@
13
13
 
14
14
  module AWS
15
15
  module Record
16
+
17
+ # The primary interface for finding records with AWS::Record.
18
+ #
19
+ # == Getting a Scope Object
20
+ #
21
+ # You should normally never need to construct a Scope object directly.
22
+ # Scope objects are returned from the AWS::Record::Base finder methods
23
+ # (e.g. +find+ +all+, +where+, +order+, +limit+, etc).
24
+ #
25
+ # books = Book.where(:author => 'John Doe')
26
+ # books.class #=> AWS::Record::Scope, not Array
27
+ #
28
+ # Scopes are also returned from methods defined with the +scope+ method.
29
+ #
30
+ # == Delayed Execution
31
+ #
32
+ # Scope objects represent a select expression, but do not actually
33
+ # cause a request to be made until enumerated.
34
+ #
35
+ # # no request made yet
36
+ # books = Book.where(:author => 'John Doe')
37
+ #
38
+ # # a request is made now
39
+ # books.each {|book| ... }
40
+ #
41
+ # You can refine a scope object by calling other scope methods on
42
+ # it.
43
+ #
44
+ # # refine the previous books Scope, no request
45
+ # top_10 = books.order(:popularity, :desc).limit(10)
46
+ #
47
+ # # another request is made now
48
+ # top_10.first
49
+ #
16
50
  class Scope
17
51
 
18
52
  include Enumerable
19
-
20
- attr_reader :base_class
21
53
 
54
+ # @param [Record::Base] base_class A class that extends
55
+ # {AWS::Record::Base}.
56
+ # @param [Hash] options
57
+ # @option options :
58
+ # @private
22
59
  def initialize base_class, options = {}
23
60
  @base_class = base_class
24
61
  @options = options
25
62
  end
26
63
 
64
+ # @return [Class] Returns the AWS::Record::Base extending class that
65
+ # this scope will find records for.
66
+ attr_reader :base_class
67
+
68
+ # @overload find(id)
69
+ # Finds and returns a single record by id. If no record is found
70
+ # with the given +id+, then a RecordNotFound error will be raised.
71
+ # @param [String] id ID of the record to find.
72
+ # @return [Record::Base] Returns the record.
73
+ #
74
+ # @overload find(:first, options = {})
75
+ # Returns the first record found. If no records were matched then
76
+ # nil will be returned (raises no exceptions).
77
+ # @param [Symbol] mode (:first)
78
+ # @return [Object,nil] Returns the first record or nil if no
79
+ # records matched the conditions.
80
+ #
81
+ # @overload find(:all, options = {})
82
+ # Returns an enumerable Scope object that represents all matching
83
+ # records. No request is made to AWS until the scope is enumerated.
84
+ #
85
+ # Book.find(:all, :limit => 100).each do |book|
86
+ # # ...
87
+ # end
88
+ #
89
+ # @param [Symbol] mode (:all)
90
+ # @return [Scope] Returns an enumerable scope object.
91
+ #
27
92
  def find id_or_mode, options = {}
28
93
 
29
94
  scope = _handle_options(options)
@@ -35,16 +100,17 @@ module AWS
35
100
  else
36
101
  object = scope.where('itemName() = ?', id_or_mode).limit(1).first
37
102
  if object.nil?
38
- raise RecordNotFound, "no data found for id: #{id_or_mode}"
103
+ raise RecordNotFound, "no data found for record `#{id_or_mode}`"
39
104
  end
40
105
  object
41
106
  end
42
107
 
43
108
  end
44
109
 
45
- def count(options = {})
46
- if scope = _handle_options(options) and
47
- scope != self
110
+ # @return [Integer] Returns the number of records that match the
111
+ # current scoped finder.
112
+ def count options = {}
113
+ if scope = _handle_options(options) and scope != self
48
114
  scope.count
49
115
  else
50
116
  _item_collection.count
@@ -52,6 +118,31 @@ module AWS
52
118
  end
53
119
  alias_method :size, :count
54
120
 
121
+ # Applies conditions to the scope that limit which records are returned.
122
+ # Only those matching all given conditions will be returned.
123
+ #
124
+ # @overload where(conditions_hash)
125
+ # Specify a hash of conditions to query with. Multiple conditions
126
+ # are joined together with AND.
127
+ #
128
+ # Book.where(:author => 'John Doe', :softcover => true)
129
+ # # where `author` = `John Doe` AND `softcover` = `1`
130
+ #
131
+ # @param [Hash] conditions
132
+ #
133
+ # @overload where(conditions_string, *values)
134
+ # A sql-like query fragment with optional placeholders and values.
135
+ # Placeholders are replaced with properly quoted values.
136
+ #
137
+ # Book.where('author = ?', 'John Doe')
138
+ #
139
+ # @param [String] conditions_string A sql-like where string with
140
+ # question mark placeholders. For each placeholder there should
141
+ # be a value that will be quoted into that position.
142
+ # @param [String] *values A value that should be quoted into the
143
+ # corresponding (by position) placeholder.
144
+ #
145
+ # @return [Scope] Returns a new scope with the passed conditions applied.
55
146
  def where *conditions
56
147
  if conditions.empty?
57
148
  raise ArgumentError, 'missing required condition'
@@ -59,14 +150,47 @@ module AWS
59
150
  _with(:where => Record.as_array(@options[:where]) + [conditions])
60
151
  end
61
152
 
62
- def order attribute, order = :asc
63
- _with(:order => [attribute, order])
153
+ # Specifies how to sort records returned.
154
+ #
155
+ # # enumerate books, starting with the most recently published ones
156
+ # Book.order(:published_at, :desc).each do |book|
157
+ # # ...
158
+ # end
159
+ #
160
+ # Only one order may be applied. If order is specified more than
161
+ # once the last one in the chain takes precedence:
162
+ #
163
+ #
164
+ # # books returned by this scope will be ordered by :published_at
165
+ # # and not :author.
166
+ # Book.where(:read => false).order(:author).order(:published_at)
167
+ #
168
+ # @param [String,Symbol] attribute_name The attribute to sort by.
169
+ # @param [:asc, :desc] order (:asc) The direct to sort.
170
+ def order attribute_name, order = :asc
171
+ _with(:order => [attribute_name, order])
64
172
  end
65
173
 
174
+ # Limits the maximum number of total records to return when finding
175
+ # or counting. Returns a scope, does not make a request.
176
+ #
177
+ # books = Book.limit(100)
178
+ #
179
+ # @param [Integer] limit The maximum number of records to return.
180
+ # @return [Scope] Returns a new scope that has the applied limit.
66
181
  def limit limit
67
182
  _with(:limit => limit)
68
183
  end
69
184
 
185
+ # Yields once for each record matching the request made by this scope.
186
+ #
187
+ # books = Book.where(:author => 'me').order(:price, :asc).limit(10)
188
+ #
189
+ # books.each do |book|
190
+ # puts book.attributes.to_yaml
191
+ # end
192
+ #
193
+ # @yieldparam [Object] record
70
194
  def each &block
71
195
  if block_given?
72
196
  _each_object(&block)
@@ -76,12 +200,13 @@ module AWS
76
200
  end
77
201
 
78
202
  # @private
203
+ private
79
204
  def _empty?
80
205
  @options == {}
81
206
  end
82
- private :_empty?
83
207
 
84
208
  # @private
209
+ private
85
210
  def _each_object &block
86
211
 
87
212
  items = _item_collection
@@ -93,22 +218,27 @@ module AWS
93
218
  end
94
219
 
95
220
  end
96
- private :_each_object
97
221
 
98
222
  # @private
223
+ private
99
224
  def _with options
100
225
  Scope.new(base_class, @options.merge(options))
101
226
  end
102
- private :_with
103
227
 
104
228
  # @private
229
+ private
105
230
  def method_missing scope_name, *args
106
231
  # @todo only proxy named scope methods
107
232
  _merge_scope(base_class.send(scope_name, *args))
108
233
  end
109
- private :method_missing
110
234
 
235
+ # Merges another scope with this scope. Conditions are added together
236
+ # and the limit and order parts replace those in this scope (if set).
237
+ # @param [Scope] scope A scope to merge with this one.
238
+ # @return [Scope] Returns a new scope with merged conditions and
239
+ # overriden order and limit.
111
240
  # @private
241
+ private
112
242
  def _merge_scope scope
113
243
  merged = self
114
244
  scope.instance_variable_get('@options').each_pair do |opt_name,opt_value|
@@ -124,10 +254,18 @@ module AWS
124
254
  end
125
255
  merged
126
256
  end
127
- private :_merge_scope
128
257
 
258
+ # Consumes a hash of options (e.g. +:where+, +:order+ and +:limit+) and
259
+ # builds them onto the current scope, returning a new one.
260
+ # @param [Hash] options
261
+ # @option options :where
262
+ # @option options :order
263
+ # @option options [Integer] :limit
264
+ # @return [Scope] Returns a new scope with the hash of scope
265
+ # options applied.
129
266
  # @private
130
- def _handle_options(options)
267
+ private
268
+ def _handle_options options
131
269
  scope = self
132
270
  options.each_pair do |method, args|
133
271
  if method == :where and args.is_a?(Hash)
@@ -139,9 +277,11 @@ module AWS
139
277
  end
140
278
  scope
141
279
  end
142
- private :_handle_options
143
280
 
281
+ # Converts this scope object into an AWS::SimpleDB::ItemCollection
282
+ # @return [SimpleDB::ItemCollection]
144
283
  # @private
284
+ private
145
285
  def _item_collection
146
286
  items = base_class.sdb_domain.items
147
287
  items = items.order(*@options[:order]) if @options[:order]
@@ -151,7 +291,7 @@ module AWS
151
291
  end
152
292
  items
153
293
  end
154
- private :_item_collection
294
+
155
295
  end
156
296
  end
157
297
  end