aws-sdk 1.2.6 → 1.3.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.
- data/lib/aws.rb +2 -0
- data/lib/aws/api_config/DynamoDB-2011-12-05.yml +721 -0
- data/lib/aws/core.rb +10 -1
- data/lib/aws/core/client.rb +17 -12
- data/lib/aws/core/configuration.rb +13 -3
- data/lib/aws/core/configured_json_client_methods.rb +71 -0
- data/lib/aws/core/lazy_error_classes.rb +7 -2
- data/lib/aws/core/option_grammar.rb +67 -13
- data/lib/aws/core/resource.rb +9 -1
- data/lib/aws/core/session_signer.rb +95 -0
- data/lib/aws/dynamo_db.rb +169 -0
- data/lib/aws/dynamo_db/attribute_collection.rb +460 -0
- data/lib/aws/dynamo_db/batch_get.rb +206 -0
- data/lib/aws/dynamo_db/client.rb +119 -0
- data/lib/aws/dynamo_db/config.rb +20 -0
- data/lib/aws/dynamo_db/errors.rb +57 -0
- data/lib/aws/dynamo_db/expectations.rb +40 -0
- data/lib/aws/dynamo_db/item.rb +130 -0
- data/lib/aws/dynamo_db/item_collection.rb +837 -0
- data/lib/aws/{record/optimistic_locking.rb → dynamo_db/item_data.rb} +9 -12
- data/lib/aws/{record/attributes/boolean.rb → dynamo_db/keys.rb} +15 -23
- data/lib/aws/dynamo_db/primary_key_element.rb +47 -0
- data/lib/aws/dynamo_db/request.rb +78 -0
- data/lib/aws/{record/attributes/float.rb → dynamo_db/resource.rb} +10 -25
- data/lib/aws/dynamo_db/table.rb +418 -0
- data/lib/aws/dynamo_db/table_collection.rb +165 -0
- data/lib/aws/dynamo_db/types.rb +86 -0
- data/lib/aws/ec2/resource_tag_collection.rb +3 -1
- data/lib/aws/record.rb +36 -8
- data/lib/aws/record/abstract_base.rb +642 -0
- data/lib/aws/record/attributes.rb +384 -0
- data/lib/aws/record/dirty_tracking.rb +0 -1
- data/lib/aws/record/errors.rb +0 -8
- data/lib/aws/record/hash_model.rb +163 -0
- data/lib/aws/record/hash_model/attributes.rb +182 -0
- data/lib/aws/record/hash_model/finder_methods.rb +178 -0
- data/lib/aws/record/hash_model/scope.rb +108 -0
- data/lib/aws/record/model.rb +429 -0
- data/lib/aws/record/model/attributes.rb +377 -0
- data/lib/aws/record/model/finder_methods.rb +232 -0
- data/lib/aws/record/model/scope.rb +213 -0
- data/lib/aws/record/scope.rb +43 -169
- data/lib/aws/record/validations.rb +11 -11
- data/lib/aws/s3/client.rb +9 -6
- data/lib/aws/s3/object_collection.rb +1 -1
- data/lib/aws/simple_db/expect_condition_option.rb +1 -1
- data/lib/aws/simple_db/item_collection.rb +5 -3
- data/lib/aws/sts/client.rb +9 -0
- metadata +73 -30
- data/lib/aws/record/attribute.rb +0 -94
- data/lib/aws/record/attribute_macros.rb +0 -312
- data/lib/aws/record/attributes/date.rb +0 -89
- data/lib/aws/record/attributes/datetime.rb +0 -86
- data/lib/aws/record/attributes/integer.rb +0 -68
- data/lib/aws/record/attributes/sortable_float.rb +0 -60
- data/lib/aws/record/attributes/sortable_integer.rb +0 -95
- data/lib/aws/record/attributes/string.rb +0 -69
- data/lib/aws/record/base.rb +0 -828
- data/lib/aws/record/finder_methods.rb +0 -230
- data/lib/aws/record/scopes.rb +0 -55
@@ -0,0 +1,232 @@
|
|
1
|
+
# Copyright 2011-2012 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
|
+
module AWS
|
15
|
+
module Record
|
16
|
+
class Model
|
17
|
+
class << self
|
18
|
+
|
19
|
+
# @param [String] id The id of the record to load.
|
20
|
+
# @param [Hash] options
|
21
|
+
# @option options [String] :shard Specifies what shard (i.e. domain)
|
22
|
+
# should be searched.
|
23
|
+
# @raise [RecordNotFound] Raises a record not found exception if there
|
24
|
+
# was no data found for the given id.
|
25
|
+
# @return [Record::HashModel] Returns the record with the given id.
|
26
|
+
def find_by_id id, options = {}
|
27
|
+
|
28
|
+
domain = sdb_domain(options[:shard] || options[:domain])
|
29
|
+
|
30
|
+
data = domain.items[id].data.attributes
|
31
|
+
|
32
|
+
raise RecordNotFound, "no data found for id: #{id}" if data.empty?
|
33
|
+
|
34
|
+
obj = self.new(:shard => domain)
|
35
|
+
obj.send(:hydrate, id, data)
|
36
|
+
obj
|
37
|
+
|
38
|
+
end
|
39
|
+
alias_method :[], :find_by_id
|
40
|
+
|
41
|
+
# Finds records in SimpleDB and returns them as objects of the
|
42
|
+
# current class.
|
43
|
+
#
|
44
|
+
# Finding +:all+ returns an enumerable scope object
|
45
|
+
#
|
46
|
+
# People.find(:all, :order => [:age, :desc], :limit => 10).each do |person|
|
47
|
+
# puts person.name
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# Finding +:first+ returns a single record (or nil)
|
51
|
+
#
|
52
|
+
# boss = People.find(:first, :where => { :boss => true })
|
53
|
+
#
|
54
|
+
# Find accepts a hash of find modifiers (+:where+, +:order+ and
|
55
|
+
# +:limit+). You can also choose to omit these modifiers and
|
56
|
+
# chain them on the scope object returned. In the following
|
57
|
+
# example only one request is made to SimpleDB (when #each is
|
58
|
+
# called)
|
59
|
+
#
|
60
|
+
# people = People.find(:all)
|
61
|
+
#
|
62
|
+
# johns = people.where(:name => 'John Doe')
|
63
|
+
#
|
64
|
+
# johns.order(:age, :desc).limit(10).each do |suspects|
|
65
|
+
# # ...
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# See also {#where}, {#order} and {#limit} for more
|
69
|
+
# information and options.
|
70
|
+
#
|
71
|
+
# @overload find(id)
|
72
|
+
# @param id The record to find, raises an exception if the record is
|
73
|
+
# not found.
|
74
|
+
#
|
75
|
+
# @overload find(mode, options = {})
|
76
|
+
# @param [:all,:first] mode (:all) When finding +:all+ matching records
|
77
|
+
# and array is returned of records. When finding +:first+ then
|
78
|
+
# +nil+ or a single record will be returned.
|
79
|
+
# @param [Hash] options
|
80
|
+
# @option options [Mixed] :where Conditions that determine what
|
81
|
+
# records are returned.
|
82
|
+
# @option options [String,Array] :sort The order records should be
|
83
|
+
# returned in.
|
84
|
+
# @option options [Integer] :limit The max number of records to fetch.
|
85
|
+
def find *args
|
86
|
+
new_scope.find(*args)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns a chainable scope object that restricts further scopes to a
|
90
|
+
# particular domain.
|
91
|
+
#
|
92
|
+
# Book.domain('books-2').each do |book|
|
93
|
+
# # ...
|
94
|
+
# end
|
95
|
+
#
|
96
|
+
# @param [String] domain
|
97
|
+
# @return [Scope] Returns a scope for restricting the domain of subsequent
|
98
|
+
def shard shard_name
|
99
|
+
new_scope.shard(shard_name)
|
100
|
+
end
|
101
|
+
alias_method :domain, :shard
|
102
|
+
|
103
|
+
# Returns an enumerable scope object represents all records.
|
104
|
+
#
|
105
|
+
# Book.all.each do |book|
|
106
|
+
# # ...
|
107
|
+
# end
|
108
|
+
#
|
109
|
+
# This method is equivalent to +find(:all)+, and therefore you can also
|
110
|
+
# pass aditional options. See {#find} for more information on what
|
111
|
+
# options you can pass.
|
112
|
+
#
|
113
|
+
# Book.all(:where => { :author' => 'me' }).each do |my_book|
|
114
|
+
# # ...
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
# @return [Scope] Returns an enumerable scope object.
|
118
|
+
def all options = {}
|
119
|
+
new_scope.find(:all, options)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Yields once for each record.
|
123
|
+
def each &block
|
124
|
+
all.each(&block)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Counts records in SimpleDB.
|
128
|
+
#
|
129
|
+
# With no arguments, counts all records:
|
130
|
+
#
|
131
|
+
# People.count
|
132
|
+
#
|
133
|
+
# Accepts query options to count a subset of records:
|
134
|
+
#
|
135
|
+
# People.count(:where => { :boss => true })
|
136
|
+
#
|
137
|
+
# You can also count records on a scope object:
|
138
|
+
#
|
139
|
+
# People.find(:all).where(:boss => true).count
|
140
|
+
#
|
141
|
+
# See {#find} and {Scope#count} for more details.
|
142
|
+
#
|
143
|
+
# @param [Hash] options (<code>{}</code>) Options for counting
|
144
|
+
# records.
|
145
|
+
#
|
146
|
+
# @option options [Mixed] :where Conditions that determine what
|
147
|
+
# records are counted.
|
148
|
+
# @option options [Integer] :limit The max number of records to count.
|
149
|
+
def count(options = {})
|
150
|
+
new_scope.count(options)
|
151
|
+
end
|
152
|
+
alias_method :size, :count
|
153
|
+
|
154
|
+
# @return [Object,nil] Returns the first record found. If there were
|
155
|
+
# no records found, nil is returned.
|
156
|
+
def first options = {}
|
157
|
+
new_scope.first(options)
|
158
|
+
end
|
159
|
+
|
160
|
+
# Limits which records are retried from SimpleDB when performing a find.
|
161
|
+
#
|
162
|
+
# Simple string condition
|
163
|
+
#
|
164
|
+
# Car.where('color = "red" or color = "blue"').each {|car| ... }
|
165
|
+
#
|
166
|
+
# String with placeholders for quoting params
|
167
|
+
#
|
168
|
+
# Car.where('color = ?', 'red')
|
169
|
+
#
|
170
|
+
# Car.where('color = ? OR style = ?', 'red', 'compact')
|
171
|
+
#
|
172
|
+
# # produces a condition using in, like: WHERE color IN ('red', 'blue')
|
173
|
+
# Car.where('color IN ?', ['red','blue'])
|
174
|
+
#
|
175
|
+
# Hash arguments
|
176
|
+
#
|
177
|
+
# # WHERE age = '40' AND gender = 'male'
|
178
|
+
# People.where(:age => 40, :gender => 'male').each {|person| ... }
|
179
|
+
#
|
180
|
+
# # WHERE name IN ('John', 'Jane')
|
181
|
+
# People.where(:name => ['John', 'Jane']).each{|person| ... }
|
182
|
+
#
|
183
|
+
# Chaining where with other scope modifiers
|
184
|
+
#
|
185
|
+
# # 10 most expensive red cars
|
186
|
+
# Car.where(:color => 'red').order(:price, :desc).limit(10)
|
187
|
+
#
|
188
|
+
# @overload where(conditions_hash)
|
189
|
+
# @overload where(sql_fragment[, quote_params, ...])
|
190
|
+
#
|
191
|
+
# @param [Hash] conditions_hash A hash of attributes to values. Each
|
192
|
+
# key/value pair from the hash becomes a find condition. All conditions
|
193
|
+
# are joined by AND.
|
194
|
+
def where *args
|
195
|
+
new_scope.where(*args)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Defines the order in which records are returned when performing a find.
|
199
|
+
# SimpleDB only allows sorting by one attribute per request.
|
200
|
+
#
|
201
|
+
# # oldest to youngest
|
202
|
+
# People.order(:age, :desc).each {|person| ... }
|
203
|
+
#
|
204
|
+
# You can chain order with the other scope modifiers:
|
205
|
+
#
|
206
|
+
# Pepole.order(:age, :desc).limit(10).each {|person| ... }
|
207
|
+
#
|
208
|
+
# @overload order(attribute, direction = :asc)
|
209
|
+
# @param [String,Symbol] attribute The attribute in SimpleDB to sort by.
|
210
|
+
# @param [:asc,:desc] direction (:asc) The direction to sort, ascending
|
211
|
+
# or descending order.
|
212
|
+
def order *args
|
213
|
+
new_scope.order(*args)
|
214
|
+
end
|
215
|
+
|
216
|
+
# The maximum number of records to return. By default, all records
|
217
|
+
# matching the where conditions will be returned from a find.
|
218
|
+
#
|
219
|
+
# People.limit(10).each {|person| ... }
|
220
|
+
#
|
221
|
+
# Limit can be chained with other scope modifiers:
|
222
|
+
#
|
223
|
+
# People.where(:age => 40).limit(10).each {|person| ... }
|
224
|
+
#
|
225
|
+
def limit limit
|
226
|
+
new_scope.limit(limit)
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
# Copyright 2011-2012 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
|
+
module AWS
|
15
|
+
module Record
|
16
|
+
class Model
|
17
|
+
|
18
|
+
# The primary interface for finding records with {AWS::Record::Model}.
|
19
|
+
#
|
20
|
+
# == Getting a Scope Object
|
21
|
+
#
|
22
|
+
# You should normally never need to construct a Scope object directly.
|
23
|
+
# Scope objects are returned from the AWS::Record::Model finder methods
|
24
|
+
# (e.g. +shard+, +where+, +order+, +limit+, etc).
|
25
|
+
#
|
26
|
+
# books = Book.where(:author => 'John Doe')
|
27
|
+
# books.class #=> AWS::Record::Scope, not Array
|
28
|
+
#
|
29
|
+
# Scopes are also returned from methods defined with the +scope+ method.
|
30
|
+
#
|
31
|
+
# == Chaining Scopes
|
32
|
+
#
|
33
|
+
# Scope objects represent a request, but do not actualy make a request
|
34
|
+
# until required. This allows you to chain requests
|
35
|
+
#
|
36
|
+
# # no request made by the following 2 statements
|
37
|
+
# books = Book.where(:author => 'John Doe')
|
38
|
+
# books = books.limit(10)
|
39
|
+
#
|
40
|
+
# books.each do |book|
|
41
|
+
# # yields up to 10 books
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# Each of the following methods returns a scope that can be chained.
|
45
|
+
#
|
46
|
+
# * {#shard}
|
47
|
+
# * {#where}
|
48
|
+
# * {#order}
|
49
|
+
# * {#limit}
|
50
|
+
#
|
51
|
+
# == Terminating Scopes
|
52
|
+
#
|
53
|
+
# To terminate a scope you can enumerate it or call #first.
|
54
|
+
#
|
55
|
+
# # terminate a scope by enumerating
|
56
|
+
# Book.limit(10).each {|book| ... }
|
57
|
+
#
|
58
|
+
# # terminate a scope by getting the first value
|
59
|
+
# Book.where('author' => 'John Doe').first
|
60
|
+
#
|
61
|
+
class Scope < Record::Scope
|
62
|
+
|
63
|
+
# @private
|
64
|
+
def initialize base_class, options = {}
|
65
|
+
super
|
66
|
+
@options[:where] ||= []
|
67
|
+
end
|
68
|
+
|
69
|
+
def new attributes = {}
|
70
|
+
|
71
|
+
attributes = attributes.dup
|
72
|
+
|
73
|
+
@options[:where].each do |conditions|
|
74
|
+
if conditions.size == 1 and conditions.first.is_a?(Hash)
|
75
|
+
attributes.merge!(conditions.first)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
super(attributes)
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
# Applies conditions to the scope that limit which records are returned.
|
84
|
+
# Only those matching all given conditions will be returned.
|
85
|
+
#
|
86
|
+
# @overload where(conditions_hash)
|
87
|
+
# Specify a hash of conditions to query with. Multiple conditions
|
88
|
+
# are joined together with AND.
|
89
|
+
#
|
90
|
+
# Book.where(:author => 'John Doe', :softcover => true)
|
91
|
+
# # where `author` = `John Doe` AND `softcover` = `1`
|
92
|
+
#
|
93
|
+
# @param [Hash] conditions
|
94
|
+
#
|
95
|
+
# @overload where(conditions_string, *values)
|
96
|
+
# A sql-like query fragment with optional placeholders and values.
|
97
|
+
# Placeholders are replaced with properly quoted values.
|
98
|
+
#
|
99
|
+
# Book.where('author = ?', 'John Doe')
|
100
|
+
#
|
101
|
+
# @param [String] conditions_string A sql-like where string with
|
102
|
+
# question mark placeholders. For each placeholder there should
|
103
|
+
# be a value that will be quoted into that position.
|
104
|
+
# @param [String] *values A value that should be quoted into the
|
105
|
+
# corresponding (by position) placeholder.
|
106
|
+
#
|
107
|
+
# @return [Scope] Returns a new scope with the passed conditions applied.
|
108
|
+
def where *conditions
|
109
|
+
if conditions.empty?
|
110
|
+
raise ArgumentError, 'missing required condition'
|
111
|
+
end
|
112
|
+
_with(:where => @options[:where] + [conditions])
|
113
|
+
end
|
114
|
+
|
115
|
+
# Specifies how to sort records returned.
|
116
|
+
#
|
117
|
+
# # enumerate books, starting with the most recently published ones
|
118
|
+
# Book.order(:published_at, :desc).each do |book|
|
119
|
+
# # ...
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# Only one order may be applied. If order is specified more than
|
123
|
+
# once the last one in the chain takes precedence:
|
124
|
+
#
|
125
|
+
#
|
126
|
+
# # books returned by this scope will be ordered by :published_at
|
127
|
+
# # and not :author.
|
128
|
+
# Book.where(:read => false).order(:author).order(:published_at)
|
129
|
+
#
|
130
|
+
# @param [String,Symbol] attribute_name The attribute to sort by.
|
131
|
+
# @param [:asc, :desc] order (:asc) The direct to sort.
|
132
|
+
def order attribute_name, order = :asc
|
133
|
+
_with(:order => [attribute_name, order])
|
134
|
+
end
|
135
|
+
|
136
|
+
# @private
|
137
|
+
private
|
138
|
+
def _each_object &block
|
139
|
+
|
140
|
+
items = _item_collection
|
141
|
+
|
142
|
+
items.select.each do |item_data|
|
143
|
+
obj = base_class.new(:shard => _shard)
|
144
|
+
obj.send(:hydrate, item_data.name, item_data.attributes)
|
145
|
+
yield(obj)
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
# Merges another scope with this scope. Conditions are added together
|
151
|
+
# and the limit and order parts replace those in this scope (if set).
|
152
|
+
# @param [Scope] scope A scope to merge with this one.
|
153
|
+
# @return [Scope] Returns a new scope with merged conditions and
|
154
|
+
# overriden order and limit.
|
155
|
+
# @private
|
156
|
+
private
|
157
|
+
def _merge_scope scope
|
158
|
+
merged = self
|
159
|
+
scope.instance_variable_get('@options').each_pair do |opt_name,opt_value|
|
160
|
+
unless [nil, []].include?(opt_value)
|
161
|
+
if opt_name == :where
|
162
|
+
opt_value.each do |condition|
|
163
|
+
merged = merged.where(*condition)
|
164
|
+
end
|
165
|
+
else
|
166
|
+
merged = merged.send(opt_name, *opt_value)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
merged
|
171
|
+
end
|
172
|
+
|
173
|
+
# Consumes a hash of options (e.g. +:where+, +:order+ and +:limit+) and
|
174
|
+
# builds them onto the current scope, returning a new one.
|
175
|
+
# @param [Hash] options
|
176
|
+
# @option options :where
|
177
|
+
# @option options :order
|
178
|
+
# @option options [Integer] :limit
|
179
|
+
# @return [Scope] Returns a new scope with the hash of scope
|
180
|
+
# options applied.
|
181
|
+
# @private
|
182
|
+
private
|
183
|
+
def _handle_options options
|
184
|
+
scope = self
|
185
|
+
options.each_pair do |method, args|
|
186
|
+
if method == :where and args.is_a?(Hash)
|
187
|
+
# splatting a hash turns it into an array, bad juju
|
188
|
+
scope = scope.send(method, args)
|
189
|
+
else
|
190
|
+
scope = scope.send(method, *args)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
scope
|
194
|
+
end
|
195
|
+
|
196
|
+
# Converts this scope object into an AWS::SimpleDB::ItemCollection
|
197
|
+
# @return [SimpleDB::ItemCollection]
|
198
|
+
# @private
|
199
|
+
private
|
200
|
+
def _item_collection
|
201
|
+
items = base_class.sdb_domain(_shard).items
|
202
|
+
items = items.order(*@options[:order]) if @options[:order]
|
203
|
+
items = items.limit(*@options[:limit]) if @options[:limit]
|
204
|
+
@options[:where].each do |where_condition|
|
205
|
+
items = items.where(*where_condition)
|
206
|
+
end
|
207
|
+
items
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
data/lib/aws/record/scope.rb
CHANGED
@@ -14,90 +14,59 @@
|
|
14
14
|
module AWS
|
15
15
|
module Record
|
16
16
|
|
17
|
-
#
|
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
|
-
#
|
17
|
+
# Base class for {AWS::Record::Model::Scope} and
|
18
|
+
# {AWS::Record::HashModel::Scope}.
|
50
19
|
class Scope
|
51
20
|
|
52
21
|
include Enumerable
|
53
22
|
|
54
|
-
# @param
|
55
|
-
# {AWS::Record::Base}.
|
23
|
+
# @param base_class A class that extends {AWS::Record::AbstractBase}.
|
56
24
|
# @param [Hash] options
|
57
25
|
# @option options :
|
58
26
|
# @private
|
59
27
|
def initialize base_class, options = {}
|
28
|
+
|
60
29
|
@base_class = base_class
|
30
|
+
|
61
31
|
@options = options.dup
|
62
|
-
|
63
|
-
|
32
|
+
|
33
|
+
# backwards compat
|
34
|
+
@options[:shard] = @options.delete(:domain) if @options[:domain]
|
35
|
+
|
64
36
|
end
|
65
37
|
|
66
|
-
# @return [Class] Returns the AWS::Record::
|
38
|
+
# @return [Class] Returns the AWS::Record::Model extending class that
|
67
39
|
# this scope will find records for.
|
68
40
|
attr_reader :base_class
|
69
41
|
|
70
42
|
def new attributes = {}
|
71
43
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
44
|
+
attributes = attributes.dup
|
45
|
+
attributes[:shard] ||= attributes.delete(:shard)
|
46
|
+
attributes[:shard] ||= attributes.delete('shard')
|
47
|
+
# for backwards compatability, domain is accepted
|
48
|
+
attributes[:shard] ||= attributes.delete('domain')
|
49
|
+
attributes[:shard] ||= attributes.delete(:domain)
|
50
|
+
attributes[:shard] ||= _shard
|
77
51
|
|
78
|
-
|
79
|
-
if conditions.size == 1 and conditions.first.is_a?(Hash)
|
80
|
-
options.merge!(conditions.first)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
base_class.new(options)
|
52
|
+
base_class.new(attributes)
|
85
53
|
|
86
54
|
end
|
87
55
|
alias_method :build, :new
|
88
56
|
|
89
|
-
# @param [String]
|
90
|
-
# @return [Scope] Returns a scope
|
91
|
-
#
|
92
|
-
def
|
93
|
-
_with(:
|
57
|
+
# @param [String] shard_name
|
58
|
+
# @return [Scope] Returns a scope that specifies which shard
|
59
|
+
# (i.e. SimpleDB domain) should be used.
|
60
|
+
def shard shard_name
|
61
|
+
_with(:shard => shard_name)
|
94
62
|
end
|
63
|
+
alias_method :domain, :shard
|
95
64
|
|
96
65
|
# @overload find(id)
|
97
66
|
# Finds and returns a single record by id. If no record is found
|
98
67
|
# with the given +id+, then a RecordNotFound error will be raised.
|
99
68
|
# @param [String] id ID of the record to find.
|
100
|
-
# @return
|
69
|
+
# @return Returns the record.
|
101
70
|
#
|
102
71
|
# @overload find(:first, options = {})
|
103
72
|
# Returns the first record found. If no records were matched then
|
@@ -125,7 +94,7 @@ module AWS
|
|
125
94
|
when id_or_mode == :all then scope
|
126
95
|
when id_or_mode == :first then scope.limit(1).to_a.first
|
127
96
|
else
|
128
|
-
base_class.find_by_id(id_or_mode, :
|
97
|
+
base_class.find_by_id(id_or_mode, :shard => scope._shard)
|
129
98
|
end
|
130
99
|
|
131
100
|
end
|
@@ -141,64 +110,11 @@ module AWS
|
|
141
110
|
end
|
142
111
|
alias_method :size, :count
|
143
112
|
|
144
|
-
# @return
|
145
|
-
#
|
113
|
+
# @return Returns the first record found, returns
|
114
|
+
# nil if the domain/table is empty.
|
146
115
|
def first options = {}
|
147
116
|
_handle_options(options).find(:first)
|
148
117
|
end
|
149
|
-
|
150
|
-
# Applies conditions to the scope that limit which records are returned.
|
151
|
-
# Only those matching all given conditions will be returned.
|
152
|
-
#
|
153
|
-
# @overload where(conditions_hash)
|
154
|
-
# Specify a hash of conditions to query with. Multiple conditions
|
155
|
-
# are joined together with AND.
|
156
|
-
#
|
157
|
-
# Book.where(:author => 'John Doe', :softcover => true)
|
158
|
-
# # where `author` = `John Doe` AND `softcover` = `1`
|
159
|
-
#
|
160
|
-
# @param [Hash] conditions
|
161
|
-
#
|
162
|
-
# @overload where(conditions_string, *values)
|
163
|
-
# A sql-like query fragment with optional placeholders and values.
|
164
|
-
# Placeholders are replaced with properly quoted values.
|
165
|
-
#
|
166
|
-
# Book.where('author = ?', 'John Doe')
|
167
|
-
#
|
168
|
-
# @param [String] conditions_string A sql-like where string with
|
169
|
-
# question mark placeholders. For each placeholder there should
|
170
|
-
# be a value that will be quoted into that position.
|
171
|
-
# @param [String] *values A value that should be quoted into the
|
172
|
-
# corresponding (by position) placeholder.
|
173
|
-
#
|
174
|
-
# @return [Scope] Returns a new scope with the passed conditions applied.
|
175
|
-
def where *conditions
|
176
|
-
if conditions.empty?
|
177
|
-
raise ArgumentError, 'missing required condition'
|
178
|
-
end
|
179
|
-
_with(:where => @options[:where] + [conditions])
|
180
|
-
end
|
181
|
-
|
182
|
-
# Specifies how to sort records returned.
|
183
|
-
#
|
184
|
-
# # enumerate books, starting with the most recently published ones
|
185
|
-
# Book.order(:published_at, :desc).each do |book|
|
186
|
-
# # ...
|
187
|
-
# end
|
188
|
-
#
|
189
|
-
# Only one order may be applied. If order is specified more than
|
190
|
-
# once the last one in the chain takes precedence:
|
191
|
-
#
|
192
|
-
#
|
193
|
-
# # books returned by this scope will be ordered by :published_at
|
194
|
-
# # and not :author.
|
195
|
-
# Book.where(:read => false).order(:author).order(:published_at)
|
196
|
-
#
|
197
|
-
# @param [String,Symbol] attribute_name The attribute to sort by.
|
198
|
-
# @param [:asc, :desc] order (:asc) The direct to sort.
|
199
|
-
def order attribute_name, order = :asc
|
200
|
-
_with(:order => [attribute_name, order])
|
201
|
-
end
|
202
118
|
|
203
119
|
# Limits the maximum number of total records to return when finding
|
204
120
|
# or counting. Returns a scope, does not make a request.
|
@@ -229,28 +145,21 @@ module AWS
|
|
229
145
|
end
|
230
146
|
|
231
147
|
protected
|
232
|
-
def
|
233
|
-
@options[:
|
148
|
+
def _shard
|
149
|
+
@options[:shard] || base_class.shard_name
|
234
150
|
end
|
151
|
+
alias_method :domain, :shard
|
235
152
|
|
236
153
|
# @private
|
237
154
|
private
|
238
155
|
def _each_object &block
|
239
|
-
|
240
|
-
items = _item_collection
|
241
|
-
|
242
|
-
items.select.each do |item_data|
|
243
|
-
obj = base_class.new(:domain => _domain)
|
244
|
-
obj.send(:hydrate, item_data.name, item_data.attributes)
|
245
|
-
yield(obj)
|
246
|
-
end
|
247
|
-
|
156
|
+
raise NotImplementedError
|
248
157
|
end
|
249
158
|
|
250
159
|
# @private
|
251
160
|
private
|
252
161
|
def _with options
|
253
|
-
|
162
|
+
self.class.new(base_class, @options.merge(options))
|
254
163
|
end
|
255
164
|
|
256
165
|
# @private
|
@@ -260,66 +169,31 @@ module AWS
|
|
260
169
|
_merge_scope(base_class.send(scope_name, *args))
|
261
170
|
end
|
262
171
|
|
263
|
-
# Merges
|
264
|
-
#
|
265
|
-
# @
|
266
|
-
# @return [Scope] Returns a new scope with merged conditions and
|
267
|
-
# overriden order and limit.
|
172
|
+
# Merges the one scope with the current scope, returning a 3rd.
|
173
|
+
# @param [Scope] scope
|
174
|
+
# @return [Scope]
|
268
175
|
# @private
|
269
176
|
private
|
270
177
|
def _merge_scope scope
|
271
|
-
|
272
|
-
scope.instance_variable_get('@options').each_pair do |opt_name,opt_value|
|
273
|
-
unless [nil, []].include?(opt_value)
|
274
|
-
if opt_name == :where
|
275
|
-
opt_value.each do |condition|
|
276
|
-
merged = merged.where(*condition)
|
277
|
-
end
|
278
|
-
else
|
279
|
-
merged = merged.send(opt_name, *opt_value)
|
280
|
-
end
|
281
|
-
end
|
282
|
-
end
|
283
|
-
merged
|
178
|
+
raise NotImplementedError
|
284
179
|
end
|
285
180
|
|
286
|
-
# Consumes a hash of options (e.g. +:
|
287
|
-
#
|
288
|
-
# @
|
289
|
-
# @option options :where
|
290
|
-
# @option options :order
|
291
|
-
# @option options [Integer] :limit
|
292
|
-
# @return [Scope] Returns a new scope with the hash of scope
|
293
|
-
# options applied.
|
181
|
+
# Consumes a hash of options (e.g. +:shard+, +:limit) and returns
|
182
|
+
# a new scope with those applied.
|
183
|
+
# @return [Scope]
|
294
184
|
# @private
|
295
185
|
private
|
296
186
|
def _handle_options options
|
297
|
-
|
298
|
-
options.each_pair do |method, args|
|
299
|
-
if method == :where and args.is_a?(Hash)
|
300
|
-
# splatting a hash turns it into an array, bad juju
|
301
|
-
scope = scope.send(method, args)
|
302
|
-
else
|
303
|
-
scope = scope.send(method, *args)
|
304
|
-
end
|
305
|
-
end
|
306
|
-
scope
|
187
|
+
raise NotImplementedError
|
307
188
|
end
|
308
189
|
|
309
|
-
# Converts this scope object into an AWS::SimpleDB::ItemCollection
|
310
|
-
# @return [SimpleDB::ItemCollection]
|
311
190
|
# @private
|
312
191
|
private
|
313
192
|
def _item_collection
|
314
|
-
|
315
|
-
items = items.order(*@options[:order]) if @options[:order]
|
316
|
-
items = items.limit(*@options[:limit]) if @options[:limit]
|
317
|
-
@options[:where].each do |where_condition|
|
318
|
-
items = items.where(*where_condition)
|
319
|
-
end
|
320
|
-
items
|
193
|
+
raise NotImplementedError
|
321
194
|
end
|
322
195
|
|
323
196
|
end
|
197
|
+
|
324
198
|
end
|
325
199
|
end
|