DataMapper: Flexibility of mapping model attributes to table columns

Written on 10:13:00 AM by S. Potter

I know an esteemed ex-colleague of mine (even if he is an Apple zombie now - yes, becoming a fan of Apple on Facebook deserves some heckling;)) has reservations about the apparent unDRY-ness of DataMapper with migrations. I used to share his reservations before I wrote two applications using DataMapper. Neither Merb application was particularly spectacular, but both had to work with legacy database schemas. Oh the joys of crazy DBA naming conventions! Let's look at a brief example of DBA naming madness (some names were changed, but the conventions used are the same):

ordersTable:
  - uid_int: int (PK)
  - acc_id_int: int
  - amt_int: int
  - ref_code_string: varchar(64) natural key
  - desc_string: varchar(128)
  - entered_dt: datetime
  - changed_dt: datetime
In another table managed by a different group we had:
Account:
  - ID: int (PK)
  - Balance: int
  - UserID: int (FK)
  - EnteredDateTime: datetime
  - ChangedDateTime: datetime
I kid you not. Two different conventions, both relatively unreadable as Ruby attributes as they both violate popular coding conventions in some way. In ActiveRecord you would be left doing non-trivial coding to hide the ugly column names in the model and map Ruby-friendly names to the appropriate column. In DataMapper this is not so. Lending from the design pattern's primary purpose - to explicitly map model attributes to database columns to decouple the two - we can write something like the following using DM:

class Order
  include DataMapper::Resource
  set_table_name("ordersTable") #ridiculous name really, but what can you do if other older applications rely on this already?

  has(1, :account, :child_key => 'acc_id_int', :repository => repository(:accounts))
  property(:id, Integer, :serial => true, :field => 'uid')
  property(:amount, Integer, :field => 'amt_int')
  property(:reference, String, :field => 'ref_code_string', :key => true)
  property(:description, String, :field => 'desc_string')
  property(:created_at, DateTime, :field => 'entered_dt')
  property(:changed_dt, DateTime, :field => 'changed_dt')
end

class Account
  include DataMapper::Resource
  set_table_name('Account')

  property(:id, Integer, :serial => true, :field => 'ID')
  property(:balance, Integer, :field => 'Balance')
  property(:created_at, DateTime, :field => 'EnteredDateTime')
  property(:updated_at, DateTime, :field => 'ChangedDateTime')
end

This way we can write readable Ruby code with the model. Next time we can look at lazy loading: how to switch it on and off and when to use it for greater effect.

If you enjoyed this post Subscribe to our feed

No Comment

Post a Comment