Commit 9ea545f1c8e386bc11af13d2de7333d52d487c98

Authored by AntonioTerceiro
1 parent 5d01bf73

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
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 =&gt; 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 =&gt; 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 =&gt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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
... ...