fixed tests, implemented sql based partitioning for favorites

This commit is contained in:
albert
2011-07-16 20:16:34 -04:00
parent fc9755b748
commit 469ae14805
10 changed files with 1291 additions and 4555 deletions

View File

@@ -4,7 +4,7 @@ module PostSets
def initialize(user_id, page = 1) def initialize(user_id, page = 1)
@user = ::User.find(user_id) @user = ::User.find(user_id)
@favorites = ::Favorite.model_for(user.id).for_user(user.id).paginate(page) @favorites = ::Favorite.for_user(user.id).paginate(page)
end end
def tag_array def tag_array
@@ -16,7 +16,7 @@ module PostSets
end end
def posts def posts
favorites.map(&:post) favorites.order("favorites.id desc").includes(:post).map(&:post)
end end
def presenter def presenter

View File

@@ -1,22 +1,4 @@
class Favorite < ActiveRecord::Base class Favorite < ActiveRecord::Base
TABLE_COUNT = 100
belongs_to :post belongs_to :post
scope :for_user, lambda {|user_id| where("user_id = ?", user_id)} scope :for_user, lambda {|user_id| where("user_id = ?", user_id)}
def self.model_for(user_id)
mod = user_id.to_i % TABLE_COUNT
Object.const_get("Favorite#{mod}")
end
def self.delete_post(post_id)
0.upto(TABLE_COUNT - 1) do |i|
model_for(i).destroy_all(:post_id => post_id)
end
end
end
0.upto(Favorite::TABLE_COUNT - 1) do |i|
Object.const_set("Favorite#{i}", Class.new(Favorite))
Object.const_get("Favorite#{i}").set_table_name("favorites_#{i}")
end end

View File

@@ -389,7 +389,7 @@ class Post < ActiveRecord::Base
module FavoriteMethods module FavoriteMethods
def delete_favorites def delete_favorites
Favorite.delete_post(id) Favorite.delete_all(:post_id => id)
end end
def favorited_by?(user_id) def favorited_by?(user_id)

View File

@@ -5,12 +5,12 @@ class User < ActiveRecord::Base
class PrivilegeError < Exception ; end class PrivilegeError < Exception ; end
module Levels module Levels
MEMBER = 0 MEMBER = 20
PRIVILEGED = 100 PRIVILEGED = 30
CONTRIBUTOR = 200 CONTRIBUTOR = 33
JANITOR = 300 JANITOR = 35
MODERATOR = 400 MODERATOR = 40
ADMIN = 500 ADMIN = 50
end end
attr_accessor :password, :old_password attr_accessor :password, :old_password
@@ -128,18 +128,18 @@ class User < ActiveRecord::Base
module FavoriteMethods module FavoriteMethods
def favorites def favorites
Favorite.model_for(id).where("user_id = ?", id).order("id desc") Favorite.where("user_id = ?", id).order("id desc")
end end
def add_favorite!(post) def add_favorite!(post)
return if Favorite.model_for(id).exists?(:user_id => id, :post_id => post.id) return if Favorite.exists?(:user_id => id, :post_id => post.id)
Favorite.model_for(id).create(:user_id => id, :post_id => post.id) Favorite.create(:user_id => id, :post_id => post.id)
post.add_favorite!(self) post.add_favorite!(self)
end end
def remove_favorite!(post) def remove_favorite!(post)
return unless Favorite.model_for(id).exists?(:user_id => id, :post_id => post.id) return unless Favorite.exists?(:user_id => id, :post_id => post.id)
Favorite.model_for(id).destroy_all(:user_id => id, :post_id => post.id) Favorite.destroy_all(:user_id => id, :post_id => post.id)
post.remove_favorite!(self) post.remove_favorite!(self)
end end
end end

View File

@@ -8,13 +8,13 @@ Bundler.require(:default, Rails.env) if defined?(Bundler)
module Danbooru module Danbooru
class Application < Rails::Application class Application < Rails::Application
config.active_record.schema_format = :sql
config.encoding = "utf-8" config.encoding = "utf-8"
config.filter_parameters += [:password] config.filter_parameters += [:password]
config.assets.enabled = true config.assets.enabled = true
config.autoload_paths += %W(#{config.root}/app/presenters #{config.root}/app/logical) config.autoload_paths += %W(#{config.root}/app/presenters #{config.root}/app/logical)
config.plugins = [:all] config.plugins = [:all]
config.time_zone = 'Eastern Time (US & Canada)' config.time_zone = 'Eastern Time (US & Canada)'
config.active_record.schema_format = :sql
# config.action_view.javascript_expansions[:defaults] = [ # config.action_view.javascript_expansions[:defaults] = [
# "src/lib/jquery-1.6.0.min.js", # "src/lib/jquery-1.6.0.min.js",
# "src/lib/jquery-ui-1.8.9.custom.min.js", # "src/lib/jquery-ui-1.8.9.custom.min.js",

File diff suppressed because it is too large Load Diff

View File

@@ -9,14 +9,44 @@ class CreateFavorites < ActiveRecord::Migration
end end
0.upto(TABLE_COUNT - 1) do |i| 0.upto(TABLE_COUNT - 1) do |i|
create_table "favorites_#{i}" do |t| execute <<-EOS
t.column :user_id, :integer create table favorites_#{i} (
t.column :post_id, :integer check (user_id % 100 = #{i})
end ) inherits (favorites)
EOS
add_index "favorites_#{i}", :user_id add_index "favorites_#{i}", :user_id
add_index "favorites_#{i}", :post_id add_index "favorites_#{i}", :post_id
end end
fragment = []
1.upto(TABLE_COUNT - 1) do |i|
fragment << <<-EOS
elsif (NEW.user_id % 100 = #{i}) then
insert into favorites_#{i} values (NEW.*);
EOS
end
execute <<-EOS
create or replace function favorites_insert_trigger()
returns trigger as $$
begin
if (NEW.user_id % 100 = 0) then
insert into favorites_0 values (NEW.*);
#{fragment.join("\n")}
end if;
return NULL;
end;
$$
language plpgsql
EOS
execute <<-EOS
create trigger insert_favorites_trigger
before insert on favorites
for each row execute procedure favorites_insert_trigger()
EOS
end end
def self.down def self.down

View File

@@ -1,6 +0,0 @@
namespace :db do
namespace :test do
task :reset => [:environment, "db:drop", "db:create", "db:migrate", "db:structure:dump", "db:test:clone_structure"] do
end
end
end

View File

@@ -24,8 +24,8 @@ module PostSets
context "a favorite set for before the most recent post" do context "a favorite set for before the most recent post" do
setup do setup do
id = ::Favorite.model_for(@user.id).where(:user_id => @user.id, :post_id => @post_3.id).first.id id = ::Favorite.where(:user_id => @user.id, :post_id => @post_3.id).first.id
::Favorite.model_for(@user.id).stubs(:records_per_page).returns(1) ::Favorite.stubs(:records_per_page).returns(1)
@set = PostSets::Favorite.new(@user.id, "b#{id}") @set = PostSets::Favorite.new(@user.id, "b#{id}")
end end
@@ -39,8 +39,8 @@ module PostSets
context "a favorite set for after the second most recent post" do context "a favorite set for after the second most recent post" do
setup do setup do
id = ::Favorite.model_for(@user.id).where(:user_id => @user.id, :post_id => @post_2.id).first.id id = ::Favorite.where(:user_id => @user.id, :post_id => @post_2.id).first.id
::Favorite.model_for(@user.id).stubs(:records_per_page).returns(1) ::Favorite.stubs(:records_per_page).returns(1)
@set = PostSets::Favorite.new(@user.id, "a#{id}") @set = PostSets::Favorite.new(@user.id, "a#{id}")
end end
@@ -54,7 +54,7 @@ module PostSets
context "a favorite set for page 2" do context "a favorite set for page 2" do
setup do setup do
::Favorite.model_for(@user.id).stubs(:records_per_page).returns(1) ::Favorite.stubs(:records_per_page).returns(1)
@set = PostSets::Favorite.new(@user.id, 2) @set = PostSets::Favorite.new(@user.id, 2)
end end
@@ -68,7 +68,7 @@ module PostSets
context "a favorite set with no page specified" do context "a favorite set with no page specified" do
setup do setup do
::Favorite.model_for(@user.id).stubs(:records_per_page).returns(1) ::Favorite.stubs(:records_per_page).returns(1)
@set = PostSets::Favorite.new(@user.id) @set = PostSets::Favorite.new(@user.id)
end end

View File

@@ -85,8 +85,8 @@ class PostTest < ActiveSupport::TestCase
c1.add_favorite!(user) c1.add_favorite!(user)
c1.delete! c1.delete!
p1.reload p1.reload
assert(!Favorite.model_for(user.id).exists?(:post_id => c1.id, :user_id => user.id)) assert(!Favorite.exists?(:post_id => c1.id, :user_id => user.id))
assert(Favorite.model_for(user.id).exists?(:post_id => p1.id, :user_id => user.id)) assert(Favorite.exists?(:post_id => p1.id, :user_id => user.id))
end end
should "update the parent's has_children flag" do should "update the parent's has_children flag" do
@@ -335,22 +335,22 @@ class PostTest < ActiveSupport::TestCase
post.add_favorite!(user) post.add_favorite!(user)
post.reload post.reload
assert_equal("fav:#{user.id}", post.fav_string) assert_equal("fav:#{user.id}", post.fav_string)
assert(Favorite.model_for(user.id).exists?(:user_id => user.id, :post_id => post.id)) assert(Favorite.exists?(:user_id => user.id, :post_id => post.id))
post.add_favorite!(user) post.add_favorite!(user)
post.reload post.reload
assert_equal("fav:#{user.id}", post.fav_string) assert_equal("fav:#{user.id}", post.fav_string)
assert(Favorite.model_for(user.id).exists?(:user_id => user.id, :post_id => post.id)) assert(Favorite.exists?(:user_id => user.id, :post_id => post.id))
post.remove_favorite!(user) post.remove_favorite!(user)
post.reload post.reload
assert_equal("", post.fav_string) assert_equal("", post.fav_string)
assert(!Favorite.model_for(user.id).exists?(:user_id => user.id, :post_id => post.id)) assert(!Favorite.exists?(:user_id => user.id, :post_id => post.id))
post.remove_favorite!(user) post.remove_favorite!(user)
post.reload post.reload
assert_equal("", post.fav_string) assert_equal("", post.fav_string)
assert(!Favorite.model_for(user.id).exists?(:user_id => user.id, :post_id => post.id)) assert(!Favorite.exists?(:user_id => user.id, :post_id => post.id))
end end
end end
end end