Commit 9ea545f1c8e386bc11af13d2de7333d52d487c98
1 parent
5d01bf73
Exists in
master
and in
22 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 @@ | @@ -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,7 +9,7 @@ | ||
9 | # | 9 | # |
10 | # It's strongly recommended to check this file into your version control system. | 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 | create_table "article_versions", :force => true do |t| | 14 | create_table "article_versions", :force => true do |t| |
15 | t.integer "article_id" | 15 | t.integer "article_id" |
@@ -35,6 +35,7 @@ ActiveRecord::Schema.define(:version => 41) do | @@ -35,6 +35,7 @@ ActiveRecord::Schema.define(:version => 41) do | ||
35 | t.boolean "published", :default => true | 35 | t.boolean "published", :default => true |
36 | t.date "start_date" | 36 | t.date "start_date" |
37 | t.date "end_date" | 37 | t.date "end_date" |
38 | + t.integer "children_count", :default => 0 | ||
38 | end | 39 | end |
39 | 40 | ||
40 | create_table "articles", :force => true do |t| | 41 | create_table "articles", :force => true do |t| |
@@ -61,6 +62,7 @@ ActiveRecord::Schema.define(:version => 41) do | @@ -61,6 +62,7 @@ ActiveRecord::Schema.define(:version => 41) do | ||
61 | t.boolean "published", :default => true | 62 | t.boolean "published", :default => true |
62 | t.date "start_date" | 63 | t.date "start_date" |
63 | t.date "end_date" | 64 | t.date "end_date" |
65 | + t.integer "children_count", :default => 0 | ||
64 | end | 66 | end |
65 | 67 | ||
66 | create_table "articles_categories", :id => false, :force => true do |t| | 68 | create_table "articles_categories", :id => false, :force => true do |t| |
@@ -96,6 +98,7 @@ ActiveRecord::Schema.define(:version => 41) do | @@ -96,6 +98,7 @@ ActiveRecord::Schema.define(:version => 41) do | ||
96 | t.float "lat" | 98 | t.float "lat" |
97 | t.float "lng" | 99 | t.float "lng" |
98 | t.boolean "display_in_menu", :default => false | 100 | t.boolean "display_in_menu", :default => false |
101 | + t.integer "children_count", :default => 0 | ||
99 | end | 102 | end |
100 | 103 | ||
101 | create_table "categories_profiles", :id => false, :force => true do |t| | 104 | create_table "categories_profiles", :id => false, :force => true do |t| |
lib/acts_as_filesystem.rb
@@ -12,12 +12,13 @@ module ActsAsFileSystem | @@ -12,12 +12,13 @@ module ActsAsFileSystem | ||
12 | # non-alphanumericd characters changed into dashed) | 12 | # non-alphanumericd characters changed into dashed) |
13 | # * path (+:text+)- stores the full path of the object (the full path of | 13 | # * path (+:text+)- stores the full path of the object (the full path of |
14 | # the parent, a "/" and the slug of the object) | 14 | # the parent, a "/" and the slug of the object) |
15 | + # * children_count - a cache of the number of children elements. | ||
15 | def acts_as_filesystem | 16 | def acts_as_filesystem |
16 | 17 | ||
17 | include ActsAsFileSystem::InstanceMethods | 18 | include ActsAsFileSystem::InstanceMethods |
18 | 19 | ||
19 | # a filesystem is a tree | 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 | # calculate the right path | 23 | # calculate the right path |
23 | before_create do |record| | 24 | before_create do |record| |
@@ -163,7 +164,7 @@ module ActsAsFileSystem | @@ -163,7 +164,7 @@ module ActsAsFileSystem | ||
163 | 164 | ||
164 | while !current_level.empty? | 165 | while !current_level.empty? |
165 | result += current_level | 166 | result += current_level |
166 | - ids = current_level.map(&:id) | 167 | + ids = current_level.select {|item| item.children_count > 0}.map(&:id) |
167 | current_level = self.class.find(:all, :conditions => { :parent_id => ids}) | 168 | current_level = self.class.find(:all, :conditions => { :parent_id => ids}) |
168 | end | 169 | end |
169 | block ||= (lambda { |x| x }) | 170 | block ||= (lambda { |x| x }) |
test/unit/acts_as_filesystem_test.rb
@@ -26,11 +26,14 @@ class ActsAsFilesystemTest < Test::Unit::TestCase | @@ -26,11 +26,14 @@ class ActsAsFilesystemTest < Test::Unit::TestCase | ||
26 | 26 | ||
27 | a1 = profile.articles.build(:name => 'a1'); a1.save! | 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 | assert_equivalent [a1, a1_1, a1_2, a1_1_1, a1_1_2], a1.map_traversal | 38 | assert_equivalent [a1, a1_1, a1_2, a1_1_1, a1_1_2], a1.map_traversal |
36 | end | 39 | end |
@@ -40,11 +43,14 @@ class ActsAsFilesystemTest < Test::Unit::TestCase | @@ -40,11 +43,14 @@ class ActsAsFilesystemTest < Test::Unit::TestCase | ||
40 | 43 | ||
41 | a1 = profile.articles.build(:name => 'a1'); a1.save! | 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 | assert_equivalent [a1_1, a1_2, a1_1_1, a1_1_2].map(&:id), a1.all_children.map(&:id) | 55 | assert_equivalent [a1_1, a1_2, a1_1_1, a1_1_2].map(&:id), a1.all_children.map(&:id) |
50 | end | 56 | end |
@@ -54,11 +60,14 @@ class ActsAsFilesystemTest < Test::Unit::TestCase | @@ -54,11 +60,14 @@ class ActsAsFilesystemTest < Test::Unit::TestCase | ||
54 | 60 | ||
55 | a1 = profile.articles.build(:name => 'a1'); a1.save! | 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 | assert_equivalent ['a1', 'a1.1', 'a1.2', 'a1.1.1', 'a1.1.2'], a1.map_traversal { |item| item.name } | 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,4 +85,11 @@ class ActsAsFilesystemTest < Test::Unit::TestCase | ||
76 | assert_equal 'd', a.full_name_without_leading(3) | 85 | assert_equal 'd', a.full_name_without_leading(3) |
77 | end | 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 | end | 95 | end |
test/unit/article_test.rb
@@ -55,6 +55,7 @@ class ArticleTest < Test::Unit::TestCase | @@ -55,6 +55,7 @@ class ArticleTest < Test::Unit::TestCase | ||
55 | b.save! | 55 | b.save! |
56 | assert_equal 'my-article/child-article', b.path | 56 | assert_equal 'my-article/child-article', b.path |
57 | 57 | ||
58 | + a = Article.find(a.id); | ||
58 | a.name = 'another name' | 59 | a.name = 'another name' |
59 | a.save! | 60 | a.save! |
60 | 61 | ||
@@ -308,4 +309,19 @@ class ArticleTest < Test::Unit::TestCase | @@ -308,4 +309,19 @@ class ArticleTest < Test::Unit::TestCase | ||
308 | assert_includes Article.find_by_contents('anything'), art | 309 | assert_includes Article.find_by_contents('anything'), art |
309 | end | 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 | end | 327 | end |
test/unit/category_test.rb
@@ -418,4 +418,17 @@ class CategoryTest < Test::Unit::TestCase | @@ -418,4 +418,17 @@ class CategoryTest < Test::Unit::TestCase | ||
418 | assert_equivalent [c1, c11, c2], c.children_for_menu | 418 | assert_equivalent [c1, c11, c2], c.children_for_menu |
419 | end | 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 | end | 434 | end |