Skip to content

remotezygote/RedisObject

Repository files navigation

RedisObject

RedisObject is a fast and simple-to-use object persistence layer for Ruby.

Gem Version Build Status

Prerequisites

You'll need Redis. Other storage adapters are in the works. Maybe.

Installation

gem install redis_object

Or, you can add it to your Gemfile:

gem 'redis_object'

Usage

Simple Example

class Thing < RedisObject
  def name
    "#{first_name} #{last_name}"
  end
  def name=(new_name)
    first, last = new_name.split(" ")
    set(:first_name,first)
    set(:last_name,last)
  end
end
a = Thing.create("an_id")
a.name = "Testy Testerton"
b = Thing.create({:first_name => "Testy", :last_name => "Testerton"})

Config

You can configure the storage adapter by sending a packet of commands to configure_store like:

RedisObject.configure_store({:db: 2})

The default storage adapter is Redis. The above config will connect to Redis on localhost on the default port (6379), but will select database number 2.

Or, you can configure multiple stores to use within an app by passing a second parameter to name the store (default is 'general')

RedisObject.configure_store({adapter: "Redis", :db: 4, :path: "/var/run/redis.sock"}, :message_queue)

class Message < RedisObject
  use_store :message_queue
end

'Collections'

Object relationships are stored in collections of objects attached to other objects. To 'collect' an object onto another, you simply call reference to reference the objects (also aliased to the concat operator <<).

Collections are automatically created, and can be access by their plural, lower-case name to gather all of the items in a collection (returns an Enumerable Collection object), or by its singular lower-case name to just get one somewhat randomly (useful for 1 -> 1 style relationships).

Example:

class Person < RedisObject; end
class Address < RedisObject; end
john = Person.create("john")
john << Address.create({
  :street => "123 Main St.",
  :city => "San Francisco",
  :state => "CA",
  :zip => "12345"
})

john.addresses
# ["Address:john"]
john.address 
# {
#   :address_id => "john",
#   :street => "123 Main St.",
#   :city => "San Francisco",
#   :state => "CA",
#   :zip => "12345",
#   :class=>"Address",
#   :key=>"Address:john",
#   :created_at=>Wed, 12 Dec 2012 16:49:26 -0800,
#   :updated_at=>Wed, 12 Dec 2012 16:49:26 -0800
# }

You may notice that the type of object, its basic storage key, and some timestamps are automatically created and updated appropriately.

It is important to note that collections inherit any indices of its underlying object type. See Indices below for examples.

Types

A few types of data can be specified for certain fields. The types supported are:

  • Date
  • Number
  • Float
  • Bool
  • Array
  • JSON (store any data that can be JSON-encoded - it will be automatically encoded/decoded when stored/accessed)

These types are also used for scoring when keeping field indices. If no type is specified, String is used, and no scoring is possible at this time.

Setting the type of a field is super easy:

class Person < RedisObject
  bool :verified
  json :meta
end

john = Person.create("john")
john.meta = {:external_id => "123456", :number => 123}
john.verified # false

TODO: Add verified? and verified! -style methods automagically for boolean fields.

You can add your own custom types by defining filter methods for getting and setting a field, and can define a scoring function if you would like to index fields of your type.

Example:

class Person < RedisObject

  def format_boolean(val)
    val=="true"
  end

  def save_boolean(val)
    val ? "true" : "false"
  end

  def score_boolean(val)
    val ? 1 : 0
  end

  class << self
    def bool(k)
      field_formats[k] = :format_boolean
      save_formats[k] = :save_boolean
      score_formats[k] = :score_boolean
    end
    alias_method :boolean, :bool

  end

end

TODO: Make defining custom formats easier - no need to define class methods for this - could have helper function for it like custom_format :bool, :get => :format_boolean or similar.

Indices

Any field that can be scored can store a sidecar index by that score. These indices can be used to index items in a collection (internally, it is a simple Redis set intersection, so it is very fast). Timestamps are indexed by default for any object, so out of the box you can do:

Person.indexed(:created_at) # all Person objects, oldest first
Person.indexed(:created_at, 1, true) # newest Person (index_field, number of items, reverse sort?)
Person.latest # always available if timestamps are on - most recently created object of type
john.addresses.indexed(:created_at, 3, true) # john's 3 most recent addresses
Person.indexed(:updated_at, -1, true) do |person|
  # iterate through Person objects in order of update times, most recent first
end

Accessing indexed items always returns an Enumerator, so first/last/each/count/etc. are usable anywhere and will access objects only when iterated.

Named Views

TODO: Add some damn View documentation.

Links

Redis: http://redis.io
RedisObject Code: https://github.com/remotezygote/RedisObject

About

Redis-mapped object persistence

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages