Specifying indeces in DataMapper

Posted by # June 2nd 01:00 PM

I’ve been working with Merb and DataMapper in the context of a new project for a week now, and the experience has been both pleasant and interesting. On one hand the stack is solid and super-fast (like, desktop app fast), on the other there are a lot of things that catch you if you don’t manage to remove the Rails hat off your head. The youth of the frameworks still shows (especially in DataMapper which has recently seen a major refactoring to make it more modular the same way Merb was reworked a bit earlier) but at the same time I get the chance to help with some really cool up-and-coming open source software. If you don’t consider that a plus, maybe you should still wait a couple months before you consider these critters for a production app.

One clear symptom of the young age of both Merb and DataMapper is the lack of documentation. They both have documentation sections on their respective websites and there are other efforts such as Merbunity going on, but you still have to have the guts to dive into the source code if you want to find out how some of the less common use cases work.

Here’s a short piece on how to declare indeces for your DataMapper models. I plan to continue publishing this kind of tutorials for other functionality as well, and to contribute them back to the “official” docs when appropriate.

The big difference

The big conceptual different between ActiveRecord and DataMapper is that in ActiveRecord, the place where the properties of database tables are defined are the migration files. The actual tables are then built according to the migrations and the actual model classes build their property to methods from the database schema.

In DataMapper, the properties are defined in the actual model file. DM has so called auto migrations that compare the model file and the database schema, and modify the schema if the two don’t match.

Here’s an example DataMapper model:

class User
  include DataMapper::Resource

  property :id,         Integer, :serial => true
  property :first_name, String
  property :last_name,  String
  property :bio,        Text
  property :single,     Boolean
end

Seems clean, doesn’t it. Looking at a model it is clear what properties it has and what methods it supports. But what about indeces? In AR migrations, you would use the create_index method. In DataMapper, index is an option given to the property method:

property :last_name,    String, :index => true

Or, if you want the index to be unique:

property :last_name,    String, :unique_index => true

OK, but what if you need multi-column composite indeces? Easy. Instead of true, give the index a name using a symbol:

property :last_name,     String, :index => :name
property :first_name,    String, :index => :name

This will create an index called index_products_name for the table, spanning columns last_name and first_name. The columns are added to the index in order of appearance, so in this case the indexing order would be last name, first name. If you want to change that order, just change the order of you property calls in the model call definition.

There you have it! No rocket surgery, but something I had to dive into the source code to find out.

Jump to comment form

Comments

  1. Dr Nic 06.02.08 / 15PM

    There’s a nice gem ‘hobofields’ that provides a similar “schema-in-your-models” approach. I like it.

  2. Sam Smoot 06.02.08 / 18PM

    DISCLAIMER: This will make an appearance in the next release. I wrote up the comment before checking to find the class-method hasn’t been ported forward. We’ll fix that. ;-)

    You mentioned the index ordering gotcha. If you have multiple composite indexes (probably most common), you might get more mileage out of the Resource::index method, which allows for something like this:

    index [:id, :last_name] index [:id, :first_name, :last_name, :bio]

    Which wouldn’t be possible with the inline property options.

  3. Jarkko 06.02.08 / 18PM

    Sam: Thanks for the note! I tried to look for such a method in the (0.9.1) source and didn’t find one, but that explains very well why :-)

  4. Jarkko 06.02.08 / 18PM

    Dr Nic: Thanks for the tip, I’ll look into that!

  5. Sebastian 06.06.08 / 00AM

    Usefull post!

  6. Mirko Froehlich 07.08.08 / 19PM

    Thank for the tip.

    Unfortunately I am using DataMapper’s custom migrations (i.e. migration runner), rather than auto migrations. Custom migrations work similar to ActiveRecord’s migrations, but they are still a bit rough around the edges and in particular don’t seem to support specifying indexes. At least I haven’t found a way to do this yet…

Have your say

A name is required. You may use Textile in your comments.




Recently

RailsConf 2007 Speaker

Beginning Ruby on Rails E-Commerce