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.
GitHub Overview
datamapper/dm-core
DataMapper - Core
Topics
Star History
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
- DataMapper GitHub Organization - Official Repository (Archived)
- ROM - Ruby Object Mapper - Successor Project
- DataMapper - Wikipedia - Project Overview
- DataMapper Tutorial - Learning Resource (Historical)
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.