NewToy (now Zynga with Friends) the folks that brought you the wildly popular mobile game Words With Friends, also have served up some open source code for your enjoyment. John Nunemaker and Geoffrey Dagley have created Toy Store, an ORM that promises to let you completely change your data store in a couple lines of code.
Toy Store features include:
- Attributes – attribute :name, String (or some other type) Can be virtual which works just like attr_accessor but all the power of dirty tracking, serialization, etc. Also, can be abbreviated which means :first_name could be the method you use, but in the data store the attribute is :fn. Save those bytes! Allows for default values and defaults can be procs.
- Typecasting – Same type system as MongoMapper. One day they will share the exact same type system in its own gem, for now duplicated.
- Callbacks – all the usual suspects.
- Dirty Tracking – save, create, update, destroy
- Mass assignment security – attr_accessible and attr_protected
- Proper cloning
- Lists – arrays of ids. If user has many games, user would have list :games which stores in game_ids key on user and works just like an association.
- Embedded Lists – array of hashes. More consistent than MongoMapper, which will soon reap the benefits of the work on Toy Store embedded lists.
- References – think belongs_to by a different (better?) name. Post model could reference :creator, User to add creator_id key and relate creator to post.
- Identity Map – On by default. Should be thread-safe.
- Read/write through caching – If you specific a cache adapter (say memcached), ToyStore will write to memcached first and read from memcached first, populating the cache if it was not present.
- Indexing – Need to do lookups by email? index :email and whenever a user is saved the user data is written to one key and the email is written as another key with a value of the user id.
- Serialization (XML and JSON)
- Primary key factories
John has created adapters for Riak, memcached, Redis, and Cassandra. If you need support for another store, you can build your own adapter by implementing just four methods for
Adapter.define(:memory) do def read(key) decode(client[key_for(key)]) end def write(key, value) client[key_for(key)] = encode(value) end def delete(key) client.delete(key_for(key)) end def clear client.clear end end