module AWS::Record
AWS::Record
is an ORM built on top of AWS
services.
Constants
- Base
An ActiveRecord-like interface built ontop of Amazon
SimpleDB
.class Book < AWS::Record::Model string_attr :title string_attr :author integer_attr :number_of_pages timestamps # adds a :created_at and :updated_at pair of timestamps end b = Book.new(:title => 'My Book', :author => 'Me', :pages => 1) b.save
# Attribute Macros
When extending
AWS::Record::Model
you should first consider what attributes your class should have. Unlike ActiveRecord,AWS::Record
models are not backed by a database table/schema. You must choose what attributes (and what types) you need.-
‘string_attr`
-
‘boolean_attr`
-
‘integer_attr`
-
‘float_attr`
-
‘datetime_attr`
-
‘date_attr`
### Usage
Normally you just call these methods inside your model class definition:
class Book < AWS::Record::Model string_attr :title boolean_attr :has_been_read integer_attr :number_of_pages float_attr :weight_in_pounds datetime_attr :published_at end
For each attribute macro a pair of setter/getter methods are added # to your class (and a few other useful methods).
b = Book.new b.title = "My Book" b.has_been_read = true b.number_of_pages = 1000 b.weight_in_pounds = 1.1 b.published_at = Time.now b.save b.id #=> "0aa894ca-8223-4d34-831e-e5134b2bb71c" b.attributes #=> { 'title' => 'My Book', 'has_been_read' => true, ... }
### Default Values
All attribute macros accept the ‘:default_value` option. This sets a value that is populated onto all new instnaces of the class.
class Book < AWS::Record::Model string_attr :author, :default_value => 'Me' end Book.new.author #=> 'Me'
### Multi-Valued (Set)
Attributes
AWS::Record
permits storing multiple values with a single attribute.class Book < AWS::Record::Model string_attr :tags, :set => true end b = Book.new b.tags #=> #<Set: {}> b.tags = ['fiction', 'fantasy'] b.tags #=> #<Set: {'fiction', 'fantasy'}>
These multi-valued attributes are treated as sets, not arrays. This means:
-
values are unordered
-
duplicate values are automatically omitted
Please consider these limitations when you choose to use the ‘:set` option with the attribute macros.
It’s important to validate models before there are persisted to keep your data clean.
AWS::Record
supports most of the ActiveRecord style validators.class Book < AWS::Record::Model string_attr :title validates_presence_of :title end b = Book.new b.valid? #=> false b.errors.full_messages #=> ['Title may not be blank']
Validations
are checked before saving a record. If any of the validators adds an error, the the save will fail.For more information about the available validation methods see {Validations}.
# Finder Methods
You can find records by their ID. Each record gets a UUID when it is saved for the first time. You can use this ID to fetch the record at a latter time:
b = Book["0aa894ca-8223-4d34-831e-e5134b2bb71c"] b = Book.find("0aa894ca-8223-4d34-831e-e5134b2bb71c")
If you try to find a record by ID that has no data an error will be raised.
### All
You can enumerate all of your records using ‘all`.
Book.all.each do |book| puts book.id end Book.find(:all) do |book| puts book.id end
Be careful when enumerating all. Depending on the number of records and number of attributes each record has, this can take a while, causing quite a few requests.
### First
If you only want a single record, you should use ‘first`.
b = Book.first
### Modifiers
Frequently you do not want ALL records or the very first record. You can pass options to ‘find`, `all` and `first`.
my_books = Book.find(:all, :where => 'owner = "Me"') book = Book.first(:where => { :has_been_read => false })
You can pass as find options:
-
‘:where` - Conditions that must be met to be returned
-
‘:order` - The order to sort matched records by
-
‘:limit` - The maximum number of records to return
# Scopes
More useful than writing query fragments all over the place is to name your most common conditions for reuse.
class Book < AWS::Record::Model scope :mine, where(:owner => 'Me') scope :unread, where(:has_been_read => false) scope :by_popularity, order(:score, :desc) scope :top_10, by_popularity.limit(10) end # The following expression returns 10 books that belong # to me, that are unread sorted by popularity. next_good_reads = Book.mine.unread.top_10
There are 3 standard scope methods:
-
‘where`
-
‘order`
-
‘limit`
### Conditions (where)
Where accepts aruments in a number of forms:
-
As an sql-like fragment. If you need to escape values this form is not suggested.
Book.where('title = "My Book"')
-
An sql-like fragment, with placeholders. This escapes quoted arguments properly to avoid injection.
Book.where('title = ?', 'My Book')
-
A hash of key-value pairs. This is the simplest form, but also the least flexible. You can not use this form if you need more complex expressions that use or.
Book.where(:title => 'My Book')
### Order
This orders the records as returned by
AWS
. Default ordering is ascending. Pass the value :desc as a second argument to sort in reverse ordering.Book.order(:title) # alphabetical ordering Book.order(:title, :desc) # reverse alphabetical ordering
You may only order by a single attribute. If you call order twice in the chain, the last call gets presedence:
Book.order(:title).order(:price)
In this example the books will be ordered by :price and the order(:title) is lost.
### Limit
Just call ‘limit` with an integer argument. This sets the maximum number of records to retrieve:
Book.limit(2)
### Delayed Execution
It should be noted that all finds are lazy (except ‘first`). This means the value returned is not an array of records, rather a handle to a {Scope} object that will return records when you enumerate over them.
This allows you to build an expression without making unecessary requests. In the following example no request is made until the call to each_with_index.
all_books = Books.all ten_books = all_books.limit(10) ten_books.each_with_index do |book,n| puts "#{n + 1} : #{book.title}" end
-
Public Class Methods
A utility method for casting values into an array.
-
nil is returned as an empty array, []
-
Arrays are returned unmodified
-
Everything else is returned as the sole element of an array
@param [Object] value @return [Array] The value cast into an array @api private
# File lib/aws/record.rb, line 114 def self.as_array value case value when nil then [] when Set then value.to_a when Array then value else [value] end end
A utility method for casting values into
-
Sets are returned unmodified
-
everything else is passed through #{as_array} and then into a new Set
@param [Object] value @return [Set] The value cast into a Set. @api private
# File lib/aws/record.rb, line 131 def self.as_set value case value when Set then value else Set.new(as_array(value)) end end
@return [String,nil] The string that is prepended to all domain names.
# File lib/aws/record.rb, line 74 def self.domain_prefix @domain_prefix end
Sets a prefix to be applied to all SimpleDB
domains associated with AWS::Record::Base
classes.
AWS::Record.domain_prefix = 'production_' class Product < AWS::Record::Base set_shard_name 'products' end p = Product.new p.shard #=> 'products' p.save # the product is persisted to the 'production-products' domain
@param [String] prefix A prefix to append to all domains. This is useful
for grouping domains used by one application with a single prefix.
# File lib/aws/record.rb, line 69 def self.domain_prefix= prefix @domain_prefix = prefix end
@return [String,nil] The string that is prepended to all table names.
# File lib/aws/record.rb, line 101 def self.table_prefix @table_prefix end
Sets a prefix to be applied to all DynamoDB
tables associated with {AWS::Record::HashModel} and {AWS::Record::ListModel} classes.
AWS::Record.table_prefix = 'production_' class Product < AWS::Record::HashModel set_shard_name 'products' end p = Product.new p.shard #=> 'products' p.save # the product is persisted to the 'production-products' table
@param [String] prefix A prefix to append to all tables. This is
useful for grouping tables used by one application with a single prefix.
# File lib/aws/record.rb, line 96 def self.table_prefix= prefix @table_prefix = prefix end