Created
March 10, 2009 18:35
-
-
Save kusor/77052 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'rubygems' | |
gem 'dm-core', '>=0.9.10' | |
require 'dm-core' | |
DataMapper::Logger.new(STDOUT, :debug) | |
DataMapper.setup(:default, 'sqlite3::memory:') | |
module Foo | |
class Comment | |
include DataMapper::Resource | |
property :id, Integer, :serial => true | |
# So, we can deal with ActiveRecord polymorphic tables from DataMapper without too many headaches: | |
property :commentable_type, String, :default => lambda { |r,p| p.model.to_s.gsub(/Comment/, '') } | |
property :commentable_id, Integer | |
property :text, Text | |
end | |
class Note | |
include DataMapper::Resource | |
property :id, Integer, :serial => true | |
property :title, String | |
has n, :comments, :class_name => 'NoteComment', :child_key => [:commentable_id], :conditions => {:commentable_type => 'Note'} | |
end | |
class Post | |
include DataMapper::Resource | |
property :id, Integer, :serial => true | |
property :title, String | |
has n, :comments, :class_name => 'PostComment', :child_key => [:commentable_id], :conditions => {:commentable_type => 'Post'} | |
end | |
class PostComment < Comment | |
belongs_to :post, :child_key => [:commentable_id] | |
end | |
class NoteComment < Comment | |
belongs_to :note, :child_key => [:commentable_id] | |
end | |
end | |
Foo::Comment.auto_migrate! | |
Foo::Post.auto_migrate! | |
Foo::Note.auto_migrate! | |
# 1) Create Post | |
post = Foo::Post.create(:title => 'My first blog post!') | |
# 2) Create Note | |
note = Foo::Note.create(:title => 'My first notebook note!') | |
# (1) & (2) Same id | |
# 3) Create Post's comment (Post.comments.create) | |
post.comments.create(:text => 'Click here for cheap viagra') | |
# 4) Create Note's comments (Note.comments.create) | |
note.comments.create(:text => 'Click here for even more cheap viagra') | |
1.upto(5) do |i| | |
post.comments.create(:text => "Click here for cheap viagra #{i}") | |
end | |
post_comments = post.comments.size | |
post.comments.each do |comment| | |
raise TypeError unless comment.post == post | |
end | |
post.reload | |
raise StandardError, "Expected #{post_comments} post comments, got #{post.comments.size}" unless post_comments == post.comments.size | |
post.comments.each do |comment| | |
puts "Comment #{comment.text} (#{comment.id})" | |
end | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'rubygems' | |
gem 'dm-core', '>=0.9.10' | |
require 'dm-core' | |
DataMapper::Logger.new(STDOUT, :debug) | |
DataMapper.setup(:default, 'sqlite3::memory:') | |
class Comment | |
include DataMapper::Resource | |
property :id, Integer, :serial => true | |
# So, we can deal with ActiveRecord polymorphic tables from DataMapper without too many headaches: | |
property :commentable_type, String, :default => lambda { |r,p| p.model.to_s.gsub(/Comment/, '') } | |
property :commentable_id, Integer | |
property :text, Text | |
end | |
class Note | |
include DataMapper::Resource | |
property :id, Integer, :serial => true | |
property :title, String | |
has n, :comments, :class_name => 'NoteComment', :child_key => [:commentable_id], :conditions => {:commentable_type => 'Note'} | |
end | |
class Post | |
include DataMapper::Resource | |
property :id, Integer, :serial => true | |
property :title, String | |
has n, :comments, :class_name => 'PostComment', :child_key => [:commentable_id], :conditions => {:commentable_type => 'Post'} | |
end | |
class PostComment < Comment | |
belongs_to :post, :child_key => [:commentable_id] | |
end | |
class NoteComment < Comment | |
belongs_to :note, :child_key => [:commentable_id] | |
end | |
Comment.auto_migrate! | |
Post.auto_migrate! | |
Note.auto_migrate! | |
# 1) Create Post | |
post = Post.create(:title => 'My first blog post!') | |
# 2) Create Note | |
note = Note.create(:title => 'My first notebook note!') | |
# (1) & (2) Same id | |
# 3) Create Post's comment (Post.comments.create) | |
post.comments.create(:text => 'Click here for cheap viagra') | |
# 4) Create Note's comments (Note.comments.create) | |
note.comments.create(:text => 'Click here for even more cheap viagra') | |
1.upto(5) do |i| | |
post.comments.create(:text => "Click here for cheap viagra #{i}") | |
end | |
post_comments = post.comments.size | |
post.comments.each do |comment| | |
raise TypeError unless comment.post == post | |
end | |
post.reload | |
raise StandardError, "Expected #{post_comments} post comments, got #{post.comments.size}" unless post_comments == post.comments.size | |
post.comments.each do |comment| | |
puts "Comment #{comment.text} (#{comment.id})" | |
end | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
DROP TABLE IF EXISTS "comments" | |
PRAGMA table_info('comments') | |
SELECT sqlite_version(*) | |
CREATE TABLE "comments" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "commentable_type" VARCHAR(50), "commentable_id" INTEGER, "text" TEXT) | |
DROP TABLE IF EXISTS "posts" | |
PRAGMA table_info('posts') | |
CREATE TABLE "posts" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "title" VARCHAR(50)) | |
DROP TABLE IF EXISTS "notes" | |
PRAGMA table_info('notes') | |
CREATE TABLE "notes" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "title" VARCHAR(50)) | |
INSERT INTO "posts" ("title") VALUES ('My first blog post!') | |
INSERT INTO "notes" ("title") VALUES ('My first notebook note!') | |
SELECT "id", "commentable_type", "commentable_id" FROM "comments" WHERE ("commentable_id" IN (1)) AND ("commentable_type" = 'Post') ORDER BY "id" | |
INSERT INTO "comments" ("commentable_type", "text", "commentable_id") VALUES ('Post', 'Click here for cheap viagra', 1) | |
SELECT "id", "commentable_type", "commentable_id" FROM "comments" WHERE ("commentable_id" IN (1)) AND ("commentable_type" = 'Note') ORDER BY "id" | |
INSERT INTO "comments" ("commentable_id", "commentable_type", "text") VALUES (1, 'Note', 'Click here for even more cheap viagra') | |
INSERT INTO "comments" ("commentable_type", "text", "commentable_id") VALUES ('Post', 'Click here for cheap viagra 1', 1) | |
INSERT INTO "comments" ("commentable_type", "text", "commentable_id") VALUES ('Post', 'Click here for cheap viagra 2', 1) | |
INSERT INTO "comments" ("commentable_type", "text", "commentable_id") VALUES ('Post', 'Click here for cheap viagra 3', 1) | |
INSERT INTO "comments" ("commentable_type", "text", "commentable_id") VALUES ('Post', 'Click here for cheap viagra 4', 1) | |
INSERT INTO "comments" ("commentable_type", "text", "commentable_id") VALUES ('Post', 'Click here for cheap viagra 5', 1) | |
SELECT "id", "title" FROM "posts" WHERE ("id" IN (1)) ORDER BY "id" | |
SELECT "id", "title" FROM "posts" WHERE ("id" IN (1)) ORDER BY "id" | |
SELECT "id", "title" FROM "posts" WHERE ("id" IN (1)) ORDER BY "id" | |
SELECT "id", "title" FROM "posts" WHERE ("id" IN (1)) ORDER BY "id" | |
SELECT "id", "title" FROM "posts" WHERE ("id" IN (1)) ORDER BY "id" | |
SELECT "id", "title" FROM "posts" WHERE ("id" IN (1)) ORDER BY "id" | |
SELECT "id", "title" FROM "posts" WHERE ("id" = 1) ORDER BY "id" | |
SELECT "id", "commentable_type", "commentable_id" FROM "comments" WHERE ("commentable_id" IN (1)) AND ("commentable_type" = 'Post') ORDER BY "id" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/ruby | |
require 'rubygems' | |
gem 'dm-core', '>=0.9.10' | |
require 'dm-core' | |
module DataMapper | |
module Is | |
module ExPolymorphic | |
def self.included(base) | |
end | |
## | |
# Model method to allow data manipulation from ActiveRecord polymorphic | |
# associations tables. | |
# | |
# The only goal of this module is not to implement Polymorphism for | |
# DataMapper, but to allow proper data CRUD from schemas defined for | |
# ActiveRecord polymorphic associations. | |
# | |
# It will define the properties "#{polymorphism_name}_type" and | |
# "#{polymorphism_name}_id" for the Model. | |
# | |
# @example [Usage] | |
# is :ex_polymorphic, :polymorphism_name => :polymorphic_able | |
# | |
# @param options <Hash>. Only supported and required option is | |
# :polymorphism_name => :polymorphic_able | |
# for example: | |
# | |
# class Comment | |
# is :ex_polymorphic, :polymorphism_name => :commentable | |
# end | |
# | |
# will create the properties: | |
# property :commentable_type, String, :default => lambda { |r,p| p.model.to_s.gsub(/Comment/, '') } | |
# property :commentable_id, Integer | |
# | |
def is_ex_polymorphic(options = {}) | |
raise ArgumentError, "Is::ExPolymorphic requires ':polymorphism_name' option definition" unless options.has_key?(:polymorphism_name) && !options[:polymorphism_name].nil? | |
polymorphism_name = options.delete(:polymorphism_name) | |
polymorphism_name = polymorphism_name.id2name unless polymorphism_name.kind_of?(String) | |
extend DataMapper::Is::ExPolymorphic::ClassMethods | |
include DataMapper::Is::ExPolymorphic::InstanceMethods | |
property "#{polymorphism_name}_type".to_sym, String, :default => lambda { |r,p| p.model.to_s.gsub(%r{self.to_s}, '') } | |
property "#{polymorphism_name}_id".to_sym, Integer | |
end | |
module ClassMethods | |
end | |
module InstanceMethods | |
end | |
end # ExPolymorphic | |
end # Is | |
module Associations | |
alias_method :has_without_ex_polymorphism, :has | |
# Adds the option to specific old polymorphic associations to "has" method: | |
# | |
# @example [Usage] | |
# has n, :comments, :was_polymorphic => :commentable, :class_name => 'Comment' | |
# | |
# @todo: inflect the value of :class_name from the association name and cardinality | |
# | |
def has(cardinality, name, opts = {}) | |
if polymorphism_name = opts.delete(:was_polymorphic) | |
polymorphism_name = polymorphism_name.id2name unless polymorphism_name.kind_of?(String) | |
cl_name = opts.delete(:class_name) | |
polymorphic_opts = { | |
:class_name => "#{self.to_s}#{cl_name}", | |
:child_key => ["#{polymorphism_name}_id".to_sym], | |
:conditions => {"#{polymorphism_name}_type".to_sym => self.to_s} | |
} | |
opts.merge!(polymorphic_opts) | |
end | |
has_without_ex_polymorphism(cardinality, name, opts) | |
# Define the required new class: | |
# (Should try to get the class module and define there) | |
Kernel.module_eval <<-EOS, __FILE__, __LINE__ | |
class ::#{self.to_s}#{cl_name} < ::#{cl_name} | |
belongs_to :#{Extlib::Inflection.singularize(self.to_s.downcase)}, :child_key => [:#{polymorphism_name}_id] | |
end | |
EOS | |
end | |
end # Associations | |
end # DataMapper | |
DataMapper::Model.append_extensions DataMapper::Is::ExPolymorphic | |
DataMapper::Logger.new(STDOUT, :debug) | |
DataMapper.setup(:default, 'sqlite3::memory:') | |
# (1) Auto create the polymorphism related stuff for Comment | |
# (2) Auto append the has n, :comments stuff for "Commentables" | |
# (3) Auto define the "CommentableComment" classes | |
class Comment | |
include DataMapper::Resource | |
property :id, Integer, :serial => true | |
property :text, Text | |
is :ex_polymorphic, :polymorphism_name => :commentable | |
end | |
class Note | |
include DataMapper::Resource | |
property :id, Integer, :serial => true | |
property :title, String | |
has n, :comments, :was_polymorphic => :commentable, :class_name => 'Comment' | |
end | |
class Post | |
include DataMapper::Resource | |
property :id, Integer, :serial => true | |
property :title, String | |
has n, :comments, :was_polymorphic => :commentable, :class_name => 'Comment' | |
end | |
Comment.auto_migrate! | |
Post.auto_migrate! | |
Note.auto_migrate! | |
# 1) Create Post | |
post = Post.create(:title => 'My first blog post!') | |
# 2) Create Note | |
note = Note.create(:title => 'My first notebook note!') | |
# (1) & (2) Same id | |
# 3) Create Post's comment (Post.comments.create) | |
post.comments.create(:text => 'Click here for cheap viagra') | |
# 4) Create Note's comments (Note.comments.create) | |
note.comments.create(:text => 'Click here for even more cheap viagra') | |
1.upto(5) do |i| | |
post.comments.create(:text => "Click here for cheap viagra #{i}") | |
end | |
post_comments = post.comments.size | |
post.comments.each do |comment| | |
raise TypeError unless comment.post == post | |
end | |
post.reload | |
raise StandardError, "Expected #{post_comments} post comments, got #{post.comments.size}" unless post_comments == post.comments.size | |
post.comments.each do |comment| | |
puts "Comment #{comment.text} (#{comment.id})" | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment