Skip to content

Instantly share code, notes, and snippets.

@kusor
Created March 10, 2009 18:35
Show Gist options
  • Save kusor/77052 to your computer and use it in GitHub Desktop.
Save kusor/77052 to your computer and use it in GitHub Desktop.
#!/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
#!/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
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"
#!/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