closure_tree 6.1.0 → 6.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -0
  3. data/.rspec +0 -0
  4. data/.travis.yml +0 -0
  5. data/.yardopts +0 -0
  6. data/Appraisals +0 -0
  7. data/CHANGELOG.md +7 -0
  8. data/Gemfile +0 -0
  9. data/MIT-LICENSE +0 -0
  10. data/README.md +6 -1
  11. data/Rakefile +0 -0
  12. data/closure_tree.gemspec +0 -0
  13. data/gemfiles/activerecord_4.1.gemfile +0 -0
  14. data/gemfiles/activerecord_4.2.gemfile +0 -0
  15. data/gemfiles/activerecord_5.0.gemfile +0 -0
  16. data/gemfiles/activerecord_5.0_foreigner.gemfile +0 -0
  17. data/gemfiles/activerecord_edge.gemfile +0 -0
  18. data/img/example.png +0 -0
  19. data/img/preorder.png +0 -0
  20. data/lib/closure_tree.rb +2 -0
  21. data/lib/closure_tree/active_record_support.rb +0 -0
  22. data/lib/closure_tree/configuration.rb +0 -0
  23. data/lib/closure_tree/deterministic_ordering.rb +0 -0
  24. data/lib/closure_tree/digraphs.rb +0 -0
  25. data/lib/closure_tree/finders.rb +3 -3
  26. data/lib/closure_tree/has_closure_tree.rb +0 -0
  27. data/lib/closure_tree/has_closure_tree_root.rb +88 -0
  28. data/lib/closure_tree/hash_tree.rb +0 -0
  29. data/lib/closure_tree/hash_tree_support.rb +0 -0
  30. data/lib/closure_tree/hierarchy_maintenance.rb +0 -0
  31. data/lib/closure_tree/model.rb +0 -0
  32. data/lib/closure_tree/numeric_deterministic_ordering.rb +1 -1
  33. data/lib/closure_tree/numeric_order_support.rb +0 -0
  34. data/lib/closure_tree/support.rb +0 -0
  35. data/lib/closure_tree/support_attributes.rb +1 -2
  36. data/lib/closure_tree/support_flags.rb +0 -0
  37. data/lib/closure_tree/test/matcher.rb +0 -0
  38. data/lib/closure_tree/version.rb +1 -1
  39. data/lib/generators/closure_tree/config_generator.rb +0 -0
  40. data/lib/generators/closure_tree/migration_generator.rb +0 -0
  41. data/lib/generators/closure_tree/templates/config.rb +0 -0
  42. data/lib/generators/closure_tree/templates/create_hierarchies_table.rb.erb +0 -0
  43. data/spec/cache_invalidation_spec.rb +0 -0
  44. data/spec/cuisine_type_spec.rb +0 -0
  45. data/spec/db/database.yml +0 -0
  46. data/spec/db/models.rb +24 -2
  47. data/spec/db/schema.rb +22 -0
  48. data/spec/fixtures/tags.yml +0 -0
  49. data/spec/generators/migration_generator_spec.rb +0 -0
  50. data/spec/has_closure_tree_root_spec.rb +132 -0
  51. data/spec/hierarchy_maintenance_spec.rb +0 -0
  52. data/spec/label_spec.rb +0 -0
  53. data/spec/matcher_spec.rb +0 -0
  54. data/spec/metal_spec.rb +0 -0
  55. data/spec/model_spec.rb +0 -0
  56. data/spec/namespace_type_spec.rb +0 -0
  57. data/spec/parallel_spec.rb +0 -0
  58. data/spec/spec_helper.rb +0 -0
  59. data/spec/support/database.rb +0 -0
  60. data/spec/support/database_cleaner.rb +0 -0
  61. data/spec/support/exceed_query_limit.rb +18 -0
  62. data/spec/support/hash_monkey_patch.rb +0 -0
  63. data/spec/support/query_counter.rb +18 -0
  64. data/spec/support/sqlite3_with_advisory_lock.rb +0 -0
  65. data/spec/support_spec.rb +0 -0
  66. data/spec/tag_examples.rb +0 -0
  67. data/spec/tag_spec.rb +0 -0
  68. data/spec/user_spec.rb +0 -0
  69. data/spec/uuid_tag_spec.rb +0 -0
  70. metadata +9 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: be5442160917053dfca50f710fa8276b2d2d937c
4
- data.tar.gz: e6012dd4b630ace5fa36835de936bd395e41df20
3
+ metadata.gz: e3b96ba78aea59298da3138316379a458d28c713
4
+ data.tar.gz: f1c786fb41309ea4460a06ae296b7393ea058b63
5
5
  SHA512:
6
- metadata.gz: 43316c4fd1030f11ca90d59cf477f9a7d5300a16771152e3b81a779d5a25f665b9f9a288c42bc0c54183717d537cc95d704fc180166064079fbe6a9ee20d2bc5
7
- data.tar.gz: 7f65c0281b3d878b2c333087f3e63a8e09c6aecbcabc98d798e2e1651853f50f7aefe50ece31b611bf12b17718fa3b023adc67cb39c747034a79aafae152dd93
6
+ metadata.gz: b5850fadca83ecdc88e53f4fac48a19faaafda82c7b6bd93f8051e264b632a94b56edbc3b22d9d060d658cf76dca02268fda625835c74e9e6cfb6ef75e9430d6
7
+ data.tar.gz: cae0ca262a5f9f76d1a01b24aac119a5307a49637a77e9287305630d2e97c2b3265a767180b5e76eedff9a4a9ada44ff07aebe648d0b109949c7ed2e012b9b93
data/.gitignore CHANGED
File without changes
data/.rspec CHANGED
File without changes
data/.travis.yml CHANGED
File without changes
data/.yardopts CHANGED
File without changes
data/Appraisals CHANGED
File without changes
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ### 6.2.0
4
+
5
+ * Fix for [MySQL lock lengths](https://github.com/mceachen/closure_tree/issues/231).
6
+ Thanks to [Liam](https://github.com/hut8)!
7
+ * [Tom Smyth](https://github.com/hooverlunch) added [eager tree loading](https://github.com/mceachen/closure_tree/pull/232)
8
+ * Merged [PR 200](https://github.com/mceachen/closure_tree/pull/200) which may or may not add support to SQLServer 2008 (but this is not a supported RDBMS).
9
+
3
10
  ### 6.1.0
4
11
 
5
12
  * Added official support for ActiveRecord 5.0! Thanks to [Abdelkader Boudih](https://github.com/seuros),
data/Gemfile CHANGED
File without changes
data/MIT-LICENSE CHANGED
File without changes
data/README.md CHANGED
@@ -468,7 +468,12 @@ Yup! [Ilya Bodrov](https://github.com/bodrovis) wrote [Nested Comments with Rail
468
468
 
469
469
  ### Does this work well with ```#default_scope```?
470
470
 
471
- No. Please see [issue 86](https://github.com/mceachen/closure_tree/issues/86) for details.
471
+ **No.** Please see [issue 86](https://github.com/mceachen/closure_tree/issues/86) for details.
472
+
473
+ ### Can I update parentage with `update_attribute`?
474
+
475
+ **No.** `update_attribute` skips the validation hook that is required for maintaining the
476
+ hierarchy table.
472
477
 
473
478
  ### Does this gem support multiple parents?
474
479
 
data/Rakefile CHANGED
File without changes
data/closure_tree.gemspec CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
data/img/example.png CHANGED
File without changes
data/img/preorder.png CHANGED
File without changes
data/lib/closure_tree.rb CHANGED
@@ -4,6 +4,7 @@ module ClosureTree
4
4
  extend ActiveSupport::Autoload
5
5
 
6
6
  autoload :HasClosureTree
7
+ autoload :HasClosureTreeRoot
7
8
  autoload :Support
8
9
  autoload :HierarchyMaintenance
9
10
  autoload :Model
@@ -25,4 +26,5 @@ end
25
26
 
26
27
  ActiveSupport.on_load :active_record do
27
28
  ActiveRecord::Base.send :extend, ClosureTree::HasClosureTree
29
+ ActiveRecord::Base.send :extend, ClosureTree::HasClosureTreeRoot
28
30
  end
File without changes
File without changes
File without changes
File without changes
@@ -39,7 +39,7 @@ module ClosureTree
39
39
  SELECT descendant_id
40
40
  FROM #{_ct.quoted_hierarchy_table_name}
41
41
  WHERE ancestor_id = #{_ct.quote(self.id)}
42
- GROUP BY 1
42
+ GROUP BY descendant_id
43
43
  HAVING MAX(#{_ct.quoted_hierarchy_table_name}.generations) = #{generation_level.to_i}
44
44
  ) AS descendants ON (#{_ct.quoted_table_name}.#{_ct.base_class.primary_key} = descendants.descendant_id)
45
45
  SQL
@@ -74,7 +74,7 @@ module ClosureTree
74
74
  INNER JOIN (
75
75
  SELECT ancestor_id
76
76
  FROM #{_ct.quoted_hierarchy_table_name}
77
- GROUP BY 1
77
+ GROUP BY ancestor_id
78
78
  HAVING MAX(#{_ct.quoted_hierarchy_table_name}.generations) = 0
79
79
  ) AS leaves ON (#{_ct.quoted_table_name}.#{primary_key} = leaves.ancestor_id)
80
80
  SQL
@@ -100,7 +100,7 @@ module ClosureTree
100
100
  INNER JOIN (
101
101
  SELECT ancestor_id, descendant_id
102
102
  FROM #{_ct.quoted_hierarchy_table_name}
103
- GROUP BY 1, 2
103
+ GROUP BY ancestor_id, descendant_id
104
104
  HAVING MAX(generations) = #{generation_level.to_i}
105
105
  ) AS descendants ON (
106
106
  #{_ct.quoted_table_name}.#{primary_key} = descendants.descendant_id
File without changes
@@ -0,0 +1,88 @@
1
+ module ClosureTree
2
+ class MultipleRootError < StandardError; end
3
+
4
+ module HasClosureTreeRoot
5
+
6
+ def has_closure_tree_root(assoc_name, options = {})
7
+ options.assert_valid_keys(
8
+ :class_name,
9
+ :foreign_key
10
+ )
11
+
12
+ options[:class_name] ||= assoc_name.to_s.sub(/\Aroot_/, "").classify
13
+ options[:foreign_key] ||= self.name.underscore << "_id"
14
+
15
+ has_one assoc_name, -> { where(parent: nil) }, options
16
+
17
+ # Fetches the association, eager loading all children and given associations
18
+ define_method("#{assoc_name}_including_tree") do |assoc_map_or_reload = nil, assoc_map = nil|
19
+ reload = false
20
+ if assoc_map_or_reload.is_a?(::Hash)
21
+ assoc_map = assoc_map_or_reload
22
+ else
23
+ reload = assoc_map_or_reload
24
+ end
25
+
26
+ unless reload
27
+ # Memoize
28
+ @closure_tree_roots ||= {}
29
+ @closure_tree_roots[assoc_name] ||= {}
30
+ if @closure_tree_roots[assoc_name].has_key?(assoc_map)
31
+ return @closure_tree_roots[assoc_name][assoc_map]
32
+ end
33
+ end
34
+
35
+ roots = options[:class_name].constantize.where(parent: nil, options[:foreign_key] => id).to_a
36
+
37
+ return nil if roots.empty?
38
+
39
+ if roots.size > 1
40
+ raise MultipleRootError.new("#{self.class.name}: has_closure_tree_root requires a single root")
41
+ end
42
+
43
+ temp_root = roots.first
44
+ root = nil
45
+ id_hash = {}
46
+ parent_col_id = temp_root.class._ct.options[:parent_column_name]
47
+
48
+ # Lookup inverse belongs_to association reflection on target class.
49
+ inverse = temp_root.class.reflections.values.detect do |r|
50
+ r.macro == :belongs_to && r.klass == self.class
51
+ end
52
+
53
+ # Fetch all descendants in constant number of queries.
54
+ # This is the last query-triggering statement in the method.
55
+ temp_root.self_and_descendants.includes(assoc_map).each do |node|
56
+ id_hash[node.id] = node
57
+ parent_node = id_hash[node[parent_col_id]]
58
+
59
+ # Pre-assign parent association
60
+ parent_assoc = node.association(:parent)
61
+ parent_assoc.loaded!
62
+ parent_assoc.target = parent_node
63
+
64
+ # Pre-assign children association as empty for now,
65
+ # children will be added in subsequent loop iterations
66
+ children_assoc = node.association(:children)
67
+ children_assoc.loaded!
68
+
69
+ if parent_node
70
+ parent_node.association(:children).target << node
71
+ else
72
+ # Capture the root we're going to use
73
+ root = node
74
+ end
75
+
76
+ # Pre-assign inverse association back to this class, if it exists on target class.
77
+ if inverse
78
+ inverse_assoc = node.association(inverse.name)
79
+ inverse_assoc.loaded!
80
+ inverse_assoc.target = self
81
+ end
82
+ end
83
+
84
+ @closure_tree_roots[assoc_name][assoc_map] = root
85
+ end
86
+ end
87
+ end
88
+ end
File without changes
File without changes
File without changes
File without changes
@@ -72,7 +72,7 @@ module ClosureTree
72
72
  JOIN (
73
73
  SELECT descendant_id, max(generations) AS max_depth
74
74
  FROM #{_ct.quoted_hierarchy_table_name}
75
- GROUP BY 1
75
+ GROUP BY descendant_id
76
76
  ) AS depths ON depths.descendant_id = anc.#{_ct.quoted_id_column_name}
77
77
  SQL
78
78
  joins(join_sql)
File without changes
File without changes
@@ -1,12 +1,11 @@
1
1
  require 'forwardable'
2
2
  module ClosureTree
3
3
  module SupportAttributes
4
-
5
4
  extend Forwardable
6
5
  def_delegators :model_class, :connection, :transaction, :table_name, :base_class, :inheritance_column, :column_names
7
6
 
8
7
  def advisory_lock_name
9
- "ClosureTree::#{base_class.name}"
8
+ Digest::SHA1.hexdigest("ClosureTree::#{base_class.name}")[0..32]
10
9
  end
11
10
 
12
11
  def quoted_table_name
File without changes
File without changes
@@ -1,3 +1,3 @@
1
1
  module ClosureTree
2
- VERSION = Gem::Version.new('6.1.0')
2
+ VERSION = Gem::Version.new('6.2.0')
3
3
  end
File without changes
File without changes
File without changes
File without changes
File without changes
data/spec/db/database.yml CHANGED
File without changes
data/spec/db/models.rb CHANGED
@@ -35,13 +35,30 @@ end
35
35
  class DestroyedTag < ActiveRecord::Base
36
36
  end
37
37
 
38
+ class Group < ActiveRecord::Base
39
+ has_closure_tree_root :root_user
40
+ end
41
+
42
+ class Grouping < ActiveRecord::Base
43
+ has_closure_tree_root :root_person, class_name: "User", foreign_key: :group_id
44
+ end
45
+
46
+ class UserSet < ActiveRecord::Base
47
+ has_closure_tree_root :root_user, class_name: "Useur"
48
+ end
49
+
50
+ class Team < ActiveRecord::Base
51
+ has_closure_tree_root :root_user, class_name: "User", foreign_key: :grp_id
52
+ end
53
+
38
54
  class User < ActiveRecord::Base
39
55
  acts_as_tree :parent_column_name => "referrer_id",
40
56
  :name_column => 'email',
41
57
  :hierarchy_class_name => 'ReferralHierarchy',
42
58
  :hierarchy_table_name => 'referral_hierarchies'
43
59
 
44
- has_many :contracts
60
+ has_many :contracts, inverse_of: :user
61
+ belongs_to :group # Can't use and don't need inverse_of here when using has_closure_tree_root.
45
62
 
46
63
  def indirect_contracts
47
64
  Contract.where(:user_id => descendant_ids)
@@ -53,7 +70,12 @@ class User < ActiveRecord::Base
53
70
  end
54
71
 
55
72
  class Contract < ActiveRecord::Base
56
- belongs_to :user
73
+ belongs_to :user, inverse_of: :contracts
74
+ belongs_to :contract_type, inverse_of: :contracts
75
+ end
76
+
77
+ class ContractType < ActiveRecord::Base
78
+ has_many :contracts, inverse_of: :contract_type
57
79
  end
58
80
 
59
81
  class Label < ActiveRecord::Base
data/spec/db/schema.rb CHANGED
@@ -43,9 +43,26 @@ ActiveRecord::Schema.define(:version => 0) do
43
43
  add_index "tag_hierarchies", [:ancestor_id, :descendant_id, :generations], :unique => true, :name => "tag_anc_desc_idx"
44
44
  add_index "tag_hierarchies", [:descendant_id], :name => "tag_desc_idx"
45
45
 
46
+ create_table "groups" do |t|
47
+ t.string "name", null: false
48
+ end
49
+
50
+ create_table "groupings" do |t|
51
+ t.string "name", null: false
52
+ end
53
+
54
+ create_table "user_sets" do |t|
55
+ t.string "name", null: false
56
+ end
57
+
58
+ create_table "teams" do |t|
59
+ t.string "name", null: false
60
+ end
61
+
46
62
  create_table "users" do |t|
47
63
  t.string "email"
48
64
  t.integer "referrer_id"
65
+ t.integer "group_id"
49
66
  t.timestamps null: false
50
67
  end
51
68
 
@@ -53,6 +70,11 @@ ActiveRecord::Schema.define(:version => 0) do
53
70
 
54
71
  create_table "contracts" do |t|
55
72
  t.integer "user_id", :null => false
73
+ t.integer "contract_type_id"
74
+ end
75
+
76
+ create_table "contract_types" do |t|
77
+ t.string "name", :null => false
56
78
  end
57
79
 
58
80
  create_table "referral_hierarchies", :id => false do |t|
File without changes
File without changes
@@ -0,0 +1,132 @@
1
+ require "spec_helper"
2
+
3
+ describe "has_closure_tree_root" do
4
+ let!(:ct1) { ContractType.create!(name: "Type1") }
5
+ let!(:ct2) { ContractType.create!(name: "Type2") }
6
+ let!(:user1) { User.create!(email: "1@example.com", group_id: group.id) }
7
+ let!(:user2) { User.create!(email: "2@example.com", group_id: group.id) }
8
+ let!(:user3) { User.create!(email: "3@example.com", group_id: group.id) }
9
+ let!(:user4) { User.create!(email: "4@example.com", group_id: group.id) }
10
+ let!(:user5) { User.create!(email: "5@example.com", group_id: group.id) }
11
+ let!(:user6) { User.create!(email: "6@example.com", group_id: group.id) }
12
+ let!(:group_reloaded) { group.class.find(group.id) } # Ensures were starting fresh.
13
+
14
+ before do
15
+ # The tree (contract types in parens)
16
+ #
17
+ # U1(1)
18
+ # / \
19
+ # U2(1) U3(1&2)
20
+ # / / \
21
+ # U4(2) U5(1) U6(2)
22
+
23
+ user1.children << user2
24
+ user1.children << user3
25
+ user2.children << user4
26
+ user3.children << user5
27
+ user3.children << user6
28
+
29
+ user1.contracts.create!(contract_type: ct1)
30
+ user2.contracts.create!(contract_type: ct1)
31
+ user3.contracts.create!(contract_type: ct1)
32
+ user3.contracts.create!(contract_type: ct2)
33
+ user4.contracts.create!(contract_type: ct2)
34
+ user5.contracts.create!(contract_type: ct1)
35
+ user6.contracts.create!(contract_type: ct2)
36
+ end
37
+
38
+ context "with basic config" do
39
+ let!(:group) { Group.create!(name: "TheGroup") }
40
+
41
+ it "loads all nodes and associations in a constant number of queries" do
42
+ expect do
43
+ root = group_reloaded.root_user_including_tree(contracts: :contract_type)
44
+ expect(root.children[0].email).to eq "2@example.com"
45
+ expect(root.children[0].parent.children[1].email).to eq "3@example.com"
46
+ expect(root.children[1].contracts.map(&:contract_type).map(&:name)).to eq %w(Type1 Type2)
47
+ expect(root.children[1].children[0].contracts[0].contract_type.name).to eq "Type1"
48
+ expect(root.children[0].children[0].contracts[0].user.
49
+ parent.parent.children[1].children[1].contracts[0].contract_type.name).to eq "Type2"
50
+ end.to_not exceed_query_limit(4) # Without this feature, this is 15, and scales with number of nodes.
51
+ end
52
+
53
+ it "memoizes by assoc_map" do
54
+ group_reloaded.root_user_including_tree.email = "x"
55
+ expect(group_reloaded.root_user_including_tree.email).to eq "x"
56
+ group_reloaded.root_user_including_tree(contracts: :contract_type).email = "y"
57
+ expect(group_reloaded.root_user_including_tree(contracts: :contract_type).email).to eq "y"
58
+ expect(group_reloaded.root_user_including_tree.email).to eq "x"
59
+ end
60
+
61
+ it "doesn't memoize if true argument passed" do
62
+ group_reloaded.root_user_including_tree.email = "x"
63
+ expect(group_reloaded.root_user_including_tree(true).email).to eq "1@example.com"
64
+ group_reloaded.root_user_including_tree(contracts: :contract_type).email = "y"
65
+ expect(group_reloaded.root_user_including_tree(true, contracts: :contract_type).email).
66
+ to eq "1@example.com"
67
+ end
68
+
69
+ it "eager loads inverse association to group" do
70
+ expect do
71
+ root = group_reloaded.root_user_including_tree
72
+ expect(root.group).to eq group
73
+ expect(root.children[0].group).to eq group
74
+ end.to_not exceed_query_limit(2)
75
+ end
76
+
77
+ it "works if eager load association map is not given" do
78
+ expect do
79
+ root = group_reloaded.root_user_including_tree
80
+ expect(root.children[0].email).to eq "2@example.com"
81
+ expect(root.children[0].parent.children[1].children[0].email).to eq "5@example.com"
82
+ end.to_not exceed_query_limit(2)
83
+ end
84
+
85
+ context "with no tree root" do
86
+ let(:group2) { Group.create!(name: "OtherGroup") }
87
+
88
+ it "should return nil" do
89
+ expect(group2.root_user_including_tree(contracts: :contract_type)).to be_nil
90
+ end
91
+ end
92
+
93
+ context "with multiple tree roots" do
94
+ let!(:other_root) { User.create!(email: "10@example.com", group_id: group.id) }
95
+
96
+ it "should error" do
97
+ expect do
98
+ root = group_reloaded.root_user_including_tree(contracts: :contract_type)
99
+ end.to raise_error(ClosureTree::MultipleRootError)
100
+ end
101
+ end
102
+ end
103
+
104
+ context "with explicit class_name and foreign_key" do
105
+ let(:group) { Grouping.create!(name: "TheGrouping") }
106
+
107
+ it "should still work" do
108
+ root = group_reloaded.root_person_including_tree(contracts: :contract_type)
109
+ expect(root.children[0].email).to eq "2@example.com"
110
+ end
111
+ end
112
+
113
+ context "with bad class_name" do
114
+ let(:group) { UserSet.create!(name: "TheUserSet") }
115
+
116
+ it "should error" do
117
+ expect do
118
+ root = group_reloaded.root_user_including_tree(contracts: :contract_type)
119
+ end.to raise_error(NameError)
120
+ end
121
+ end
122
+
123
+ context "with bad foreign_key" do
124
+ let(:group) { Team.create!(name: "TheTeam") }
125
+
126
+ it "should error" do
127
+ expect do
128
+ root = group_reloaded.root_user_including_tree(contracts: :contract_type)
129
+ end.to raise_error(ActiveRecord::StatementInvalid)
130
+ end
131
+ end
132
+ end
File without changes
data/spec/label_spec.rb CHANGED
File without changes
data/spec/matcher_spec.rb CHANGED
File without changes
data/spec/metal_spec.rb CHANGED
File without changes
data/spec/model_spec.rb CHANGED
File without changes
File without changes
File without changes
data/spec/spec_helper.rb CHANGED
File without changes
File without changes
File without changes
@@ -0,0 +1,18 @@
1
+ # Derived from http://stackoverflow.com/a/13423584/153896. Updated for RSpec 3.
2
+ RSpec::Matchers.define :exceed_query_limit do |expected|
3
+ supports_block_expectations
4
+
5
+ match do |block|
6
+ query_count(&block) > expected
7
+ end
8
+
9
+ failure_message_when_negated do |actual|
10
+ "Expected to run maximum #{expected} queries, got #{@counter.query_count}"
11
+ end
12
+
13
+ def query_count(&block)
14
+ @counter = ActiveRecord::QueryCounter.new
15
+ ActiveSupport::Notifications.subscribed(@counter.to_proc, 'sql.active_record', &block)
16
+ @counter.query_count
17
+ end
18
+ end
File without changes
@@ -0,0 +1,18 @@
1
+ # From http://stackoverflow.com/a/13423584/153896
2
+ module ActiveRecord
3
+ class QueryCounter
4
+ attr_reader :query_count
5
+
6
+ def initialize
7
+ @query_count = 0
8
+ end
9
+
10
+ def to_proc
11
+ lambda(&method(:callback))
12
+ end
13
+
14
+ def callback(name, start, finish, message_id, values)
15
+ @query_count += 1 unless %w(CACHE SCHEMA).include?(values[:name])
16
+ end
17
+ end
18
+ end
File without changes
data/spec/support_spec.rb CHANGED
File without changes
data/spec/tag_examples.rb CHANGED
File without changes
data/spec/tag_spec.rb CHANGED
File without changes
data/spec/user_spec.rb CHANGED
File without changes
File without changes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: closure_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.1.0
4
+ version: 6.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew McEachen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-22 00:00:00.000000000 Z
11
+ date: 2016-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -154,6 +154,7 @@ files:
154
154
  - lib/closure_tree/digraphs.rb
155
155
  - lib/closure_tree/finders.rb
156
156
  - lib/closure_tree/has_closure_tree.rb
157
+ - lib/closure_tree/has_closure_tree_root.rb
157
158
  - lib/closure_tree/hash_tree.rb
158
159
  - lib/closure_tree/hash_tree_support.rb
159
160
  - lib/closure_tree/hierarchy_maintenance.rb
@@ -177,6 +178,7 @@ files:
177
178
  - spec/db/schema.rb
178
179
  - spec/fixtures/tags.yml
179
180
  - spec/generators/migration_generator_spec.rb
181
+ - spec/has_closure_tree_root_spec.rb
180
182
  - spec/hierarchy_maintenance_spec.rb
181
183
  - spec/label_spec.rb
182
184
  - spec/matcher_spec.rb
@@ -187,7 +189,9 @@ files:
187
189
  - spec/spec_helper.rb
188
190
  - spec/support/database.rb
189
191
  - spec/support/database_cleaner.rb
192
+ - spec/support/exceed_query_limit.rb
190
193
  - spec/support/hash_monkey_patch.rb
194
+ - spec/support/query_counter.rb
191
195
  - spec/support/sqlite3_with_advisory_lock.rb
192
196
  - spec/support_spec.rb
193
197
  - spec/tag_examples.rb
@@ -227,6 +231,7 @@ test_files:
227
231
  - spec/db/schema.rb
228
232
  - spec/fixtures/tags.yml
229
233
  - spec/generators/migration_generator_spec.rb
234
+ - spec/has_closure_tree_root_spec.rb
230
235
  - spec/hierarchy_maintenance_spec.rb
231
236
  - spec/label_spec.rb
232
237
  - spec/matcher_spec.rb
@@ -237,7 +242,9 @@ test_files:
237
242
  - spec/spec_helper.rb
238
243
  - spec/support/database.rb
239
244
  - spec/support/database_cleaner.rb
245
+ - spec/support/exceed_query_limit.rb
240
246
  - spec/support/hash_monkey_patch.rb
247
+ - spec/support/query_counter.rb
241
248
  - spec/support/sqlite3_with_advisory_lock.rb
242
249
  - spec/support_spec.rb
243
250
  - spec/tag_examples.rb