Commit 9ea545f1c8e386bc11af13d2de7333d52d487c98
1 parent
5d01bf73
Exists in
master
and in
23 other branches
ActionItem466: cutting down the search space
do not query for children of those that have no children git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@2060 3f533792-8f58-4932-b0fe-aaf55b0a4547
Showing
6 changed files
with
82 additions
and
15 deletions
Show diff stats
db/migrate/042_add_children_count_to_articles_and_categories.rb
0 → 100644
| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | +class AddChildrenCountToArticlesAndCategories < ActiveRecord::Migration | |
| 2 | + def self.up | |
| 3 | + add_column :articles, :children_count, :integer, :default => 0 | |
| 4 | + execute 'update articles set children_count = (select count(*) from articles a2 where (a2.parent_id = articles.id) )' | |
| 5 | + | |
| 6 | + add_column :article_versions, :children_count, :integer, :default => 0 | |
| 7 | + | |
| 8 | + add_column :categories, :children_count, :integer, :default => 0 | |
| 9 | + execute 'update categories set children_count = (select count(*) from categories c2 where (c2.parent_id = categories.id) )' | |
| 10 | + end | |
| 11 | + | |
| 12 | + def self.down | |
| 13 | + remove_column :articles, :children_count | |
| 14 | + remove_column :article_versions, :children_count | |
| 15 | + | |
| 16 | + remove_column :categories, :children_count | |
| 17 | + end | |
| 18 | +end | ... | ... |
db/schema.rb
| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | # |
| 10 | 10 | # It's strongly recommended to check this file into your version control system. |
| 11 | 11 | |
| 12 | -ActiveRecord::Schema.define(:version => 41) do | |
| 12 | +ActiveRecord::Schema.define(:version => 42) do | |
| 13 | 13 | |
| 14 | 14 | create_table "article_versions", :force => true do |t| |
| 15 | 15 | t.integer "article_id" |
| ... | ... | @@ -35,6 +35,7 @@ ActiveRecord::Schema.define(:version => 41) do |
| 35 | 35 | t.boolean "published", :default => true |
| 36 | 36 | t.date "start_date" |
| 37 | 37 | t.date "end_date" |
| 38 | + t.integer "children_count", :default => 0 | |
| 38 | 39 | end |
| 39 | 40 | |
| 40 | 41 | create_table "articles", :force => true do |t| |
| ... | ... | @@ -61,6 +62,7 @@ ActiveRecord::Schema.define(:version => 41) do |
| 61 | 62 | t.boolean "published", :default => true |
| 62 | 63 | t.date "start_date" |
| 63 | 64 | t.date "end_date" |
| 65 | + t.integer "children_count", :default => 0 | |
| 64 | 66 | end |
| 65 | 67 | |
| 66 | 68 | create_table "articles_categories", :id => false, :force => true do |t| |
| ... | ... | @@ -96,6 +98,7 @@ ActiveRecord::Schema.define(:version => 41) do |
| 96 | 98 | t.float "lat" |
| 97 | 99 | t.float "lng" |
| 98 | 100 | t.boolean "display_in_menu", :default => false |
| 101 | + t.integer "children_count", :default => 0 | |
| 99 | 102 | end |
| 100 | 103 | |
| 101 | 104 | create_table "categories_profiles", :id => false, :force => true do |t| | ... | ... |
lib/acts_as_filesystem.rb
| ... | ... | @@ -12,12 +12,13 @@ module ActsAsFileSystem |
| 12 | 12 | # non-alphanumericd characters changed into dashed) |
| 13 | 13 | # * path (+:text+)- stores the full path of the object (the full path of |
| 14 | 14 | # the parent, a "/" and the slug of the object) |
| 15 | + # * children_count - a cache of the number of children elements. | |
| 15 | 16 | def acts_as_filesystem |
| 16 | 17 | |
| 17 | 18 | include ActsAsFileSystem::InstanceMethods |
| 18 | 19 | |
| 19 | 20 | # a filesystem is a tree |
| 20 | - acts_as_tree :order => 'name' | |
| 21 | + acts_as_tree :order => 'name', :counter_cache => :children_count | |
| 21 | 22 | |
| 22 | 23 | # calculate the right path |
| 23 | 24 | before_create do |record| |
| ... | ... | @@ -163,7 +164,7 @@ module ActsAsFileSystem |
| 163 | 164 | |
| 164 | 165 | while !current_level.empty? |
| 165 | 166 | result += current_level |
| 166 | - ids = current_level.map(&:id) | |
| 167 | + ids = current_level.select {|item| item.children_count > 0}.map(&:id) | |
| 167 | 168 | current_level = self.class.find(:all, :conditions => { :parent_id => ids}) |
| 168 | 169 | end |
| 169 | 170 | block ||= (lambda { |x| x }) | ... | ... |
test/unit/acts_as_filesystem_test.rb
| ... | ... | @@ -26,11 +26,14 @@ class ActsAsFilesystemTest < Test::Unit::TestCase |
| 26 | 26 | |
| 27 | 27 | a1 = profile.articles.build(:name => 'a1'); a1.save! |
| 28 | 28 | |
| 29 | - a1_1 = profile.articles.build(:name => 'a1.1'); a1_1.parent = a1; a1_1.save! | |
| 30 | - a1_2 = profile.articles.build(:name => 'a1.2'); a1_2.parent = a1; a1_2.save! | |
| 29 | + a1_1 = a1.children.create!(:name => 'a1.1', :profile => profile) | |
| 31 | 30 | |
| 32 | - a1_1_1 = profile.articles.build(:name => 'a1.1.1'); a1_1_1.parent = a1_1; a1_1_1.save! | |
| 33 | - a1_1_2 = profile.articles.build(:name => 'a1.1.2'); a1_1_2.parent = a1_1; a1_1_2.save! | |
| 31 | + a1_2 = a1.children.create!(:name => 'a1.2', :profile => profile) | |
| 32 | + | |
| 33 | + a1_1_1 = a1_1.children.create!(:name => 'a1.1.1', :profile => profile) | |
| 34 | + a1_1_2 = a1_1.children.create!(:name => 'a1.1.2', :profile => profile) | |
| 35 | + | |
| 36 | + a1.reload | |
| 34 | 37 | |
| 35 | 38 | assert_equivalent [a1, a1_1, a1_2, a1_1_1, a1_1_2], a1.map_traversal |
| 36 | 39 | end |
| ... | ... | @@ -40,11 +43,14 @@ class ActsAsFilesystemTest < Test::Unit::TestCase |
| 40 | 43 | |
| 41 | 44 | a1 = profile.articles.build(:name => 'a1'); a1.save! |
| 42 | 45 | |
| 43 | - a1_1 = profile.articles.build(:name => 'a1.1'); a1_1.parent = a1; a1_1.save! | |
| 44 | - a1_2 = profile.articles.build(:name => 'a1.2'); a1_2.parent = a1; a1_2.save! | |
| 46 | + a1_1 = a1.children.create!(:name => 'a1.1', :profile => profile) | |
| 47 | + | |
| 48 | + a1_2 = a1.children.create!(:name => 'a1.2', :profile => profile) | |
| 45 | 49 | |
| 46 | - a1_1_1 = profile.articles.build(:name => 'a1.1.1'); a1_1_1.parent = a1_1; a1_1_1.save! | |
| 47 | - a1_1_2 = profile.articles.build(:name => 'a1.1.2'); a1_1_2.parent = a1_1; a1_1_2.save! | |
| 50 | + a1_1_1 = a1_1.children.create!(:name => 'a1.1.1', :profile => profile) | |
| 51 | + a1_1_2 = a1_1.children.create!(:name => 'a1.1.2', :profile => profile) | |
| 52 | + | |
| 53 | + a1.reload | |
| 48 | 54 | |
| 49 | 55 | assert_equivalent [a1_1, a1_2, a1_1_1, a1_1_2].map(&:id), a1.all_children.map(&:id) |
| 50 | 56 | end |
| ... | ... | @@ -54,11 +60,14 @@ class ActsAsFilesystemTest < Test::Unit::TestCase |
| 54 | 60 | |
| 55 | 61 | a1 = profile.articles.build(:name => 'a1'); a1.save! |
| 56 | 62 | |
| 57 | - a1_1 = profile.articles.build(:name => 'a1.1'); a1_1.parent = a1; a1_1.save! | |
| 58 | - a1_2 = profile.articles.build(:name => 'a1.2'); a1_2.parent = a1; a1_2.save! | |
| 63 | + a1_1 = a1.children.create!(:name => 'a1.1', :profile => profile) | |
| 64 | + | |
| 65 | + a1_2 = a1.children.create!(:name => 'a1.2', :profile => profile) | |
| 59 | 66 | |
| 60 | - a1_1_1 = profile.articles.build(:name => 'a1.1.1'); a1_1_1.parent = a1_1; a1_1_1.save! | |
| 61 | - a1_1_2 = profile.articles.build(:name => 'a1.1.2'); a1_1_2.parent = a1_1; a1_1_2.save! | |
| 67 | + a1_1_1 = a1_1.children.create!(:name => 'a1.1.1', :profile => profile) | |
| 68 | + a1_1_2 = a1_1.children.create!(:name => 'a1.1.2', :profile => profile) | |
| 69 | + | |
| 70 | + a1.reload | |
| 62 | 71 | |
| 63 | 72 | assert_equivalent ['a1', 'a1.1', 'a1.2', 'a1.1.1', 'a1.1.2'], a1.map_traversal { |item| item.name } |
| 64 | 73 | |
| ... | ... | @@ -76,4 +85,11 @@ class ActsAsFilesystemTest < Test::Unit::TestCase |
| 76 | 85 | assert_equal 'd', a.full_name_without_leading(3) |
| 77 | 86 | end |
| 78 | 87 | |
| 88 | + should 'cache children count' do | |
| 89 | + profile = create_user('testinguser').person | |
| 90 | + a1 = profile.articles.create!(:name => 'a1') | |
| 91 | + a11 = profile.articles.create!(:name => 'a11', :parent => a1) | |
| 92 | + a12 = profile.articles.create!(:name => 'a12', :parent => a1) | |
| 93 | + end | |
| 94 | + | |
| 79 | 95 | end | ... | ... |
test/unit/article_test.rb
| ... | ... | @@ -55,6 +55,7 @@ class ArticleTest < Test::Unit::TestCase |
| 55 | 55 | b.save! |
| 56 | 56 | assert_equal 'my-article/child-article', b.path |
| 57 | 57 | |
| 58 | + a = Article.find(a.id); | |
| 58 | 59 | a.name = 'another name' |
| 59 | 60 | a.save! |
| 60 | 61 | |
| ... | ... | @@ -308,4 +309,19 @@ class ArticleTest < Test::Unit::TestCase |
| 308 | 309 | assert_includes Article.find_by_contents('anything'), art |
| 309 | 310 | end |
| 310 | 311 | |
| 312 | + should 'cache children count' do | |
| 313 | + owner = create_user('testuser').person | |
| 314 | + art = owner.articles.build(:name => 'ytest'); art.save! | |
| 315 | + | |
| 316 | + # two children articles | |
| 317 | + art.children.create!(:profile => owner, :name => 'c1') | |
| 318 | + art.children.create!(:profile => owner, :name => 'c2') | |
| 319 | + | |
| 320 | + art.reload | |
| 321 | + | |
| 322 | + assert_equal 2, art.children_count | |
| 323 | + assert_equal 2, art.children.size | |
| 324 | + | |
| 325 | + end | |
| 326 | + | |
| 311 | 327 | end | ... | ... |
test/unit/category_test.rb
| ... | ... | @@ -418,4 +418,17 @@ class CategoryTest < Test::Unit::TestCase |
| 418 | 418 | assert_equivalent [c1, c11, c2], c.children_for_menu |
| 419 | 419 | end |
| 420 | 420 | |
| 421 | + should 'cache children count' do | |
| 422 | + c = Category.create!(:name => 'test', :environment => Environment.default) | |
| 423 | + | |
| 424 | + # two children catagories | |
| 425 | + c.children.create!(:name => 'test1', :environment => Environment.default) | |
| 426 | + c.children.create!(:name => 'test2', :environment => Environment.default) | |
| 427 | + | |
| 428 | + c.reload | |
| 429 | + | |
| 430 | + assert_equal 2, c.children_count | |
| 431 | + assert_equal 2, c.children.size | |
| 432 | + end | |
| 433 | + | |
| 421 | 434 | end | ... | ... |