aws-sdk 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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