Jamie Gaskins

Ruby/Rails developer, coffee addict

Perpetuity 1.0.0.beta Released

Published Dec 15, 2013

After what feels like way too long, I've finally released a 1.0 beta of Perpetuity. For those unfamiliar, Perpetuity is an implementation of the Data Mapper pattern in Ruby (and, from what I can tell, it was the first one in Ruby). If you're used to ActiveRecord, it may feel a little awkward at first because suddenly your objects stand on their own, but this actually gives you a significant amount of freedom in how you structure your objects.

What makes Perpetuity awesome?

Because I love lists…

  • Your objects are whatever you want rather than forced subclasses of a library base class.
  • The query syntax is very similar to Ruby's Enumerable module
  • Persisting entire object graphs is a one-liner for new objects (great for seed/test data)

Objects can be whatever you want

With most ORMs, your persisted objects are required to be subclasses of some library base class. Some ORMs do this the least evil way and let you include the persistence behavior as a mixin, but that's still imposing.

Perpetuity allows your objects to be POROs (plain-old Ruby objects) or you can use gems like Virtus to give them a bit of a friendlier feel. As long as they save state in instance variables, Perpetuity can stick them into your database in a queryable form.

Query syntax

I get tired of writing Rubified SQL. I like to think of database tables/collections as arrays on disk, and we query arrays in Ruby using the select method and passing a block:

array.select { |object| object.name == 'foo' }

With Perpetuity, we query a database with the exact same syntax.

Perpetuity[Foo].select { |foo| foo.name == 'foo' }

The database adapter transforms this into its own query format:

/* PostgreSQL */
SELECT * FROM "Foo" WHERE name = 'foo'
// MongoDB
db.Foo.find({"name":"foo"})

You can find more information on queries in the project README.

Persisting entire object graphs

If you're creating a new set of objects, such as seed data, test data, or just a complex graph that gets created when a new user registers (we've all seen Rails apps with a dozen after_create hooks on the User model), you can persist them all by inserting the top-level parent object. It will automatically persist all of its attributes if necessary.

Install Perpetuity

If you'd like to try out Perpetuity in an application, simply add one of the database adapters to your Gemfile:

gem 'perpetuity-postgres'
gem 'perpetuity-mongodb', '1.0.0.beta'

Configuration can also be a one-liner:

Perpetuity.data_source :postgres, 'my_pg_db'

For a more robust configuration:

Perpetuity.data_source :postgres, 'my_pg_db', host: 'localhost',
                                              port: 5432,
                                              username: 'spiderman',
                                              password: 'nobodyknowsimpeterparker',
                                              pool_size: 20

This would go in a Rails initializer or a file required by your application on startup.

As of this writing, the Postgres adapter, the one most people have been waiting for, does implement most of Perpetuity's CRUD features but is missing indexing and a few of the niceties. The MongoDB driver fully implements all of Perpetuity's current features, though. To configure it, put :mongodb in place of :postgres in the config line above.

You can find a lot more information on usage in the Perpetuity project readme. If you find any problems with Perpetuity or either of the database adapters, please let me know via the issue tracker or a tweet (preferably with a gist showing how to reproduce).

TwitterGithubRss