class AWS::Record::Model


end
puts “#{n + 1} : #{book.title}”
ten_books.each_with_index do |book,n|
ten_books = all_books.limit(10)
all_books = Books.all
each_with_index.
In the following example no request is made until the call to
This allows you to build an expression without making unecessary requests.
to a {Scope} object that will return records when you enumerate over them.
means the value returned is not an array of records, rather a handle
It should be noted that all finds are lazy (except first). This
=== Delayed Execution
Book.limit(2)
number of records to retrieve:
Just call limit with an integer argument. This sets the maximum
=== Limit
is lost.
In this example the books will be ordered by :price and the order(:title)
Book.order(:title).order(:price)
chain, the last call gets presedence:
You may only order by a single attribute. If you call order twice in the
Book.order(:title, :desc) # reverse alphabetical ordering
Book.order(:title) # alphabetical ordering
Pass the value :desc as a second argument to sort in reverse ordering.
This orders the records as returned by AWS. Default ordering is ascending.
=== Order
Book.where(:title => ‘My Book’)
expressions that use or.
least flexible. You can not use this form if you need more complex
3. A hash of key-value pairs. This is the simplest form, but also the
Book.where(‘title = ?’, ‘My Book’)
arguments properly to avoid injection.
2. An sql-like fragment, with placeholders. This escapes quoted
Book.where(‘title = “My Book”’)
not suggested.
1. As an sql-like fragment. If you need to escape values this form is
Where accepts aruments in a number of forms:
=== Conditions (where)
* limit
* order
* where
There are 3 standard scope methods:
next_good_reads = Book.mine.unread.top_10
# to me, that are unread sorted by popularity.
# The following expression returns 10 books that belong
end
scope :top_10, by_popularity.limit(10)
scope :by_popularity, order(:score, :desc)
scope :unread, where(:has_been_read => false)
scope :mine, where(:owner => ‘Me’)
class Book < AWS::Record::Model
name your most common conditions for reuse.
More useful than writing query fragments all over the place is to
= Scopes
* :limit - The maximum number of records to return
* :order - The order to sort matched records by
* :where - Conditions that must be met to be returned
You can pass as find options:
book = Book.first(:where => { :has_been_read => false })
my_books = Book.find(:all, :where => ‘owner = “Me”’)
can pass options to find, all and first.
Frequently you do not want ALL records or the very first record. You
=== Modifiers
b = Book.first
If you only want a single record, you should use first.
=== First
causing quite a few requests.
and number of attributes each record has, this can take a while,
Be careful when enumerating all. Depending on the number of records
end
puts book.id
Book.find(:all) do |book|
end
puts book.id
Book.all.each do |book|
You can enumerate all of your records using all.
=== All
be raised.
If you try to find a record by ID that has no data an error will
b = Book.find(“0aa894ca-8223-4d34-831e-e5134b2bb71c”)
b = Book[“0aa894ca-8223-4d34-831e-e5134b2bb71c”]

at a latter time:
is saved for the first time. You can use this ID to fetch the record
You can find records by their ID. Each record gets a UUID when it
= Finder Methods
{Validations}.
For more information about the available validation methods see
adds an error, the the save will fail.
Validations are checked before saving a record. If any of the validators
b.errors.full_messages #=> [‘Title may not be blank’]
b.valid? #=> false
b = Book.new
end
validates_presence_of :title
string_attr :title
class Book < AWS::Record::Model
validators.
your data clean. AWS::Record supports most of the ActiveRecord style
It’s important to validate models before there are persisted to keep
= Validations
option with the attribute macros.
Please consider these limitations when you choose to use the :set
* duplicate values are automatically omitted
* values are unordered
means:
These multi-valued attributes are treated as sets, not arrays. This
b.tags #=> #<Set: {‘fiction’, ‘fantasy’}>
b.tags = [‘fiction’, ‘fantasy’]
b.tags #=> #<Set: {}>
b = Book.new
end
string_attr :tags, :set => true
class Book < AWS::Record::Model
AWS::Record permits storing multiple values with a single attribute.
=== Multi-Valued (Set) Attributes
Book.new.author #=> ‘Me’
end
string_attr :author, :deafult_value => ‘Me’
class Book < AWS::Record::Model
a value that is populated onto all new instnaces of the class.
All attribute macros accept the :default_value option. This sets
=== Default Values
#=> { ‘title’ => ‘My Book’, ‘has_been_read’ => true, … }
b.attributes
b.id #=> “0aa894ca-8223-4d34-831e-e5134b2bb71c”
b.save
b.published_at = Time.now
b.weight_in_pounds = 1.1
b.number_of_pages = 1000
b.has_been_read = true
b.title = “My Book”
b = Book.new
to your class (and a few other useful methods).
For each attribute macro a pair of setter/getter methods are added #
end
datetime_attr :published_at
float_attr :weight_in_pounds
integer_attr :number_of_pages
boolean_attr :has_been_read
string_attr :title
class Book < AWS::Record::Model
Normally you just call these methods inside your model class definition:
=== Usage
* date_attr
* datetime_attr
* float_attr
* integer_attr
* boolean_attr
* string_attr
attributes (and what types) you need.
models are not backed by a database table/schema. You must choose what
attributes your class should have. Unlike ActiveRecord, AWS::Record
When extending AWS::Record::Model you should first consider what
= Attribute Macros
b.save
b = Book.new(:title => ‘My Book’, :author => ‘Me’, :pages => 1)
end
timestamps # adds a :created_at and :updated_at pair of timestamps
integer_attr :number_of_pages
string_attr :author
string_attr :title
class Book < AWS::Record::Model
An ActiveRecord-like interface built ontop of Amazon SimpleDB.

def all options = {}

Returns:
  • (Scope) - Returns an enumerable scope object.
def all options = {}
  new_scope.find(:all, options)
end

def boolean_attr name, options = {}

Parameters:
  • name (Symbol) -- The name of the attribute.
def boolean_attr name, options = {}
  attr = add_attribute(Attributes::BooleanAttr.new(name, options))
  # add the boolean question mark method
  define_method("#{attr.name}?") do
    !!__send__(attr.name)
  end
end

def count(options = {})

Options Hash: (**options)
  • :limit (Integer) -- The max number of records to count.
  • :where (Mixed) -- Conditions that determine what

Parameters:
  • options (Hash) -- ({}) Options for counting
def count(options = {})
  new_scope.count(options)
end

def create_domain shard_name = nil

Returns:
  • (SimpleDB::Domain) -

Parameters:
  • shard_name (optional, String) -- Defaults to the class name.
def create_domain shard_name = nil
  sdb.domains.create(sdb_domain_name(shard_name))
end

def create_storage

def create_storage
  to_add = serialize_attributes
  sdb_item.attributes.add(to_add.merge(opt_lock_conditions))
end

def date_attr name, options = {}

Options Hash: (**options)
  • :set (Boolean) -- When true this attribute

Parameters:
  • options (Hash) --
  • name (Symbol) -- The name of the attribute.

Other tags:
    Example: A standard date attribute -
def date_attr name, options = {}
  add_attribute(Record::Attributes::DateAttr.new(name, options))
end

def datetime_attr name, options = {}

Options Hash: (**options)
  • :set (Boolean) -- When true this attribute

Parameters:
  • options (Hash) --
  • name (Symbol) -- The name of the attribute.

Other tags:
    Example: A standard datetime attribute -
def datetime_attr name, options = {}
  add_attribute(Record::Attributes::DateTimeAttr.new(name, options))
end

def delete_storage

def delete_storage
  sdb_item.delete(opt_lock_conditions)
  @_deleted = true
end

def deserialize_item_data item_data

def deserialize_item_data item_data
  marked_for_deletion = item_data['_delete_'] || []
  data = {}
  item_data.each_pair do |attr_name,values|
    attribute = self.class.attributes[attr_name]
    next unless attribute
    next if marked_for_deletion.include?(attr_name)
    if attribute.set?
      data[attr_name] = values.map{|v| attribute.deserialize(v) }
    else
      data[attr_name] = attribute.deserialize(values.first)
    end
  end
  data
end

def each &block

Yields once for each record.
def each &block
  all.each(&block)
end

def find *args

Options Hash: (**options)
  • :limit (Integer) -- The max number of records to fetch.
  • :sort (String, Array) -- The order records should be
  • :where (Mixed) -- Conditions that determine what

Parameters:
  • options (Hash) --
  • mode (:all, :first) -- (:all) When finding +:all+ matching records
  • id () -- The record to find, raises an exception if the record is

Overloads:
  • find(mode, options = {})
  • find(id)
def find *args
  new_scope.find(*args)
end

def find_by_id id, options = {}

Returns:
  • (Record::HashModel) - Returns the record with the given id.

Raises:
  • (RecordNotFound) - Raises a record not found exception if there

Options Hash: (**options)
  • :shard (String) -- Specifies what shard (i.e. domain)

Parameters:
  • options (Hash) --
  • id (String) -- The id of the record to load.
def find_by_id id, options = {}
  domain = sdb_domain(options[:shard] || options[:domain])
  data = domain.items[id].data.attributes
  raise RecordNotFound, "no data found for id: #{id}" if data.empty?
  obj = self.new(:shard => domain)
  obj.send(:hydrate, id, data)
  obj
end

def first options = {}

Returns:
  • (Object, nil) - Returns the first record found. If there were
def first options = {}
  new_scope.first(options)
end

def float_attr name, options = {}

Options Hash: (**options)
  • :set (Boolean) -- When true this attribute

Parameters:
  • options (Hash) --
  • name (Symbol) -- The name of the attribute.
def float_attr name, options = {}
  add_attribute(Attributes::FloatAttr.new(name, options))
end

def integer_attr name, options = {}

Options Hash: (**options)
  • :set (Boolean) -- When true this attribute

Parameters:
  • options (Hash) --
  • name (Symbol) -- The name of the attribute.
def integer_attr name, options = {}
  add_attribute(Attributes::IntegerAttr.new(name, options))
end

def limit limit


People.where(:age => 40).limit(10).each {|person| ... }

Limit can be chained with other scope modifiers:

People.limit(10).each {|person| ... }

matching the where conditions will be returned from a find.
The maximum number of records to return. By default, all records
def limit limit
  new_scope.limit(limit)
end

def order *args

Parameters:
  • direction (:asc, :desc) -- (:asc) The direction to sort.
  • attribute (String, Symbol) -- The attribute to sort by.

Overloads:
  • order(attribute, direction = :asc)
def order *args
  new_scope.order(*args)
end

def sdb

def sdb
  AWS::SimpleDB.new
end

def sdb_domain shard_name = nil

Other tags:
    Private: -

Returns:
  • (AWS::SimpleDB::Domain) -
def sdb_domain shard_name = nil
  sdb.domains[sdb_domain_name(shard_name)]
end

def sdb_domain

def sdb_domain
  self.class.sdb_domain(shard)
end

def sdb_domain_name shard_name = nil

def sdb_domain_name shard_name = nil
  "#{AWS::Record.domain_prefix}#{self.shard_name(shard_name)}"
end

def sdb_item

def sdb_item
  sdb_domain.items[id]
end

def shard shard_name

Returns:
  • (Scope) - Returns a scope for restricting the domain of subsequent

Parameters:
  • shard_name (String) --
def shard shard_name
  new_scope.shard(shard_name)
end

def sortable_float_attr name, options = {}

Options Hash: (**options)
  • :set (Boolean) -- When true this attribute
  • :range (Range) -- The range of numbers this attribute

Parameters:
  • options (Hash) --
  • name (Symbol) -- The name of the attribute.

Other tags:
    Note: - If you change the +:range+ after some values have been persisted
def sortable_float_attr name, options = {}
  add_attribute(Attributes::SortableFloatAttr.new(name, options))
end

def sortable_integer_attr name, options = {}

Options Hash: (**options)
  • :set (Boolean) -- When true this attribute
  • :range (Range) -- A numeric range the represents the

Parameters:
  • options (Hash) --
  • name (Symbol) -- The name of the attribute.
def sortable_integer_attr name, options = {}
  add_attribute(Attributes::SortableIntegerAttr.new(name, options))
end

def string_attr name, options = {}

Options Hash: (**options)
  • :set (Boolean) -- When true this attribute

Parameters:
  • options (Hash) --
  • name (Symbol) -- The name of the attribute.

Other tags:
    Example: A string attribute with +:set+ set to true -
    Example: A standard string attribute -
def string_attr name, options = {}
  add_attribute(Record::Attributes::StringAttr.new(name, options))
end

def timestamps


recipe.updated_at #=>
recipe.created_at #=>
recipe.save
recipe = Recipe.new

end
timestamps
class Recipe < AWS::Record::Model

@example

+:created_at+ and +:updated_at+.
A convenience method for adding the standard two datetime attributes
def timestamps
  c = datetime_attr :created_at
  u = datetime_attr :updated_at
  [c, u]
end

def update_storage

def update_storage
  to_update = {}
  to_delete = []
  # serialized_attributes will raise error if the entire record is blank
  attribute_values = serialize_attributes
  changed.each do |attr_name|
    if values = attribute_values[attr_name]
      to_update[attr_name] = values
    else
      to_delete << attr_name
    end
  end
  to_update.merge!(opt_lock_conditions)
  if to_delete.empty?
    sdb_item.attributes.replace(to_update)
  else
    sdb_item.attributes.replace(to_update.merge('_delete_' => to_delete))
    sdb_item.attributes.delete(to_delete + ['_delete_'])
  end
end

def where *args

Overloads:
  • where(sql_fragment[, quote_params, ...])
  • where(conditions_hash)

Parameters:
  • conditions_hash (Hash) -- A hash of attributes to values. Each
def where *args
  new_scope.where(*args)
end