Created
December 17, 2010 15:32
-
-
Save selman/745115 to your computer and use it in GitHub Desktop.
self referential relationship
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
require 'data_mapper' | |
DataMapper::Logger.new(STDOUT, :debug) | |
DataMapper.setup(:default, "sqlite:memory:") | |
class Person | |
class Link | |
include DataMapper::Resource | |
storage_names[:default] = 'people_links' | |
# the person who is following someone | |
belongs_to :follower, 'Person', :key => true | |
# the person who is followed by someone | |
belongs_to :followed, 'Person', :key => true | |
end | |
include DataMapper::Resource | |
property :id, Serial | |
property :name, String, :required => true | |
# If we want to know all the people that John follows, we need to look | |
# at every 'Link' where John is a :follower. Knowing these, we know all | |
# the people that are :followed by John. | |
# | |
# If we want to know all the people that follow Jane, we need to look | |
# at every 'Link' where Jane is :followed. Knowing these, we know all | |
# the people that are a :follower of Jane. | |
# | |
# This means that we need to establish two different relationships to | |
# the 'Link' model. One where the person's role is :follower and one | |
# where the person's role is to be :followed by someone. | |
# In this relationship, the person is the follower | |
has n, :links_to_followed_people, 'Person::Link', :child_key => [:follower_id] | |
# In this relationship, the person is the one followed by someone | |
has n, :links_to_followers, 'Person::Link', :child_key => [:followed_id] | |
# We can then use these two relationships to relate any person to | |
# either the people followed by the person, or to the people this | |
# person follows. | |
# Every 'Link' where John is a :follower points to a person that | |
# is :followed by John. | |
has n, :followed_people, self, | |
:through => :links_to_followed_people, # The person is a follower | |
:via => :followed | |
# Every 'Link' where Jane is :followed points to a person that | |
# is a :follower by Jane. | |
has n, :followers, self, | |
:through => :links_to_followers, # The person is followed by someone | |
:via => :follower | |
# Follow one or more other people | |
def follow(others) | |
followed_people.concat(Array(others)) | |
save | |
self | |
end | |
# Unfollow one or more other people | |
def unfollow(others) | |
links_to_followed_people.all(:followed => Array(others)).destroy! | |
reload | |
self | |
end | |
end | |
DataMapper.finalize | |
DataMapper.auto_migrate! | |
require 'minitest/autorun' | |
describe Person do | |
before do | |
@me = Person.create :name => 'me' | |
@friend = Person.create :name => 'friend' | |
@me.follow @friend | |
end | |
it "friend in my follow list" do | |
@me.followed_people.count.must_equal 1 | |
@me.followed_people.first.must_equal @friend | |
end | |
it "friend must see me as follower" do | |
@friend.followers.count.must_equal 1 | |
@friend.followers.first.must_equal @me | |
end | |
it "I have no followers" do | |
@me.followers.count.must_equal 0 | |
end | |
it "I unfollowed friend" do | |
@me.unfollow @friend | |
@me.followed_people.count.must_equal 0 | |
@friend.followers.count.must_equal 0 | |
end | |
end | |
__END__ | |
~ (0.000354) PRAGMA table_info("people_links") | |
~ (0.000027) PRAGMA table_info("people") | |
~ (0.000035) SELECT sqlite_version(*) | |
~ (0.080309) DROP TABLE IF EXISTS "people_links" | |
~ (0.000029) PRAGMA table_info("people_links") | |
~ (0.073655) CREATE TABLE "people_links" ("follower_id" INTEGER NOT NULL, "followed_id" INTEGER NOT NULL, PRIMARY KEY("follower_id", "followed_id")) | |
~ (0.074480) CREATE INDEX "index_people_links_follower" ON "people_links" ("follower_id") | |
~ (0.074465) CREATE INDEX "index_people_links_followed" ON "people_links" ("followed_id") | |
~ (0.074290) DROP TABLE IF EXISTS "people" | |
~ (0.000028) PRAGMA table_info("people") | |
~ (0.073867) CREATE TABLE "people" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "name" VARCHAR(50) NOT NULL) | |
Loaded suite dmassoc | |
Started | |
PersonSpec#test_0001_friend_in_my_follow_list: ~ (0.071468) INSERT INTO "people" ("name") VALUES ('me') | |
~ (0.090111) INSERT INTO "people" ("name") VALUES ('friend') | |
~ (0.000085) SELECT "follower_id", "followed_id" FROM "people_links" WHERE ("follower_id" = 1 AND "followed_id" = 2) ORDER BY "follower_id", "followed_id" LIMIT 1 | |
~ (0.075941) INSERT INTO "people_links" ("follower_id", "followed_id") VALUES (1, 2) | |
~ (0.000101) SELECT COUNT(*) FROM "people" INNER JOIN "people_links" ON "people"."id" = "people_links"."followed_id" INNER JOIN "people" "people_1" ON "people_links"."follower_id" = "people_1"."id" WHERE "people_links"."follower_id" = 1 | |
~ (0.000116) SELECT "people"."id", "people"."name" FROM "people" INNER JOIN "people_links" ON "people"."id" = "people_links"."followed_id" INNER JOIN "people" "people_1" ON "people_links"."follower_id" = "people_1"."id" WHERE "people_links"."follower_id" = 1 GROUP BY "people"."id", "people"."name" ORDER BY "people"."id" LIMIT 1 | |
0.25 s: . | |
PersonSpec#test_0003_i_have_no_followers: ~ (0.069603) INSERT INTO "people" ("name") VALUES ('me') | |
~ (0.073712) INSERT INTO "people" ("name") VALUES ('friend') | |
~ (0.000084) SELECT "follower_id", "followed_id" FROM "people_links" WHERE ("follower_id" = 3 AND "followed_id" = 4) ORDER BY "follower_id", "followed_id" LIMIT 1 | |
~ (0.067833) INSERT INTO "people_links" ("follower_id", "followed_id") VALUES (3, 4) | |
~ (0.000115) SELECT COUNT(*) FROM "people" INNER JOIN "people_links" ON "people"."id" = "people_links"."follower_id" INNER JOIN "people" "people_1" ON "people_links"."followed_id" = "people_1"."id" WHERE "people_links"."followed_id" = 3 | |
0.22 s: . | |
PersonSpec#test_0002_friend_must_see_me_as_follower: ~ (0.069754) INSERT INTO "people" ("name") VALUES ('me') | |
~ (0.065375) INSERT INTO "people" ("name") VALUES ('friend') | |
~ (0.000119) SELECT "follower_id", "followed_id" FROM "people_links" WHERE ("follower_id" = 5 AND "followed_id" = 6) ORDER BY "follower_id", "followed_id" LIMIT 1 | |
~ (0.076342) INSERT INTO "people_links" ("follower_id", "followed_id") VALUES (5, 6) | |
~ (0.000109) SELECT COUNT(*) FROM "people" INNER JOIN "people_links" ON "people"."id" = "people_links"."follower_id" INNER JOIN "people" "people_1" ON "people_links"."followed_id" = "people_1"."id" WHERE "people_links"."followed_id" = 6 | |
~ (0.000121) SELECT "people"."id", "people"."name" FROM "people" INNER JOIN "people_links" ON "people"."id" = "people_links"."follower_id" INNER JOIN "people" "people_1" ON "people_links"."followed_id" = "people_1"."id" WHERE "people_links"."followed_id" = 6 GROUP BY "people"."id", "people"."name" ORDER BY "people"."id" LIMIT 1 | |
0.23 s: . | |
PersonSpec#test_0004_i_unfollowed_friend: ~ (0.076265) INSERT INTO "people" ("name") VALUES ('me') | |
~ (0.073703) INSERT INTO "people" ("name") VALUES ('friend') | |
~ (0.000094) SELECT "follower_id", "followed_id" FROM "people_links" WHERE ("follower_id" = 7 AND "followed_id" = 8) ORDER BY "follower_id", "followed_id" LIMIT 1 | |
~ (0.084370) INSERT INTO "people_links" ("follower_id", "followed_id") VALUES (7, 8) | |
~ (0.081478) DELETE FROM "people_links" WHERE ("follower_id" = 7 AND "followed_id" = 8) | |
~ (0.000107) SELECT COUNT(*) FROM "people" INNER JOIN "people_links" ON "people"."id" = "people_links"."followed_id" INNER JOIN "people" "people_1" ON "people_links"."follower_id" = "people_1"."id" WHERE "people_links"."follower_id" = 7 | |
~ (0.000111) SELECT COUNT(*) FROM "people" INNER JOIN "people_links" ON "people"."id" = "people_links"."follower_id" INNER JOIN "people" "people_1" ON "people_links"."followed_id" = "people_1"."id" WHERE "people_links"."followed_id" = 8 | |
0.33 s: . | |
Finished in 1.034276 seconds. | |
4 tests, 7 assertions, 0 failures, 0 errors, 0 skips | |
Test run options: --seed 54307 --verbose |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment