dagnabit 2.2.6 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.md +105 -0
- data/LICENSE +1 -1
- data/MIGRATION.md +56 -0
- data/README.md +222 -0
- data/bin/dagnabit-test +11 -31
- data/db/connection.rb +3 -0
- data/{test/connections/native_postgresql → db/connections/postgresql}/connection.rb +6 -5
- data/db/models/edge.rb +6 -0
- data/db/models/other_edge.rb +6 -0
- data/db/models/other_vertex.rb +6 -0
- data/db/models/vertex.rb +6 -0
- data/db/schema.rb +32 -0
- data/lib/dagnabit.rb +6 -19
- data/lib/dagnabit/edge.rb +7 -0
- data/lib/dagnabit/edge/activation.rb +14 -0
- data/lib/dagnabit/edge/associations.rb +10 -0
- data/lib/dagnabit/edge/connectivity.rb +38 -0
- data/lib/dagnabit/graph.rb +143 -0
- data/lib/dagnabit/migration.rb +98 -0
- data/lib/dagnabit/version.rb +3 -0
- data/lib/dagnabit/vertex.rb +10 -0
- data/lib/dagnabit/vertex/activation.rb +19 -0
- data/lib/dagnabit/vertex/associations.rb +24 -0
- data/lib/dagnabit/vertex/bonding.rb +43 -0
- data/lib/dagnabit/vertex/connectivity.rb +130 -0
- data/lib/dagnabit/vertex/neighbors.rb +50 -0
- data/lib/dagnabit/vertex/settings.rb +56 -0
- metadata +94 -143
- data/.autotest +0 -5
- data/.document +0 -5
- data/.gitignore +0 -7
- data/Gemfile +0 -15
- data/Gemfile.lock +0 -38
- data/History.txt +0 -81
- data/README.rdoc +0 -202
- data/Rakefile +0 -52
- data/VERSION.yml +0 -5
- data/dagnabit.gemspec +0 -142
- data/init.rb +0 -1
- data/lib/dagnabit/activation.rb +0 -60
- data/lib/dagnabit/link/associations.rb +0 -18
- data/lib/dagnabit/link/class_methods.rb +0 -43
- data/lib/dagnabit/link/configuration.rb +0 -40
- data/lib/dagnabit/link/cycle_prevention.rb +0 -31
- data/lib/dagnabit/link/named_scopes.rb +0 -65
- data/lib/dagnabit/link/transitive_closure_link_model.rb +0 -86
- data/lib/dagnabit/link/transitive_closure_recalculation.rb +0 -17
- data/lib/dagnabit/link/transitive_closure_recalculation/on_create.rb +0 -104
- data/lib/dagnabit/link/transitive_closure_recalculation/on_destroy.rb +0 -125
- data/lib/dagnabit/link/transitive_closure_recalculation/on_update.rb +0 -17
- data/lib/dagnabit/link/transitive_closure_recalculation/utilities.rb +0 -56
- data/lib/dagnabit/link/validations.rb +0 -26
- data/lib/dagnabit/node/associations.rb +0 -84
- data/lib/dagnabit/node/class_methods.rb +0 -74
- data/lib/dagnabit/node/configuration.rb +0 -26
- data/lib/dagnabit/node/neighbors.rb +0 -73
- data/test/connections/native_sqlite3/connection.rb +0 -24
- data/test/dagnabit/link/test_associations.rb +0 -61
- data/test/dagnabit/link/test_class_methods.rb +0 -102
- data/test/dagnabit/link/test_configuration.rb +0 -38
- data/test/dagnabit/link/test_cycle_prevention.rb +0 -64
- data/test/dagnabit/link/test_named_scopes.rb +0 -32
- data/test/dagnabit/link/test_transitive_closure_link_model.rb +0 -69
- data/test/dagnabit/link/test_transitive_closure_recalculation.rb +0 -178
- data/test/dagnabit/link/test_validations.rb +0 -39
- data/test/dagnabit/node/test_associations.rb +0 -147
- data/test/dagnabit/node/test_class_methods.rb +0 -49
- data/test/dagnabit/node/test_configuration.rb +0 -29
- data/test/dagnabit/node/test_neighbors.rb +0 -91
- data/test/helper.rb +0 -26
- data/test/models/beta_node.rb +0 -3
- data/test/models/custom_data_link.rb +0 -4
- data/test/models/customized_link.rb +0 -7
- data/test/models/customized_link_node.rb +0 -4
- data/test/models/link.rb +0 -4
- data/test/models/node.rb +0 -3
- data/test/schema/schema.rb +0 -51
@@ -1,24 +0,0 @@
|
|
1
|
-
print "Using native SQLite3\n"
|
2
|
-
|
3
|
-
require 'logger'
|
4
|
-
|
5
|
-
# The SQLite3 Ruby driver can be present as either a gem or directly present in
|
6
|
-
# the Ruby library load path. This load method addresses these two situations.
|
7
|
-
begin
|
8
|
-
require 'sqlite3'
|
9
|
-
rescue LoadError
|
10
|
-
require 'rubygems'
|
11
|
-
gem 'sqlite3-ruby'
|
12
|
-
require 'sqlite3'
|
13
|
-
end
|
14
|
-
|
15
|
-
ActiveRecord::Base.logger = Logger.new("debug.log")
|
16
|
-
|
17
|
-
class SqliteError < StandardError
|
18
|
-
end
|
19
|
-
|
20
|
-
ActiveRecord::Base.configurations = {
|
21
|
-
'ActiveRecord::Base' => { :adapter => 'sqlite3', :database => ':memory:' }
|
22
|
-
};
|
23
|
-
|
24
|
-
ActiveRecord::Base.establish_connection('ActiveRecord::Base')
|
@@ -1,61 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
module Dagnabit
|
4
|
-
module Link
|
5
|
-
class TestAssociations < ActiveRecord::TestCase
|
6
|
-
class Node < ActiveRecord::Base
|
7
|
-
set_table_name 'nodes'
|
8
|
-
end
|
9
|
-
|
10
|
-
class Link < ActiveRecord::Base
|
11
|
-
set_table_name 'edges'
|
12
|
-
extend Dagnabit::Link::Configuration
|
13
|
-
configure_acts_as_dag_link({})
|
14
|
-
extend Dagnabit::Link::Associations
|
15
|
-
end
|
16
|
-
|
17
|
-
class CustomLink < ActiveRecord::Base
|
18
|
-
set_table_name 'other_name_edges'
|
19
|
-
|
20
|
-
extend Dagnabit::Link::Configuration
|
21
|
-
configure_acts_as_dag_link(:ancestor_id_column => 'the_ancestor_id',
|
22
|
-
:descendant_id_column => 'the_descendant_id',
|
23
|
-
:transitive_closure_table_name => 'my_transitive_closure')
|
24
|
-
|
25
|
-
extend Dagnabit::Link::Associations
|
26
|
-
end
|
27
|
-
|
28
|
-
def setup
|
29
|
-
@node = Node.new
|
30
|
-
@link = Link.new
|
31
|
-
@custom_link = CustomLink.new
|
32
|
-
end
|
33
|
-
|
34
|
-
should 'add an ancestor association proxy' do
|
35
|
-
@link.ancestor = @node
|
36
|
-
@link.save
|
37
|
-
assert_equal @node, @link.reload.ancestor
|
38
|
-
end
|
39
|
-
|
40
|
-
should 'add a descendant association proxy' do
|
41
|
-
@link.descendant = @node
|
42
|
-
@link.save
|
43
|
-
assert_equal @node, @link.reload.descendant
|
44
|
-
end
|
45
|
-
|
46
|
-
should 'permit customization of the ancestor association foreign key' do
|
47
|
-
@custom_link.ancestor = @node
|
48
|
-
@custom_link.save
|
49
|
-
@custom_link = CustomLink.find(@custom_link.id)
|
50
|
-
assert_equal @node, @custom_link.ancestor
|
51
|
-
end
|
52
|
-
|
53
|
-
should 'permit customization of the descendant association foreign key' do
|
54
|
-
@custom_link.descendant = @node
|
55
|
-
@custom_link.save
|
56
|
-
@custom_link = CustomLink.find(@custom_link.id)
|
57
|
-
assert_equal @node, @custom_link.descendant
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
@@ -1,102 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
module Dagnabit
|
4
|
-
module Link
|
5
|
-
class TestClassMethods < ActiveRecord::TestCase
|
6
|
-
should 'include a method to build edges' do
|
7
|
-
n1 = ::Node.new
|
8
|
-
n2 = ::Node.new
|
9
|
-
|
10
|
-
link = ::Link.build_edge(n1, n2)
|
11
|
-
assert_equal n1, link.ancestor
|
12
|
-
assert_equal n2, link.descendant
|
13
|
-
end
|
14
|
-
|
15
|
-
should 'permit custom data to be included on edges' do
|
16
|
-
n1 = ::Node.new
|
17
|
-
n2 = ::Node.new
|
18
|
-
|
19
|
-
link = CustomDataLink.build_edge(n1, n2, :data => 'foobar')
|
20
|
-
assert_equal 'foobar', link.data
|
21
|
-
end
|
22
|
-
|
23
|
-
context 'connect' do
|
24
|
-
should 'connect two nodes' do
|
25
|
-
n1 = ::Node.new
|
26
|
-
n2 = ::Node.new
|
27
|
-
|
28
|
-
::Link.connect(n1, n2)
|
29
|
-
link = ::Link.find(:first, :conditions => { :ancestor_id => n1.id, :descendant_id => n2.id })
|
30
|
-
|
31
|
-
assert_not_nil link
|
32
|
-
assert_equal n1, link.ancestor
|
33
|
-
assert_equal n2, link.descendant
|
34
|
-
end
|
35
|
-
|
36
|
-
should 'permit custom data to be included on edges' do
|
37
|
-
n1 = ::Node.new
|
38
|
-
n2 = ::Node.new
|
39
|
-
|
40
|
-
CustomDataLink.connect(n1, n2, :data => 'foobar')
|
41
|
-
link = CustomDataLink.find(:first, :conditions => { :ancestor_id => n1.id, :descendant_id => n2.id })
|
42
|
-
|
43
|
-
assert_equal 'foobar', link.data
|
44
|
-
end
|
45
|
-
|
46
|
-
should 'return false if connection fails due to node invalidity' do
|
47
|
-
n1 = ::Node.new
|
48
|
-
n2 = ::Node.new
|
49
|
-
|
50
|
-
n1.stubs(:valid?).returns(false)
|
51
|
-
|
52
|
-
result = ::Link.connect(n1, n2)
|
53
|
-
assert_equal false, result
|
54
|
-
end
|
55
|
-
|
56
|
-
should 'not save endpoints if connection fails due to node invalidity' do
|
57
|
-
n1 = ::Node.new
|
58
|
-
n2 = ::Node.new
|
59
|
-
|
60
|
-
n1.stubs(:valid?).returns(false)
|
61
|
-
|
62
|
-
::Link.connect(n1, n2)
|
63
|
-
|
64
|
-
assert n1.new_record?
|
65
|
-
assert n2.new_record?
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
context 'path?' do
|
70
|
-
should 'return whether or not a path exists between two nodes' do
|
71
|
-
n1 = ::Node.new
|
72
|
-
n2 = ::Node.new
|
73
|
-
n3 = ::Node.new
|
74
|
-
n4 = ::Node.new
|
75
|
-
|
76
|
-
::Link.connect(n1, n2)
|
77
|
-
::Link.connect(n2, n3)
|
78
|
-
|
79
|
-
assert ::Link.path?(n1, n2)
|
80
|
-
assert ::Link.path?(n1, n3)
|
81
|
-
assert !::Link.path?(n1, n4)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
context 'paths' do
|
86
|
-
should 'return all paths between two nodes' do
|
87
|
-
n1 = ::Node.new
|
88
|
-
n2 = ::Node.new
|
89
|
-
n3 = ::Node.new
|
90
|
-
|
91
|
-
::Link.connect(n1, n2)
|
92
|
-
::Link.connect(n2, n3)
|
93
|
-
|
94
|
-
paths = ::Link.paths(n1, n3)
|
95
|
-
assert_equal 1, paths.length
|
96
|
-
assert_equal n1, paths.first.ancestor
|
97
|
-
assert_equal n3, paths.first.descendant
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
module Dagnabit
|
4
|
-
module Link
|
5
|
-
class TestConfiguration < ActiveRecord::TestCase
|
6
|
-
should 'have default and settable names for transitive closure model and column names' do
|
7
|
-
default_model = Class.new(ActiveRecord::Base) do
|
8
|
-
set_table_name 'edges'
|
9
|
-
|
10
|
-
acts_as_dag_link
|
11
|
-
end
|
12
|
-
|
13
|
-
custom_model = Class.new(ActiveRecord::Base) do
|
14
|
-
set_table_name 'other_name_edges'
|
15
|
-
|
16
|
-
acts_as_dag_link :ancestor_id_column => 'the_ancestor_id',
|
17
|
-
:descendant_id_column => 'the_descendant_id',
|
18
|
-
:transitive_closure_table_name => 'my_transitive_closure',
|
19
|
-
:transitive_closure_class_name => 'MyTransitiveClosureLink'
|
20
|
-
end
|
21
|
-
|
22
|
-
assert_equal 'ancestor_id', default_model.ancestor_id_column
|
23
|
-
assert_equal 'descendant_id', default_model.descendant_id_column
|
24
|
-
assert_equal default_model.connection.quote_table_name('edges_transitive_closure_tuples'), default_model.transitive_closure_table_name
|
25
|
-
assert_equal 'TransitiveClosureLink', default_model.transitive_closure_class_name
|
26
|
-
|
27
|
-
assert_equal 'the_ancestor_id', custom_model.ancestor_id_column
|
28
|
-
assert_equal 'the_descendant_id', custom_model.descendant_id_column
|
29
|
-
assert_equal custom_model.connection.quote_table_name('my_transitive_closure'), custom_model.transitive_closure_table_name
|
30
|
-
assert_equal 'MyTransitiveClosureLink', custom_model.transitive_closure_class_name
|
31
|
-
end
|
32
|
-
|
33
|
-
should 'not have its configuration accessors on ActiveRecord::Base' do
|
34
|
-
assert !ActiveRecord::Base.respond_to?(:ancestor_id_column)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
module Dagnabit
|
4
|
-
module Link
|
5
|
-
class TestCyclePrevention < ActiveRecord::TestCase
|
6
|
-
should 'prevent simple cycles from being saved' do
|
7
|
-
n1 = ::Node.create
|
8
|
-
n2 = ::Node.create
|
9
|
-
|
10
|
-
l1 = ::Link.create(:ancestor => n1, :descendant => n2)
|
11
|
-
l2 = ::Link.create(:ancestor => n2, :descendant => n1)
|
12
|
-
|
13
|
-
assert l2.new_record?
|
14
|
-
end
|
15
|
-
|
16
|
-
should 'prevent self-referential nodes' do
|
17
|
-
n1 = ::Node.create
|
18
|
-
|
19
|
-
l1 = ::Link.create(:ancestor => n1, :descendant => n1)
|
20
|
-
assert l1.new_record?
|
21
|
-
end
|
22
|
-
|
23
|
-
should 'prevent cycles from being saved' do
|
24
|
-
n1 = ::Node.create
|
25
|
-
n2 = ::Node.create
|
26
|
-
n3 = ::Node.create
|
27
|
-
n4 = ::Node.create
|
28
|
-
|
29
|
-
::Link.create(:ancestor => n1, :descendant => n2)
|
30
|
-
::Link.create(:ancestor => n2, :descendant => n3)
|
31
|
-
::Link.create(:ancestor => n3, :descendant => n4)
|
32
|
-
l = ::Link.create(:ancestor => n4, :descendant => n2)
|
33
|
-
|
34
|
-
assert l.new_record?
|
35
|
-
end
|
36
|
-
|
37
|
-
should 'not prevent links from being saved multiple times in a row' do
|
38
|
-
n1 = ::Node.create
|
39
|
-
n2 = ::Node.create
|
40
|
-
|
41
|
-
l = ::Link.new(:ancestor => n1, :descendant => n2)
|
42
|
-
|
43
|
-
assert l.save
|
44
|
-
assert l.save, 'should have been able to save twice'
|
45
|
-
end
|
46
|
-
|
47
|
-
should 'prevent cycles from being saved in customized links' do
|
48
|
-
n1 = ::Node.create
|
49
|
-
n2 = ::Node.create
|
50
|
-
n3 = ::Node.create
|
51
|
-
|
52
|
-
::CustomizedLink.create(:ancestor => n1, :descendant => n2)
|
53
|
-
::CustomizedLink.create(:ancestor => n1, :descendant => n3)
|
54
|
-
l3 = ::CustomizedLink.create(:ancestor => n3, :descendant => n1)
|
55
|
-
|
56
|
-
assert l3.new_record?
|
57
|
-
end
|
58
|
-
|
59
|
-
should 'not execute on links that have no ancestor or descendant' do
|
60
|
-
assert_nothing_raised { ::Link.create }
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
module Dagnabit
|
4
|
-
module Link
|
5
|
-
class TestNamedScopes < ActiveRecord::TestCase
|
6
|
-
class OtherNode < ActiveRecord::Base
|
7
|
-
set_table_name 'nodes'
|
8
|
-
end
|
9
|
-
|
10
|
-
def setup
|
11
|
-
@n1 = ::Node.new
|
12
|
-
@n2 = OtherNode.new
|
13
|
-
@n3 = ::Node.new
|
14
|
-
|
15
|
-
@l1 = ::Link.build_edge(@n1, @n2)
|
16
|
-
@l2 = ::Link.build_edge(@n2, @n3)
|
17
|
-
@l1.save
|
18
|
-
@l2.save
|
19
|
-
end
|
20
|
-
|
21
|
-
should 'scope links by ancestor type' do
|
22
|
-
links = ::Link.ancestor_type(OtherNode.name)
|
23
|
-
assert_equal [@l2], links
|
24
|
-
end
|
25
|
-
|
26
|
-
should 'scope links by descendant type' do
|
27
|
-
links = ::Link.descendant_type(OtherNode.name)
|
28
|
-
assert_equal [@l1], links
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,69 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
module Dagnabit
|
4
|
-
module Link
|
5
|
-
class TestTransitiveClosureLinkModel < ActiveRecord::TestCase
|
6
|
-
def setup
|
7
|
-
@model = ::Link::TransitiveClosureLink.new
|
8
|
-
@model.class.set_table_name 'edges_transitive_closure_tuples'
|
9
|
-
@node = ::Node.new
|
10
|
-
end
|
11
|
-
|
12
|
-
should 'belong to an ancestor' do
|
13
|
-
@model.ancestor = @node
|
14
|
-
@model.save
|
15
|
-
|
16
|
-
@model = ::Link::TransitiveClosureLink.find(@model.id)
|
17
|
-
assert_equal @node, @model.ancestor
|
18
|
-
end
|
19
|
-
|
20
|
-
should 'belong to a descendant' do
|
21
|
-
@model.descendant = @node
|
22
|
-
@model.save
|
23
|
-
|
24
|
-
@model = ::Link::TransitiveClosureLink.find(@model.id)
|
25
|
-
assert_equal @node, @model.descendant
|
26
|
-
end
|
27
|
-
|
28
|
-
# TODO: wrap tests in transaction
|
29
|
-
should 'support find(:all) queries including associations' do
|
30
|
-
::Link::TransitiveClosureLink.delete_all
|
31
|
-
|
32
|
-
n1 = ::Node.new
|
33
|
-
n2 = ::Node.new
|
34
|
-
::Link::TransitiveClosureLink.create(:ancestor => n1, :descendant => n2)
|
35
|
-
|
36
|
-
links = ::Link::TransitiveClosureLink.find(:all, :include => :ancestor)
|
37
|
-
assert_equal 1, links.length
|
38
|
-
end
|
39
|
-
|
40
|
-
should 'support scoping by ancestor type' do
|
41
|
-
::Link::TransitiveClosureLink.delete_all
|
42
|
-
|
43
|
-
n1 = ::BetaNode.new
|
44
|
-
n2 = ::Node.new
|
45
|
-
|
46
|
-
::Link::TransitiveClosureLink.create(:ancestor => n1, :descendant => n2)
|
47
|
-
|
48
|
-
links = ::Link::TransitiveClosureLink.ancestor_type(::BetaNode.name)
|
49
|
-
|
50
|
-
assert_equal 1, links.length
|
51
|
-
assert_equal n1, links.first.ancestor
|
52
|
-
end
|
53
|
-
|
54
|
-
should 'support scoping by descendant type' do
|
55
|
-
::Link::TransitiveClosureLink.delete_all
|
56
|
-
|
57
|
-
n1 = ::Node.new
|
58
|
-
n2 = ::BetaNode.new
|
59
|
-
|
60
|
-
::Link::TransitiveClosureLink.create(:ancestor => n1, :descendant => n2)
|
61
|
-
|
62
|
-
links = ::Link::TransitiveClosureLink.descendant_type(::BetaNode.name)
|
63
|
-
|
64
|
-
assert_equal 1, links.length
|
65
|
-
assert_equal n2, links.first.descendant
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
@@ -1,178 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
module Dagnabit
|
4
|
-
module Link
|
5
|
-
class TestTransitiveClosureRecalculation < ActiveRecord::TestCase
|
6
|
-
TransitiveClosureLink = ::Link::TransitiveClosureLink
|
7
|
-
CustomTransitiveClosureLink = CustomizedLink::TransitiveClosureLink
|
8
|
-
TransitiveClosureCustomDataLink = CustomDataLink::TransitiveClosureLink
|
9
|
-
|
10
|
-
should 'recalculate transitive closure on create' do
|
11
|
-
n1 = ::Node.create
|
12
|
-
n2 = ::Node.create
|
13
|
-
n3 = ::Node.create
|
14
|
-
|
15
|
-
::Link.create(:ancestor => n1, :descendant => n2)
|
16
|
-
::Link.create(:ancestor => n2, :descendant => n3)
|
17
|
-
|
18
|
-
tc = TransitiveClosureLink.find(:first, :conditions => { :ancestor_id => n1.id, :descendant_id => n3.id })
|
19
|
-
assert_not_nil tc, 'expected to find path from n1 to n3'
|
20
|
-
end
|
21
|
-
|
22
|
-
should 'transfer custom data attributes to transitive closure' do
|
23
|
-
n1 = ::Node.create
|
24
|
-
n2 = ::Node.create
|
25
|
-
n3 = ::Node.create
|
26
|
-
|
27
|
-
CustomDataLink.create(:ancestor => n1, :descendant => n2, :data => 'foo')
|
28
|
-
CustomDataLink.create(:ancestor => n2, :descendant => n3, :data => 'bar')
|
29
|
-
|
30
|
-
tc1 = TransitiveClosureCustomDataLink.find(:first, :conditions => { :ancestor_id => n1.id, :descendant_id => n2.id })
|
31
|
-
tc2 = TransitiveClosureCustomDataLink.find(:first, :conditions => { :ancestor_id => n2.id, :descendant_id => n3.id })
|
32
|
-
tc3 = TransitiveClosureCustomDataLink.find(:first, :conditions => { :ancestor_id => n1.id, :descendant_id => n3.id })
|
33
|
-
|
34
|
-
assert_equal 'foo', tc1.data, 'expected to find custom data attribute on n1->n2 edge'
|
35
|
-
assert_equal 'bar', tc2.data, 'expected to find custom data attribute on n2->n3 edge'
|
36
|
-
assert_not_nil tc3, 'expected to find path from n1 to n3'
|
37
|
-
assert_nil tc3.data, 'expected to find no custom data attribute on n1->n3 path'
|
38
|
-
end
|
39
|
-
|
40
|
-
should 'recalculate transitive closure on destroy' do
|
41
|
-
n1 = ::Node.create
|
42
|
-
n2 = ::Node.create
|
43
|
-
n3 = ::Node.create
|
44
|
-
|
45
|
-
l1 = ::Link.create(:ancestor => n1, :descendant => n2)
|
46
|
-
l2 = ::Link.create(:ancestor => n2, :descendant => n3)
|
47
|
-
|
48
|
-
l2.destroy
|
49
|
-
|
50
|
-
tc = TransitiveClosureLink.find(:first, :conditions => { :ancestor_id => n1.id, :descendant_id => n2.id })
|
51
|
-
assert_not_nil tc, 'expected to find path from n1 to n2'
|
52
|
-
|
53
|
-
tc = TransitiveClosureLink.find(:first, :conditions => { :ancestor_id => n1.id, :descendant_id => n3.id })
|
54
|
-
assert_nil tc, 'expected to not find path from n1 to n3'
|
55
|
-
end
|
56
|
-
|
57
|
-
should 'recalculate transitive closure when destroying links with custom data' do
|
58
|
-
n1 = ::Node.create
|
59
|
-
n2 = ::Node.create
|
60
|
-
n3 = ::Node.create
|
61
|
-
n4 = ::Node.create
|
62
|
-
|
63
|
-
l1 = CustomDataLink.create(:ancestor => n1, :descendant => n2, :data => 'foo')
|
64
|
-
l2 = CustomDataLink.create(:ancestor => n2, :descendant => n3, :data => 'bar')
|
65
|
-
l3 = CustomDataLink.create(:ancestor => n3, :descendant => n4, :data => 'baz')
|
66
|
-
|
67
|
-
l2.destroy
|
68
|
-
|
69
|
-
tc1 = TransitiveClosureCustomDataLink.find(:first, :conditions => { :ancestor_id => n1.id, :descendant_id => n2.id })
|
70
|
-
assert_not_nil tc1, 'expected to find path from n1 to n2'
|
71
|
-
assert_equal 'foo', tc1.data, 'expected to find custom data attribute on n1->n2 edge'
|
72
|
-
|
73
|
-
tc2 = TransitiveClosureCustomDataLink.find(:first, :conditions => { :ancestor_id => n3.id, :descendant_id => n4.id })
|
74
|
-
assert_not_nil tc2, 'expected to find path from n3 to n4'
|
75
|
-
assert_equal 'baz', tc2.data, 'expected to find custom data attribute on n3->n4 edge'
|
76
|
-
|
77
|
-
tc = TransitiveClosureCustomDataLink.find(:first, :conditions => { :ancestor_id => n1.id, :descendant_id => n3.id })
|
78
|
-
assert_nil tc, 'expected to not find path from n1 to n3'
|
79
|
-
tc = TransitiveClosureCustomDataLink.find(:first, :conditions => { :ancestor_id => n2.id, :descendant_id => n4.id })
|
80
|
-
assert_nil tc, 'expected to not find path from n2 to n4'
|
81
|
-
tc = TransitiveClosureCustomDataLink.find(:first, :conditions => { :ancestor_id => n1.id, :descendant_id => n4.id })
|
82
|
-
assert_nil tc, 'expected to not find path from n1 to n4'
|
83
|
-
end
|
84
|
-
|
85
|
-
should 'include edges in the graph when reconstructing the transitive closure on destroy' do
|
86
|
-
n1 = ::Node.create
|
87
|
-
n2 = ::Node.create
|
88
|
-
n3 = ::Node.create
|
89
|
-
|
90
|
-
l1 = ::Link.create(:ancestor => n1, :descendant => n2)
|
91
|
-
l2 = ::Link.create(:ancestor => n2, :descendant => n3)
|
92
|
-
l3 = ::Link.create(:ancestor => n1, :descendant => n3)
|
93
|
-
|
94
|
-
l1.destroy
|
95
|
-
l2.destroy
|
96
|
-
|
97
|
-
tc = TransitiveClosureLink.find(:first, :conditions => { :ancestor_id => n1.id, :descendant_id => n3.id })
|
98
|
-
assert_not_nil tc, 'expected to find path from n1 to n3'
|
99
|
-
end
|
100
|
-
|
101
|
-
should 'recalculate transitive closure on update' do
|
102
|
-
n1 = ::Node.create
|
103
|
-
n2 = ::Node.create
|
104
|
-
n3 = ::Node.create
|
105
|
-
n4 = ::Node.create
|
106
|
-
|
107
|
-
l1 = ::Link.create(:ancestor => n1, :descendant => n2)
|
108
|
-
l2 = ::Link.create(:ancestor => n2, :descendant => n3)
|
109
|
-
|
110
|
-
l2.update_attribute(:descendant, n4)
|
111
|
-
|
112
|
-
tc = TransitiveClosureLink.find(:first, :conditions => { :ancestor_id => n1.id, :descendant_id => n4.id })
|
113
|
-
assert_not_nil tc, 'expected to find path from n1 to n4'
|
114
|
-
|
115
|
-
tc = TransitiveClosureLink.find(:first, :conditions => { :ancestor_id => n1.id, :descendant_id => n3.id })
|
116
|
-
assert_nil tc, 'expected to not find path from n1 to n3'
|
117
|
-
end
|
118
|
-
|
119
|
-
should 'recalculate transitive closure on create using custom-configured link' do
|
120
|
-
n1 = ::Node.create
|
121
|
-
n2 = ::Node.create
|
122
|
-
n3 = ::Node.create
|
123
|
-
|
124
|
-
CustomizedLink.create(:ancestor => n1, :descendant => n2)
|
125
|
-
CustomizedLink.create(:ancestor => n2, :descendant => n3)
|
126
|
-
|
127
|
-
tc = CustomTransitiveClosureLink.find(:first, :conditions => { :the_ancestor_id => n1.id, :the_descendant_id => n3.id })
|
128
|
-
assert_not_nil tc, 'expected to find path from n1 to n3'
|
129
|
-
end
|
130
|
-
|
131
|
-
should 'recalculate transitive closure on destroy using custom-configured link' do
|
132
|
-
n1 = ::Node.create
|
133
|
-
n2 = ::Node.create
|
134
|
-
n3 = ::Node.create
|
135
|
-
|
136
|
-
l1 = CustomizedLink.create(:ancestor => n1, :descendant => n2)
|
137
|
-
l2 = CustomizedLink.create(:ancestor => n2, :descendant => n3)
|
138
|
-
|
139
|
-
l2.destroy
|
140
|
-
|
141
|
-
tc = CustomTransitiveClosureLink.find(:first, :conditions => { :the_ancestor_id => n1.id, :the_descendant_id => n2.id })
|
142
|
-
assert_not_nil tc, 'expected to find path from n1 to n2'
|
143
|
-
|
144
|
-
tc = CustomTransitiveClosureLink.find(:first, :conditions => { :the_ancestor_id => n1.id, :the_descendant_id => n3.id })
|
145
|
-
assert_nil tc, 'expected to not find path from n1 to n3'
|
146
|
-
end
|
147
|
-
|
148
|
-
should 'recalculate transitive closure on update using custom-configured link' do
|
149
|
-
n1 = ::Node.create
|
150
|
-
n2 = ::Node.create
|
151
|
-
n3 = ::Node.create
|
152
|
-
n4 = ::Node.create
|
153
|
-
|
154
|
-
l1 = CustomizedLink.create(:ancestor => n1, :descendant => n2)
|
155
|
-
l2 = CustomizedLink.create(:ancestor => n2, :descendant => n3)
|
156
|
-
|
157
|
-
l2.update_attribute(:descendant, n4)
|
158
|
-
|
159
|
-
tc = CustomTransitiveClosureLink.find(:first, :conditions => { :the_ancestor_id => n1.id, :the_descendant_id => n4.id })
|
160
|
-
assert_not_nil tc, 'expected to find path from n1 to n4'
|
161
|
-
|
162
|
-
tc = CustomTransitiveClosureLink.find(:first, :conditions => { :the_ancestor_id => n1.id, :the_descendant_id => n3.id })
|
163
|
-
assert_nil tc, 'expected to not find path from n1 to n3'
|
164
|
-
end
|
165
|
-
|
166
|
-
should "not recalculate transitive closure if neither a link's source nor target changed" do
|
167
|
-
n1 = ::Node.create
|
168
|
-
n2 = ::Node.create
|
169
|
-
|
170
|
-
l1 = ::Link.new(:ancestor => n1, :descendant => n2)
|
171
|
-
|
172
|
-
l1.expects(:update_transitive_closure_for_destroy).never
|
173
|
-
l1.save
|
174
|
-
l1.save
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|