closure_tree 6.4.0 → 7.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.travis.yml +19 -12
  4. data/Appraisals +75 -7
  5. data/CHANGELOG.md +92 -39
  6. data/Gemfile +0 -12
  7. data/README.md +67 -24
  8. data/_config.yml +1 -0
  9. data/closure_tree.gemspec +10 -7
  10. data/lib/closure_tree/finders.rb +32 -9
  11. data/lib/closure_tree/has_closure_tree.rb +4 -0
  12. data/lib/closure_tree/has_closure_tree_root.rb +4 -6
  13. data/lib/closure_tree/hash_tree_support.rb +4 -4
  14. data/lib/closure_tree/hierarchy_maintenance.rb +31 -11
  15. data/lib/closure_tree/model.rb +42 -16
  16. data/lib/closure_tree/numeric_deterministic_ordering.rb +20 -6
  17. data/lib/closure_tree/numeric_order_support.rb +7 -3
  18. data/lib/closure_tree/support.rb +18 -12
  19. data/lib/closure_tree/support_attributes.rb +10 -1
  20. data/lib/closure_tree/support_flags.rb +1 -4
  21. data/lib/closure_tree/version.rb +1 -1
  22. data/lib/generators/closure_tree/migration_generator.rb +8 -0
  23. data/lib/generators/closure_tree/templates/create_hierarchies_table.rb.erb +1 -1
  24. metadata +29 -75
  25. data/gemfiles/activerecord_4.2.gemfile +0 -19
  26. data/gemfiles/activerecord_5.0.gemfile +0 -19
  27. data/gemfiles/activerecord_5.0_foreigner.gemfile +0 -20
  28. data/gemfiles/activerecord_edge.gemfile +0 -20
  29. data/img/example.png +0 -0
  30. data/img/preorder.png +0 -0
  31. data/spec/cache_invalidation_spec.rb +0 -39
  32. data/spec/cuisine_type_spec.rb +0 -38
  33. data/spec/db/database.yml +0 -21
  34. data/spec/db/models.rb +0 -128
  35. data/spec/db/schema.rb +0 -166
  36. data/spec/fixtures/tags.yml +0 -98
  37. data/spec/generators/migration_generator_spec.rb +0 -48
  38. data/spec/has_closure_tree_root_spec.rb +0 -154
  39. data/spec/hierarchy_maintenance_spec.rb +0 -16
  40. data/spec/label_spec.rb +0 -554
  41. data/spec/matcher_spec.rb +0 -34
  42. data/spec/metal_spec.rb +0 -55
  43. data/spec/model_spec.rb +0 -9
  44. data/spec/namespace_type_spec.rb +0 -13
  45. data/spec/parallel_spec.rb +0 -159
  46. data/spec/spec_helper.rb +0 -24
  47. data/spec/support/database.rb +0 -52
  48. data/spec/support/database_cleaner.rb +0 -14
  49. data/spec/support/exceed_query_limit.rb +0 -18
  50. data/spec/support/hash_monkey_patch.rb +0 -13
  51. data/spec/support/query_counter.rb +0 -18
  52. data/spec/support/sqlite3_with_advisory_lock.rb +0 -10
  53. data/spec/support_spec.rb +0 -14
  54. data/spec/tag_examples.rb +0 -665
  55. data/spec/tag_spec.rb +0 -6
  56. data/spec/user_spec.rb +0 -174
  57. data/spec/uuid_tag_spec.rb +0 -6
@@ -20,7 +20,7 @@ module ClosureTree
20
20
  end
21
21
 
22
22
  def _ct_validate
23
- if !@_ct_skip_cycle_detection &&
23
+ if !(defined? @_ct_skip_cycle_detection) &&
24
24
  !new_record? && # don't validate for cycles if we're a new record
25
25
  changes[_ct.parent_column_name] && # don't validate for cycles if we didn't change our parent
26
26
  parent.present? && # don't validate if we're root
@@ -35,10 +35,13 @@ module ClosureTree
35
35
  end
36
36
 
37
37
  def _ct_after_save
38
- if changes[_ct.parent_column_name] || @was_new_record
38
+ as_5_1 = ActiveSupport.version >= Gem::Version.new('5.1.0')
39
+ changes_method = as_5_1 ? :saved_changes : :changes
40
+
41
+ if public_send(changes_method)[_ct.parent_column_name] || @was_new_record
39
42
  rebuild!
40
43
  end
41
- if changes[_ct.parent_column_name] && !@was_new_record
44
+ if public_send(changes_method)[_ct.parent_column_name] && !@was_new_record
42
45
  # Resetting the ancestral collections addresses
43
46
  # https://github.com/mceachen/closure_tree/issues/68
44
47
  ancestor_hierarchies.reload
@@ -53,7 +56,7 @@ module ClosureTree
53
56
  _ct.with_advisory_lock do
54
57
  delete_hierarchy_references
55
58
  if _ct.options[:dependent] == :nullify
56
- self.class.find(self.id).children.each { |c| c.rebuild! }
59
+ self.class.find(self.id).children.find_each { |c| c.rebuild! }
57
60
  end
58
61
  end
59
62
  true # don't prevent destruction
@@ -61,10 +64,10 @@ module ClosureTree
61
64
 
62
65
  def rebuild!(called_by_rebuild = false)
63
66
  _ct.with_advisory_lock do
64
- delete_hierarchy_references unless @was_new_record
67
+ delete_hierarchy_references unless (defined? @was_new_record) && @was_new_record
65
68
  hierarchy_class.create!(:ancestor => self, :descendant => self, :generations => 0)
66
69
  unless root?
67
- _ct.connection.execute <<-SQL.strip_heredoc
70
+ _ct.connection.execute <<-SQL.squish
68
71
  INSERT INTO #{_ct.quoted_hierarchy_table_name}
69
72
  (ancestor_id, descendant_id, generations)
70
73
  SELECT x.ancestor_id, #{_ct.quote(_ct_id)}, x.generations + 1
@@ -79,7 +82,7 @@ module ClosureTree
79
82
  _ct_reorder_siblings if !called_by_rebuild
80
83
  end
81
84
 
82
- children.each { |c| c.rebuild!(true) }
85
+ children.find_each { |c| c.rebuild!(true) }
83
86
 
84
87
  _ct_reorder_children if _ct.order_is_numeric? && children.present?
85
88
  end
@@ -91,7 +94,7 @@ module ClosureTree
91
94
  # It shouldn't affect performance of postgresql.
92
95
  # See http://dev.mysql.com/doc/refman/5.0/en/subquery-errors.html
93
96
  # Also: PostgreSQL doesn't support INNER JOIN on DELETE, so we can't use that.
94
- _ct.connection.execute <<-SQL.strip_heredoc
97
+ _ct.connection.execute <<-SQL.squish
95
98
  DELETE FROM #{_ct.quoted_hierarchy_table_name}
96
99
  WHERE descendant_id IN (
97
100
  SELECT DISTINCT descendant_id
@@ -99,7 +102,7 @@ module ClosureTree
99
102
  FROM #{_ct.quoted_hierarchy_table_name}
100
103
  WHERE ancestor_id = #{_ct.quote(id)}
101
104
  OR descendant_id = #{_ct.quote(id)}
102
- ) AS x )
105
+ ) #{ _ct.t_alias_keyword } x )
103
106
  SQL
104
107
  end
105
108
  end
@@ -109,11 +112,28 @@ module ClosureTree
109
112
  # Note that the hierarchy table will be truncated.
110
113
  def rebuild!
111
114
  _ct.with_advisory_lock do
112
- hierarchy_class.delete_all # not destroy_all -- we just want a simple truncate.
113
- roots.each { |n| n.send(:rebuild!) } # roots just uses the parent_id column, so this is safe.
115
+ cleanup!
116
+ roots.find_each { |n| n.send(:rebuild!) } # roots just uses the parent_id column, so this is safe.
114
117
  end
115
118
  nil
116
119
  end
120
+
121
+ def cleanup!
122
+ hierarchy_table = hierarchy_class.arel_table
123
+
124
+ [:descendant_id, :ancestor_id].each do |foreign_key|
125
+ alias_name = foreign_key.to_s.split('_').first + "s"
126
+ alias_table = Arel::Table.new(table_name).alias(alias_name)
127
+ arel_join = hierarchy_table.join(alias_table, Arel::Nodes::OuterJoin)
128
+ .on(alias_table[primary_key].eq(hierarchy_table[foreign_key]))
129
+ .join_sources
130
+
131
+ lonely_childs = hierarchy_class.joins(arel_join).where(alias_table[primary_key].eq(nil))
132
+ ids = lonely_childs.pluck(foreign_key)
133
+
134
+ hierarchy_class.where(hierarchy_table[foreign_key].in(ids)).delete_all
135
+ end
136
+ end
117
137
  end
118
138
  end
119
139
  end
@@ -6,20 +6,20 @@ module ClosureTree
6
6
 
7
7
  included do
8
8
 
9
- belongs_to :parent, nil, *_ct.belongs_to_with_optional_option(
9
+ belongs_to :parent, nil, **_ct.belongs_to_with_optional_option(
10
10
  class_name: _ct.model_class.to_s,
11
11
  foreign_key: _ct.parent_column_name,
12
12
  inverse_of: :children,
13
13
  touch: _ct.options[:touch],
14
14
  optional: true)
15
15
 
16
- order_by_generations = "#{_ct.quoted_hierarchy_table_name}.generations asc"
16
+ order_by_generations = -> { Arel.sql("#{_ct.quoted_hierarchy_table_name}.generations ASC") }
17
17
 
18
- has_many :children, *_ct.has_many_with_order_option(
18
+ has_many :children, *_ct.has_many_order_with_option, **{
19
19
  class_name: _ct.model_class.to_s,
20
20
  foreign_key: _ct.parent_column_name,
21
21
  dependent: _ct.options[:dependent],
22
- inverse_of: :parent) do
22
+ inverse_of: :parent } do
23
23
  # We have to redefine hash_tree because the activerecord relation is already scoped to parent_id.
24
24
  def hash_tree(options = {})
25
25
  # we want limit_depth + 1 because we don't do self_and_descendants.
@@ -28,25 +28,21 @@ module ClosureTree
28
28
  end
29
29
  end
30
30
 
31
- has_many :ancestor_hierarchies, *_ct.has_many_without_order_option(
31
+ has_many :ancestor_hierarchies, *_ct.has_many_order_without_option(order_by_generations),
32
32
  class_name: _ct.hierarchy_class_name,
33
- foreign_key: 'descendant_id',
34
- order: order_by_generations)
33
+ foreign_key: 'descendant_id'
35
34
 
36
- has_many :self_and_ancestors, *_ct.has_many_without_order_option(
35
+ has_many :self_and_ancestors, *_ct.has_many_order_without_option(order_by_generations),
37
36
  through: :ancestor_hierarchies,
38
- source: :ancestor,
39
- order: order_by_generations)
37
+ source: :ancestor
40
38
 
41
- has_many :descendant_hierarchies, *_ct.has_many_without_order_option(
39
+ has_many :descendant_hierarchies, *_ct.has_many_order_without_option(order_by_generations),
42
40
  class_name: _ct.hierarchy_class_name,
43
- foreign_key: 'ancestor_id',
44
- order: order_by_generations)
41
+ foreign_key: 'ancestor_id'
45
42
 
46
- has_many :self_and_descendants, *_ct.has_many_with_order_option(
43
+ has_many :self_and_descendants, *_ct.has_many_order_with_option(order_by_generations),
47
44
  through: :descendant_hierarchies,
48
- source: :descendant,
49
- order: order_by_generations)
45
+ source: :descendant
50
46
  end
51
47
 
52
48
  # Delegate to the Support instance on the class:
@@ -134,6 +130,36 @@ module ClosureTree
134
130
  _ct.ids_from(siblings)
135
131
  end
136
132
 
133
+ # node's parent is this record
134
+ def parent_of?(node)
135
+ self == node.parent
136
+ end
137
+
138
+ # node's root is this record
139
+ def root_of?(node)
140
+ self == node.root
141
+ end
142
+
143
+ # node's ancestors include this record
144
+ def ancestor_of?(node)
145
+ node.ancestors.include? self
146
+ end
147
+
148
+ # node is record's ancestor
149
+ def descendant_of?(node)
150
+ self.ancestors.include? node
151
+ end
152
+
153
+ # node is record's parent
154
+ def child_of?(node)
155
+ self.parent == node
156
+ end
157
+
158
+ # node and record have a same root
159
+ def family_of?(node)
160
+ self.root == node.root
161
+ end
162
+
137
163
  # Alias for appending to the children collection.
138
164
  # You can also add directly to the children collection, if you'd prefer.
139
165
  def add_child(child_node)
@@ -10,8 +10,13 @@ module ClosureTree
10
10
  end
11
11
 
12
12
  def _ct_reorder_prior_siblings_if_parent_changed
13
- if attribute_changed?(_ct.parent_column_name) && !@was_new_record
14
- was_parent_id = attribute_was(_ct.parent_column_name)
13
+ as_5_1 = ActiveSupport.version >= Gem::Version.new('5.1.0')
14
+ change_method = as_5_1 ? :saved_change_to_attribute? : :attribute_changed?
15
+
16
+ if public_send(change_method, _ct.parent_column_name) && !@was_new_record
17
+ attribute_method = as_5_1 ? :attribute_before_last_save : :attribute_was
18
+
19
+ was_parent_id = public_send(attribute_method, _ct.parent_column_name)
15
20
  _ct.reorder_with_parent_id(was_parent_id)
16
21
  end
17
22
  end
@@ -46,7 +51,7 @@ module ClosureTree
46
51
 
47
52
  # If node is nil, order the whole tree.
48
53
  def _ct_sum_order_by(node = nil)
49
- stats_sql = <<-SQL.strip_heredoc
54
+ stats_sql = <<-SQL.squish
50
55
  SELECT
51
56
  count(*) as total_descendants,
52
57
  max(generations) as max_depth
@@ -60,11 +65,16 @@ module ClosureTree
60
65
  node_score = "(1 + anc.#{_ct.quoted_order_column(false)}) * " +
61
66
  "power(#{h['total_descendants']}, #{h['max_depth'].to_i + 1} - #{depth_column})"
62
67
 
63
- "sum(#{node_score})"
68
+ # We want the NULLs to be first in case we are not ordering roots and they have NULL order.
69
+ Arel.sql("SUM(#{node_score}) IS NULL DESC, SUM(#{node_score})")
64
70
  end
65
71
 
66
72
  def roots_and_descendants_preordered
67
- join_sql = <<-SQL.strip_heredoc
73
+ if _ct.dont_order_roots
74
+ raise ClosureTree::RootOrderingDisabledError.new("Root ordering is disabled on this model")
75
+ end
76
+
77
+ join_sql = <<-SQL.squish
68
78
  JOIN #{_ct.quoted_hierarchy_table_name} anc_hier
69
79
  ON anc_hier.descendant_id = #{_ct.quoted_table_name}.#{_ct.quoted_id_column_name}
70
80
  JOIN #{_ct.quoted_table_name} anc
@@ -73,7 +83,7 @@ module ClosureTree
73
83
  SELECT descendant_id, max(generations) AS max_depth
74
84
  FROM #{_ct.quoted_hierarchy_table_name}
75
85
  GROUP BY descendant_id
76
- ) AS depths ON depths.descendant_id = anc.#{_ct.quoted_id_column_name}
86
+ ) #{ _ct.t_alias_keyword } depths ON depths.descendant_id = anc.#{_ct.quoted_id_column_name}
77
87
  SQL
78
88
  joins(join_sql)
79
89
  .group("#{_ct.quoted_table_name}.#{_ct.quoted_id_column_name}")
@@ -108,6 +118,10 @@ module ClosureTree
108
118
  def add_sibling(sibling, add_after = true)
109
119
  fail "can't add self as sibling" if self == sibling
110
120
 
121
+ if _ct.dont_order_roots && parent.nil?
122
+ raise ClosureTree::RootOrderingDisabledError.new("Root ordering is disabled on this model")
123
+ end
124
+
111
125
  # Make sure self isn't dirty, because we're going to call reload:
112
126
  save
113
127
 
@@ -14,13 +14,14 @@ module ClosureTree
14
14
 
15
15
  module MysqlAdapter
16
16
  def reorder_with_parent_id(parent_id, minimum_sort_order_value = nil)
17
+ return if parent_id.nil? && dont_order_roots
17
18
  min_where = if minimum_sort_order_value
18
19
  "AND #{quoted_order_column} >= #{minimum_sort_order_value}"
19
20
  else
20
21
  ""
21
22
  end
22
23
  connection.execute 'SET @i = 0'
23
- connection.execute <<-SQL.strip_heredoc
24
+ connection.execute <<-SQL.squish
24
25
  UPDATE #{quoted_table_name}
25
26
  SET #{quoted_order_column} = (@i := @i + 1) + #{minimum_sort_order_value.to_i - 1}
26
27
  WHERE #{where_eq(parent_column_name, parent_id)} #{min_where}
@@ -31,12 +32,13 @@ module ClosureTree
31
32
 
32
33
  module PostgreSQLAdapter
33
34
  def reorder_with_parent_id(parent_id, minimum_sort_order_value = nil)
35
+ return if parent_id.nil? && dont_order_roots
34
36
  min_where = if minimum_sort_order_value
35
37
  "AND #{quoted_order_column} >= #{minimum_sort_order_value}"
36
38
  else
37
39
  ""
38
40
  end
39
- connection.execute <<-SQL.strip_heredoc
41
+ connection.execute <<-SQL.squish
40
42
  UPDATE #{quoted_table_name}
41
43
  SET #{quoted_order_column(false)} = t.seq + #{minimum_sort_order_value.to_i - 1}
42
44
  FROM (
@@ -44,7 +46,8 @@ module ClosureTree
44
46
  FROM #{quoted_table_name}
45
47
  WHERE #{where_eq(parent_column_name, parent_id)} #{min_where}
46
48
  ) AS t
47
- WHERE #{quoted_table_name}.#{quoted_id_column_name} = t.id
49
+ WHERE #{quoted_table_name}.#{quoted_id_column_name} = t.id and
50
+ #{quoted_table_name}.#{quoted_order_column(false)} is distinct from t.seq + #{minimum_sort_order_value.to_i - 1}
48
51
  SQL
49
52
  end
50
53
 
@@ -55,6 +58,7 @@ module ClosureTree
55
58
 
56
59
  module GenericAdapter
57
60
  def reorder_with_parent_id(parent_id, minimum_sort_order_value = nil)
61
+ return if parent_id.nil? && dont_order_roots
58
62
  scope = model_class.
59
63
  where(parent_column_sym => parent_id).
60
64
  order(nulls_last_order_by)
@@ -22,7 +22,8 @@ module ClosureTree
22
22
  :parent_column_name => 'parent_id',
23
23
  :dependent => :nullify, # or :destroy or :delete_all -- see the README
24
24
  :name_column => 'name',
25
- :with_advisory_lock => true
25
+ :with_advisory_lock => true,
26
+ :numeric_order => false
26
27
  }.merge(options)
27
28
  raise ArgumentError, "name_column can't be 'path'" if options[:name_column] == 'path'
28
29
  if order_is_numeric?
@@ -31,13 +32,15 @@ module ClosureTree
31
32
  end
32
33
 
33
34
  def hierarchy_class_for_model
34
- hierarchy_class = model_class.parent.const_set(short_hierarchy_class_name, Class.new(ActiveRecord::Base))
35
+ parent_class = ActiveSupport::VERSION::MAJOR >= 6 ? model_class.module_parent : model_class.parent
36
+ hierarchy_class = parent_class.const_set(short_hierarchy_class_name, Class.new(ActiveRecord::Base))
35
37
  use_attr_accessible = use_attr_accessible?
36
38
  include_forbidden_attributes_protection = include_forbidden_attributes_protection?
37
- hierarchy_class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
39
+ model_class_name = model_class.to_s
40
+ hierarchy_class.class_eval do
38
41
  include ActiveModel::ForbiddenAttributesProtection if include_forbidden_attributes_protection
39
- belongs_to :ancestor, :class_name => "#{model_class}"
40
- belongs_to :descendant, :class_name => "#{model_class}"
42
+ belongs_to :ancestor, class_name: model_class_name
43
+ belongs_to :descendant, class_name: model_class_name
41
44
  attr_accessible :ancestor, :descendant, :generations if use_attr_accessible
42
45
  def ==(other)
43
46
  self.class == other.class && ancestor_id == other.ancestor_id && descendant_id == other.descendant_id
@@ -46,7 +49,7 @@ module ClosureTree
46
49
  def hash
47
50
  ancestor_id.hash << 31 ^ descendant_id.hash
48
51
  end
49
- RUBY
52
+ end
50
53
  hierarchy_class.table_name = hierarchy_table_name
51
54
  hierarchy_class
52
55
  end
@@ -77,17 +80,20 @@ module ClosureTree
77
80
  end
78
81
 
79
82
  def belongs_to_with_optional_option(opts)
80
- [ActiveRecord::VERSION::MAJOR < 5 ? opts.except(:optional) : opts]
83
+ ActiveRecord::VERSION::MAJOR < 5 ? opts.except(:optional) : opts
81
84
  end
82
85
 
83
86
  # lambda-ize the order, but don't apply the default order_option
84
- def has_many_without_order_option(opts)
85
- [lambda { order(opts[:order]) }, opts.except(:order)]
87
+ def has_many_order_without_option(order_by_opt)
88
+ [lambda { order(order_by_opt.call) }]
86
89
  end
87
90
 
88
- def has_many_with_order_option(opts)
89
- order_options = [opts[:order], order_by].compact
90
- [lambda { order(order_options) }, opts.except(:order)]
91
+ def has_many_order_with_option(order_by_opt=nil)
92
+ order_options = [order_by_opt, order_by].compact
93
+ [lambda {
94
+ order_options = order_options.map { |o| o.is_a?(Proc) ? o.call : o }
95
+ order(order_options)
96
+ }]
91
97
  end
92
98
 
93
99
  def ids_from(scope)
@@ -75,8 +75,12 @@ module ClosureTree
75
75
  options[:order]
76
76
  end
77
77
 
78
+ def dont_order_roots
79
+ options[:dont_order_roots] || false
80
+ end
81
+
78
82
  def nulls_last_order_by
79
- "-#{quoted_order_column} #{order_by_order(reverse = true)}"
83
+ Arel.sql "-#{quoted_order_column} #{order_by_order(true)}"
80
84
  end
81
85
 
82
86
  def order_by_order(reverse = false)
@@ -110,5 +114,10 @@ module ClosureTree
110
114
  prefix = include_table_name ? "#{quoted_table_name}." : ""
111
115
  "#{prefix}#{connection.quote_column_name(order_column)}"
112
116
  end
117
+
118
+ # table_name alias keyword , like "AS". When used on table name alias, Oracle Database don't support used 'AS'
119
+ def t_alias_keyword
120
+ (ActiveRecord::Base.connection.adapter_name.to_sym == :OracleEnhanced) ? "" : "AS"
121
+ end
113
122
  end
114
123
  end
@@ -17,10 +17,7 @@ module ClosureTree
17
17
  end
18
18
 
19
19
  def order_is_numeric?
20
- # The table might not exist yet (in the case of ActiveRecord::Observer use, see issue 32)
21
- return false if !order_option? || !model_class.table_exists?
22
- c = model_class.columns_hash[order_column]
23
- c && c.type == :integer
20
+ options[:numeric_order]
24
21
  end
25
22
 
26
23
  def subclass?
@@ -1,3 +1,3 @@
1
1
  module ClosureTree
2
- VERSION = Gem::Version.new('6.4.0')
2
+ VERSION = Gem::Version.new('7.2.0')
3
3
  end
@@ -1,5 +1,6 @@
1
1
  require 'closure_tree/active_record_support'
2
2
  require 'forwardable'
3
+ require 'rails/generators'
3
4
  require 'rails/generators/active_record'
4
5
  require 'rails/generators/named_base'
5
6
 
@@ -41,6 +42,13 @@ module ClosureTree
41
42
  end
42
43
  end
43
44
 
45
+ def migration_version
46
+ major = ActiveRecord::VERSION::MAJOR
47
+ if major >= 5
48
+ "[#{major}.#{ActiveRecord::VERSION::MINOR}]"
49
+ end
50
+ end
51
+
44
52
  def self.next_migration_number(dirname)
45
53
  ActiveRecord::Generators::Base.next_migration_number(dirname)
46
54
  end
@@ -1,4 +1,4 @@
1
- class <%= migration_class_name %> < ActiveRecord::Migration
1
+ class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version %>
2
2
  def change
3
3
  create_table :<%= migration_name %>, id: false do |t|
4
4
  t.<%= primary_key_type %> :ancestor_id, null: false
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.4.0
4
+ version: 7.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: 2017-02-17 00:00:00.000000000 Z
11
+ date: 2020-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,30 +16,30 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 4.1.0
19
+ version: 4.2.10
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 4.1.0
26
+ version: 4.2.10
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: with_advisory_lock
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 3.0.0
33
+ version: 4.0.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 3.0.0
40
+ version: 4.0.0
41
41
  - !ruby/object:Gem::Dependency
42
- name: rspec-instafail
42
+ name: appraisal
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rspec-rails
56
+ name: database_cleaner
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: database_cleaner
70
+ name: generator_spec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: appraisal
84
+ name: parallel
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: timecop
98
+ name: rspec-instafail
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -109,7 +109,21 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: parallel
112
+ name: rspec-rails
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: timecop
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
129
  - - ">="
@@ -139,13 +153,8 @@ files:
139
153
  - MIT-LICENSE
140
154
  - README.md
141
155
  - Rakefile
156
+ - _config.yml
142
157
  - closure_tree.gemspec
143
- - gemfiles/activerecord_4.2.gemfile
144
- - gemfiles/activerecord_5.0.gemfile
145
- - gemfiles/activerecord_5.0_foreigner.gemfile
146
- - gemfiles/activerecord_edge.gemfile
147
- - img/example.png
148
- - img/preorder.png
149
158
  - lib/closure_tree.rb
150
159
  - lib/closure_tree/active_record_support.rb
151
160
  - lib/closure_tree/configuration.rb
@@ -170,33 +179,6 @@ files:
170
179
  - lib/generators/closure_tree/templates/config.rb
171
180
  - lib/generators/closure_tree/templates/create_hierarchies_table.rb.erb
172
181
  - mktree.rb
173
- - spec/cache_invalidation_spec.rb
174
- - spec/cuisine_type_spec.rb
175
- - spec/db/database.yml
176
- - spec/db/models.rb
177
- - spec/db/schema.rb
178
- - spec/fixtures/tags.yml
179
- - spec/generators/migration_generator_spec.rb
180
- - spec/has_closure_tree_root_spec.rb
181
- - spec/hierarchy_maintenance_spec.rb
182
- - spec/label_spec.rb
183
- - spec/matcher_spec.rb
184
- - spec/metal_spec.rb
185
- - spec/model_spec.rb
186
- - spec/namespace_type_spec.rb
187
- - spec/parallel_spec.rb
188
- - spec/spec_helper.rb
189
- - spec/support/database.rb
190
- - spec/support/database_cleaner.rb
191
- - spec/support/exceed_query_limit.rb
192
- - spec/support/hash_monkey_patch.rb
193
- - spec/support/query_counter.rb
194
- - spec/support/sqlite3_with_advisory_lock.rb
195
- - spec/support_spec.rb
196
- - spec/tag_examples.rb
197
- - spec/tag_spec.rb
198
- - spec/user_spec.rb
199
- - spec/uuid_tag_spec.rb
200
182
  - tests.sh
201
183
  homepage: http://mceachen.github.io/closure_tree/
202
184
  licenses:
@@ -217,36 +199,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
217
199
  - !ruby/object:Gem::Version
218
200
  version: '0'
219
201
  requirements: []
220
- rubyforge_project:
221
- rubygems_version: 2.5.1
202
+ rubygems_version: 3.0.3
222
203
  signing_key:
223
204
  specification_version: 4
224
205
  summary: Easily and efficiently make your ActiveRecord model support hierarchies
225
- test_files:
226
- - spec/cache_invalidation_spec.rb
227
- - spec/cuisine_type_spec.rb
228
- - spec/db/database.yml
229
- - spec/db/models.rb
230
- - spec/db/schema.rb
231
- - spec/fixtures/tags.yml
232
- - spec/generators/migration_generator_spec.rb
233
- - spec/has_closure_tree_root_spec.rb
234
- - spec/hierarchy_maintenance_spec.rb
235
- - spec/label_spec.rb
236
- - spec/matcher_spec.rb
237
- - spec/metal_spec.rb
238
- - spec/model_spec.rb
239
- - spec/namespace_type_spec.rb
240
- - spec/parallel_spec.rb
241
- - spec/spec_helper.rb
242
- - spec/support/database.rb
243
- - spec/support/database_cleaner.rb
244
- - spec/support/exceed_query_limit.rb
245
- - spec/support/hash_monkey_patch.rb
246
- - spec/support/query_counter.rb
247
- - spec/support/sqlite3_with_advisory_lock.rb
248
- - spec/support_spec.rb
249
- - spec/tag_examples.rb
250
- - spec/tag_spec.rb
251
- - spec/user_spec.rb
252
- - spec/uuid_tag_spec.rb
206
+ test_files: []