DataMapper

DataMapper was developed as "a unified Ruby interface for data stores," providing a unified API for multiple data stores as an ORM library. It supported not only MySQL, PostgreSQL, and SQLite but also diverse data stores such as Facebook (via FQL), Salesforce API, and Amazon S3, featuring simple and intuitive query syntax. However, the project has been discontinued and migration to its successor project, Ruby Object Mapper (ROM), is recommended.

ORMRubyPatternUnified InterfaceData StoreDiscontinued Project

GitHub Overview

datamapper/dm-core

DataMapper - Core

Stars751
Watchers26
Forks153
Created:January 26, 2009
Language:Ruby
License:MIT License

Topics

None

Star History

datamapper/dm-core Star History
Data as of: 7/17/2025, 10:32 AM

Library

DataMapper

Overview

DataMapper was developed as "a unified Ruby interface for data stores," providing a unified API for multiple data stores as an ORM library. It supported not only MySQL, PostgreSQL, and SQLite but also diverse data stores such as Facebook (via FQL), Salesforce API, and Amazon S3, featuring simple and intuitive query syntax. However, the project has been discontinued and migration to its successor project, Ruby Object Mapper (ROM), is recommended.

Details

DataMapper project ended in 2013, with the development team focusing on Ruby Object Mapper (ROM). Unlike ActiveRecord, it adopted the Data Mapper pattern, separating domain models from database concerns. It implemented many innovative features such as automatic resolution of N+1 query problems, strategic lazy loading, and support for advanced query operators (gt, gte, not, etc.). However, due to maintenance burden and community fragmentation, the project was discontinued.

Key Features (Historical)

  • Unified Data Store Interface: Unified access to MySQL, NoSQL, APIs, etc.
  • Simple Query Syntax: Intuitive notation like Zoo.all(:name => 'Dallas')
  • Automatic Strategic Lazy Loading: Automatic resolution of N+1 query problems
  • Advanced Query Operators: Rich comparison operators like gt, gte, like, not
  • Performance Optimization: Default exclusion of text fields
  • Migration Features: Flexible schema management with auto_migrate! and auto_upgrade!

Pros and Cons

Pros (Historical)

  • High portability through unified API for multiple data stores
  • More intuitive and readable query syntax than ActiveRecord
  • Excellent performance through automatic resolution of N+1 query problems
  • Separation of domain logic and data access through Data Mapper pattern
  • Broad data store support with over 30 database adapters
  • Memory usage optimization through strategic lazy loading

Cons

  • Project Discontinued: Maintenance stopped since 2013
  • Security Risks: Latest vulnerability responses not implemented
  • Dependency Issues: Compatibility problems with old Ruby versions and other gems
  • Lack of Community Support: Official support and documentation updates stopped
  • Outdated Learning Resources: No guarantee of operation in latest Ruby environments
  • Migration Necessity: Migration to ROM, Sequel, ActiveRecord, etc. required

Reference Pages

Code Examples

Historical Code Examples (Currently Deprecated)

# DataMapper basic setup (before 2013)
gem install data_mapper
gem install dm-mysql-adapter

require 'data_mapper'

# Database connection configuration
DataMapper.setup(:default, 'mysql://username:password@localhost/database')

# Model definition
class User
  include DataMapper::Resource
  
  property :id, Serial
  property :name, String
  property :email, String
  property :created_at, DateTime
  
  has n, :posts
end

class Post
  include DataMapper::Resource
  
  property :id, Serial
  property :title, String
  property :content, Text
  property :created_at, DateTime
  
  belongs_to :user
end

# Database schema creation
DataMapper.finalize
DataMapper.auto_migrate!  # Delete all data
# or
DataMapper.auto_upgrade!  # Preserve existing data

Model Definition and Basic Operations (Historical)

# Basic CRUD operations
# Create
user = User.new(:name => "John Doe", :email => "[email protected]")
user.save

# or
user = User.create(:name => "John Doe", :email => "[email protected]")

# Read
users = User.all
user = User.first
user = User.get(1)  # Get by ID

# Update
user = User.get(1)
user.name = "Jane Doe"
user.save

# Delete
user = User.get(1)
user.destroy

Advanced Query Operations (Historical)

# Simple query syntax
users = User.all(:name => "John Doe")
users = User.all(:age.gt => 20)  # Greater than 20
users = User.all(:age.gte => 20) # Greater than or equal to 20
users = User.all(:age.between => 18..30) # Between 18 and 30
users = User.all(:name.like => "%John%") # Name contains "John"
users = User.all(:name.not => "John Doe") # Not "John Doe"

# Compound conditions
users = User.all(
  :age.gt => 18,
  :name.like => "%John%",
  :order => [:name.desc]
)

# Pagination
users = User.all(:limit => 10, :offset => 20)

# Count
count = User.count(:age.gt => 20)

Relation Operations (Historical)

# Retrieve related data (automatic lazy loading)
user = User.first
posts = user.posts  # Automatically resolves N+1 problem

# Create related data
user = User.create(:name => "John Doe")
post = user.posts.create(:title => "First Post", :content => "Hello World")

# Search including related data
posts = Post.all(:user => {:name => "John Doe"})

# JOIN operations
posts = Post.all.joins(:user).where(:user => {:age.gt => 20})

Practical Examples (Historical)

# Transaction processing
DataMapper.repository do |repository|
  transaction = DataMapper::Transaction.new(repository)
  
  transaction.within do |trans|
    user = User.create(:name => "John Doe")
    post = Post.create(:title => "Test", :user => user)
    
    # Automatically rollback if error occurs
    raise "Error" if some_condition
  end
end

# Validation
class User
  include DataMapper::Resource
  
  property :id, Serial
  property :name, String, :required => true, :length => 3..50
  property :email, String, :required => true, :unique => true, :format => :email_address
  property :age, Integer, :min => 0, :max => 150
  
  validates_presence_of :name
  validates_uniqueness_of :email
  validates_format_of :email, :with => :email_address
end

# Multiple database support
DataMapper.setup(:default, 'mysql://localhost/main_db')
DataMapper.setup(:logging, 'sqlite::memory:')

class User
  include DataMapper::Resource
  
  repository(:default) do
    property :id, Serial
    property :name, String
  end
end

class LogEntry
  include DataMapper::Resource
  
  repository(:logging) do
    property :id, Serial
    property :message, Text
  end
end

Note: The above code examples are provided for historical reference. The DataMapper project has been discontinued and its use in new projects is not recommended. For current Ruby development, consider using ROM, Sequel, or ActiveRecord.